summaryrefslogtreecommitdiff
path: root/spec/ruby
diff options
context:
space:
mode:
Diffstat (limited to 'spec/ruby')
-rw-r--r--spec/ruby/.mspec.constants4
-rw-r--r--spec/ruby/.rubocop.yml65
-rw-r--r--spec/ruby/.rubocop_todo.yml13
-rw-r--r--spec/ruby/CONTRIBUTING.md36
-rw-r--r--spec/ruby/README.md28
-rw-r--r--spec/ruby/command_line/backtrace_limit_spec.rb49
-rw-r--r--spec/ruby/command_line/dash_a_spec.rb4
-rw-r--r--spec/ruby/command_line/dash_l_spec.rb8
-rw-r--r--spec/ruby/command_line/dash_n_spec.rb8
-rw-r--r--spec/ruby/command_line/dash_p_spec.rb4
-rw-r--r--spec/ruby/command_line/dash_r_spec.rb5
-rw-r--r--spec/ruby/command_line/dash_upper_f_spec.rb2
-rw-r--r--spec/ruby/command_line/dash_upper_u_spec.rb7
-rw-r--r--spec/ruby/command_line/dash_upper_w_spec.rb33
-rw-r--r--spec/ruby/command_line/dash_v_spec.rb5
-rw-r--r--spec/ruby/command_line/dash_w_spec.rb6
-rw-r--r--spec/ruby/command_line/fixtures/bin/embedded_ruby.txt2
-rw-r--r--spec/ruby/command_line/fixtures/freeze_flag_required_diff_enc.rbbin121 -> 90 bytes
-rw-r--r--spec/ruby/command_line/fixtures/freeze_flag_two_literals.rb2
-rw-r--r--spec/ruby/command_line/fixtures/string_literal_frozen_comment.rb4
-rw-r--r--spec/ruby/command_line/fixtures/string_literal_mutable_comment.rb4
-rw-r--r--spec/ruby/command_line/fixtures/string_literal_raw.rb3
-rw-r--r--spec/ruby/command_line/frozen_strings_spec.rb44
-rw-r--r--spec/ruby/command_line/rubyopt_spec.rb48
-rw-r--r--spec/ruby/command_line/syntax_error_spec.rb10
-rw-r--r--spec/ruby/core/argf/bytes_spec.rb16
-rw-r--r--spec/ruby/core/argf/chars_spec.rb16
-rw-r--r--spec/ruby/core/argf/codepoints_spec.rb16
-rw-r--r--spec/ruby/core/argf/lines_spec.rb16
-rw-r--r--spec/ruby/core/argf/readpartial_spec.rb4
-rw-r--r--spec/ruby/core/argf/shared/getc.rb2
-rw-r--r--spec/ruby/core/argf/shared/read.rb4
-rw-r--r--spec/ruby/core/array/all_spec.rb13
-rw-r--r--spec/ruby/core/array/any_spec.rb12
-rw-r--r--spec/ruby/core/array/assoc_spec.rb14
-rw-r--r--spec/ruby/core/array/bsearch_index_spec.rb4
-rw-r--r--spec/ruby/core/array/clear_spec.rb20
-rw-r--r--spec/ruby/core/array/compact_spec.rb30
-rw-r--r--spec/ruby/core/array/concat_spec.rb58
-rw-r--r--spec/ruby/core/array/count_spec.rb11
-rw-r--r--spec/ruby/core/array/deconstruct_spec.rb10
-rw-r--r--spec/ruby/core/array/delete_at_spec.rb22
-rw-r--r--spec/ruby/core/array/delete_if_spec.rb36
-rw-r--r--spec/ruby/core/array/delete_spec.rb22
-rw-r--r--spec/ruby/core/array/drop_spec.rb12
-rw-r--r--spec/ruby/core/array/drop_while_spec.rb16
-rw-r--r--spec/ruby/core/array/each_index_spec.rb18
-rw-r--r--spec/ruby/core/array/each_spec.rb40
-rw-r--r--spec/ruby/core/array/element_set_spec.rb76
-rw-r--r--spec/ruby/core/array/fill_spec.rb98
-rw-r--r--spec/ruby/core/array/fixtures/classes.rb72
-rw-r--r--spec/ruby/core/array/fixtures/encoded_strings.rb18
-rw-r--r--spec/ruby/core/array/flatten_spec.rb34
-rw-r--r--spec/ruby/core/array/initialize_spec.rb4
-rw-r--r--spec/ruby/core/array/intersect_spec.rb53
-rw-r--r--spec/ruby/core/array/intersection_spec.rb16
-rw-r--r--spec/ruby/core/array/keep_if_spec.rb1
-rw-r--r--spec/ruby/core/array/multiply_spec.rb58
-rw-r--r--spec/ruby/core/array/new_spec.rb4
-rw-r--r--spec/ruby/core/array/none_spec.rb13
-rw-r--r--spec/ruby/core/array/one_spec.rb13
-rw-r--r--spec/ruby/core/array/pack/buffer_spec.rb12
-rw-r--r--spec/ruby/core/array/pack/c_spec.rb16
-rw-r--r--spec/ruby/core/array/pack/m_spec.rb10
-rw-r--r--spec/ruby/core/array/pack/p_spec.rb24
-rw-r--r--spec/ruby/core/array/pack/shared/basic.rb52
-rw-r--r--spec/ruby/core/array/pack/shared/float.rb74
-rw-r--r--spec/ruby/core/array/pack/shared/integer.rb108
-rw-r--r--spec/ruby/core/array/pack/shared/numeric_basic.rb10
-rw-r--r--spec/ruby/core/array/pack/shared/string.rb2
-rw-r--r--spec/ruby/core/array/pack/shared/taint.rb33
-rw-r--r--spec/ruby/core/array/pack/shared/unicode.rb16
-rw-r--r--spec/ruby/core/array/pack/w_spec.rb16
-rw-r--r--spec/ruby/core/array/pack/x_spec.rb1
-rw-r--r--spec/ruby/core/array/plus_spec.rb37
-rw-r--r--spec/ruby/core/array/pop_spec.rb52
-rw-r--r--spec/ruby/core/array/product_spec.rb5
-rw-r--r--spec/ruby/core/array/rassoc_spec.rb14
-rw-r--r--spec/ruby/core/array/reject_spec.rb15
-rw-r--r--spec/ruby/core/array/reverse_each_spec.rb16
-rw-r--r--spec/ruby/core/array/rindex_spec.rb17
-rw-r--r--spec/ruby/core/array/sample_spec.rb30
-rw-r--r--spec/ruby/core/array/shared/clone.rb24
-rw-r--r--spec/ruby/core/array/shared/collect.rb63
-rw-r--r--spec/ruby/core/array/shared/index.rb4
-rw-r--r--spec/ruby/core/array/shared/inspect.rb32
-rw-r--r--spec/ruby/core/array/shared/intersection.rb3
-rw-r--r--spec/ruby/core/array/shared/iterable_and_tolerating_size_increasing.rb25
-rw-r--r--spec/ruby/core/array/shared/join.rb86
-rw-r--r--spec/ruby/core/array/shared/keep_if.rb35
-rw-r--r--spec/ruby/core/array/shared/select.rb3
-rw-r--r--spec/ruby/core/array/shared/slice.rb532
-rw-r--r--spec/ruby/core/array/shared/unshift.rb18
-rw-r--r--spec/ruby/core/array/shift_spec.rb16
-rw-r--r--spec/ruby/core/array/shuffle_spec.rb14
-rw-r--r--spec/ruby/core/array/slice_spec.rb78
-rw-r--r--spec/ruby/core/array/sort_by_spec.rb33
-rw-r--r--spec/ruby/core/array/sum_spec.rb21
-rw-r--r--spec/ruby/core/array/take_spec.rb12
-rw-r--r--spec/ruby/core/array/take_while_spec.rb16
-rw-r--r--spec/ruby/core/array/to_h_spec.rb6
-rw-r--r--spec/ruby/core/array/try_convert_spec.rb2
-rw-r--r--spec/ruby/core/array/uniq_spec.rb122
-rw-r--r--spec/ruby/core/array/values_at_spec.rb9
-rw-r--r--spec/ruby/core/array/zip_spec.rb6
-rw-r--r--spec/ruby/core/basicobject/fixtures/classes.rb228
-rw-r--r--spec/ruby/core/basicobject/instance_eval_spec.rb192
-rw-r--r--spec/ruby/core/basicobject/method_missing_spec.rb1
-rw-r--r--spec/ruby/core/basicobject/singleton_method_added_spec.rb8
-rw-r--r--spec/ruby/core/binding/clone_spec.rb6
-rw-r--r--spec/ruby/core/binding/dup_spec.rb6
-rw-r--r--spec/ruby/core/binding/eval_spec.rb99
-rw-r--r--spec/ruby/core/binding/fixtures/irbrc1
-rw-r--r--spec/ruby/core/binding/irb_spec.rb15
-rw-r--r--spec/ruby/core/binding/shared/clone.rb22
-rw-r--r--spec/ruby/core/binding/source_location_spec.rb5
-rw-r--r--spec/ruby/core/builtin_constants/builtin_constants_spec.rb18
-rw-r--r--spec/ruby/core/class/attached_object_spec.rb31
-rw-r--r--spec/ruby/core/class/dup_spec.rb3
-rw-r--r--spec/ruby/core/class/subclasses_spec.rb51
-rw-r--r--spec/ruby/core/comparable/clamp_spec.rb78
-rw-r--r--spec/ruby/core/complex/comparison_spec.rb36
-rw-r--r--spec/ruby/core/complex/inspect_spec.rb21
-rw-r--r--spec/ruby/core/complex/polar_spec.rb16
-rw-r--r--spec/ruby/core/complex/to_r_spec.rb12
-rw-r--r--spec/ruby/core/complex/to_s_spec.rb11
-rw-r--r--spec/ruby/core/conditionvariable/broadcast_spec.rb1
-rw-r--r--spec/ruby/core/conditionvariable/marshal_dump_spec.rb1
-rw-r--r--spec/ruby/core/conditionvariable/signal_spec.rb1
-rw-r--r--spec/ruby/core/conditionvariable/wait_spec.rb1
-rw-r--r--spec/ruby/core/data/constants_spec.rb22
-rw-r--r--spec/ruby/core/data/define_spec.rb36
-rw-r--r--spec/ruby/core/data/fixtures/classes.rb5
-rw-r--r--spec/ruby/core/data/initialize_spec.rb65
-rw-r--r--spec/ruby/core/data/with_spec.rb35
-rw-r--r--spec/ruby/core/dir/children_spec.rb25
-rw-r--r--spec/ruby/core/dir/each_child_spec.rb20
-rw-r--r--spec/ruby/core/dir/each_spec.rb11
-rw-r--r--spec/ruby/core/dir/entries_spec.rb9
-rw-r--r--spec/ruby/core/dir/exist_spec.rb8
-rw-r--r--spec/ruby/core/dir/fchdir_spec.rb68
-rw-r--r--spec/ruby/core/dir/fixtures/common.rb20
-rw-r--r--spec/ruby/core/dir/foreach_spec.rb12
-rw-r--r--spec/ruby/core/dir/glob_spec.rb165
-rw-r--r--spec/ruby/core/dir/home_spec.rb50
-rw-r--r--spec/ruby/core/dir/mkdir_spec.rb18
-rw-r--r--spec/ruby/core/dir/read_spec.rb33
-rw-r--r--spec/ruby/core/dir/shared/chroot.rb13
-rw-r--r--spec/ruby/core/dir/shared/exist.rb8
-rw-r--r--spec/ruby/core/dir/shared/glob.rb46
-rw-r--r--spec/ruby/core/encoding/compatible_spec.rb74
-rw-r--r--spec/ruby/core/encoding/converter/convert_spec.rb15
-rw-r--r--spec/ruby/core/encoding/converter/finish_spec.rb4
-rw-r--r--spec/ruby/core/encoding/converter/last_error_spec.rb16
-rw-r--r--spec/ruby/core/encoding/converter/new_spec.rb2
-rw-r--r--spec/ruby/core/encoding/converter/primitive_convert_spec.rb5
-rw-r--r--spec/ruby/core/encoding/converter/primitive_errinfo_spec.rb1
-rw-r--r--spec/ruby/core/encoding/converter/putback_spec.rb14
-rw-r--r--spec/ruby/core/encoding/converter/replacement_spec.rb20
-rw-r--r--spec/ruby/core/encoding/default_external_spec.rb8
-rw-r--r--spec/ruby/core/encoding/inspect_spec.rb20
-rw-r--r--spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_name_spec.rb1
-rw-r--r--spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_spec.rb1
-rw-r--r--spec/ruby/core/encoding/invalid_byte_sequence_error/error_bytes_spec.rb1
-rw-r--r--spec/ruby/core/encoding/invalid_byte_sequence_error/incomplete_input_spec.rb4
-rw-r--r--spec/ruby/core/encoding/invalid_byte_sequence_error/readagain_bytes_spec.rb5
-rw-r--r--spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_name_spec.rb1
-rw-r--r--spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_spec.rb1
-rw-r--r--spec/ruby/core/encoding/list_spec.rb6
-rw-r--r--spec/ruby/core/encoding/name_spec.rb1
-rw-r--r--spec/ruby/core/encoding/replicate_spec.rb119
-rw-r--r--spec/ruby/core/encoding/to_s_spec.rb1
-rw-r--r--spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_name_spec.rb1
-rw-r--r--spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_spec.rb1
-rw-r--r--spec/ruby/core/encoding/undefined_conversion_error/error_char_spec.rb1
-rw-r--r--spec/ruby/core/encoding/undefined_conversion_error/source_encoding_name_spec.rb1
-rw-r--r--spec/ruby/core/encoding/undefined_conversion_error/source_encoding_spec.rb1
-rw-r--r--spec/ruby/core/enumerable/all_spec.rb7
-rw-r--r--spec/ruby/core/enumerable/any_spec.rb7
-rw-r--r--spec/ruby/core/enumerable/chunk_spec.rb5
-rw-r--r--spec/ruby/core/enumerable/compact_spec.rb11
-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/filter_map_spec.rb34
-rw-r--r--spec/ruby/core/enumerable/fixtures/classes.rb6
-rw-r--r--spec/ruby/core/enumerable/grep_spec.rb49
-rw-r--r--spec/ruby/core/enumerable/grep_v_spec.rb49
-rw-r--r--spec/ruby/core/enumerable/group_by_spec.rb10
-rw-r--r--spec/ruby/core/enumerable/none_spec.rb7
-rw-r--r--spec/ruby/core/enumerable/one_spec.rb8
-rw-r--r--spec/ruby/core/enumerable/shared/entries.rb10
-rw-r--r--spec/ruby/core/enumerable/shared/inject.rb50
-rw-r--r--spec/ruby/core/enumerable/sum_spec.rb19
-rw-r--r--spec/ruby/core/enumerable/tally_spec.rb61
-rw-r--r--spec/ruby/core/enumerable/to_set_spec.rb29
-rw-r--r--spec/ruby/core/enumerable/uniq_spec.rb76
-rw-r--r--spec/ruby/core/enumerable/zip_spec.rb5
-rw-r--r--spec/ruby/core/enumerator/arithmetic_sequence/begin_spec.rb10
-rw-r--r--spec/ruby/core/enumerator/chain/initialize_spec.rb4
-rw-r--r--spec/ruby/core/enumerator/chain/inspect_spec.rb4
-rw-r--r--spec/ruby/core/enumerator/each_spec.rb18
-rw-r--r--spec/ruby/core/enumerator/generator/initialize_spec.rb4
-rw-r--r--spec/ruby/core/enumerator/initialize_spec.rb12
-rw-r--r--spec/ruby/core/enumerator/inspect_spec.rb5
-rw-r--r--spec/ruby/core/enumerator/lazy/compact_spec.rb16
-rw-r--r--spec/ruby/core/enumerator/lazy/eager_spec.rb38
-rw-r--r--spec/ruby/core/enumerator/lazy/filter_map_spec.rb14
-rw-r--r--spec/ruby/core/enumerator/lazy/initialize_spec.rb4
-rw-r--r--spec/ruby/core/enumerator/lazy/lazy_spec.rb4
-rw-r--r--spec/ruby/core/enumerator/lazy/with_index_spec.rb44
-rw-r--r--spec/ruby/core/enumerator/new_spec.rb59
-rw-r--r--spec/ruby/core/enumerator/produce_spec.rb48
-rw-r--r--spec/ruby/core/enumerator/product/each_spec.rb73
-rw-r--r--spec/ruby/core/enumerator/product/initialize_copy_spec.rb54
-rw-r--r--spec/ruby/core/enumerator/product/initialize_spec.rb33
-rw-r--r--spec/ruby/core/enumerator/product/inspect_spec.rb22
-rw-r--r--spec/ruby/core/enumerator/product/rewind_spec.rb64
-rw-r--r--spec/ruby/core/enumerator/product/size_spec.rb56
-rw-r--r--spec/ruby/core/enumerator/product_spec.rb93
-rw-r--r--spec/ruby/core/enumerator/rewind_spec.rb4
-rw-r--r--spec/ruby/core/enumerator/yielder/to_proc_spec.rb20
-rw-r--r--spec/ruby/core/env/clone_spec.rb23
-rw-r--r--spec/ruby/core/env/delete_spec.rb16
-rw-r--r--spec/ruby/core/env/dup_spec.rb11
-rw-r--r--spec/ruby/core/env/except_spec.rb44
-rw-r--r--spec/ruby/core/env/index_spec.rb14
-rw-r--r--spec/ruby/core/env/indexes_spec.rb1
-rw-r--r--spec/ruby/core/env/indices_spec.rb1
-rw-r--r--spec/ruby/core/env/key_spec.rb32
-rw-r--r--spec/ruby/core/env/merge_spec.rb6
-rw-r--r--spec/ruby/core/env/shared/include.rb7
-rw-r--r--spec/ruby/core/env/shared/key.rb31
-rw-r--r--spec/ruby/core/env/shared/update.rb38
-rw-r--r--spec/ruby/core/env/shared/value.rb7
-rw-r--r--spec/ruby/core/env/slice_spec.rb10
-rw-r--r--spec/ruby/core/env/to_a_spec.rb5
-rw-r--r--spec/ruby/core/exception/backtrace_spec.rb27
-rw-r--r--spec/ruby/core/exception/case_compare_spec.rb2
-rw-r--r--spec/ruby/core/exception/detailed_message_spec.rb43
-rw-r--r--spec/ruby/core/exception/equal_value_spec.rb14
-rw-r--r--spec/ruby/core/exception/fixtures/common.rb4
-rw-r--r--spec/ruby/core/exception/fixtures/syntax_error.rb3
-rw-r--r--spec/ruby/core/exception/fixtures/thread_fiber_ensure.rb22
-rw-r--r--spec/ruby/core/exception/fixtures/thread_fiber_ensure_non_root_fiber.rb25
-rw-r--r--spec/ruby/core/exception/frozen_error_spec.rb44
-rw-r--r--spec/ruby/core/exception/full_message_spec.rb132
-rw-r--r--spec/ruby/core/exception/interrupt_spec.rb9
-rw-r--r--spec/ruby/core/exception/no_method_error_spec.rb79
-rw-r--r--spec/ruby/core/exception/set_backtrace_spec.rb28
-rw-r--r--spec/ruby/core/exception/signal_exception_spec.rb6
-rw-r--r--spec/ruby/core/exception/syntax_error_spec.rb27
-rw-r--r--spec/ruby/core/exception/system_exit_spec.rb42
-rw-r--r--spec/ruby/core/exception/to_s_spec.rb2
-rw-r--r--spec/ruby/core/exception/top_level_spec.rb42
-rw-r--r--spec/ruby/core/false/case_compare_spec.rb14
-rw-r--r--spec/ruby/core/false/singleton_method_spec.rb15
-rw-r--r--spec/ruby/core/false/to_s_spec.rb12
-rw-r--r--spec/ruby/core/fiber/blocking_spec.rb79
-rw-r--r--spec/ruby/core/fiber/inspect_spec.rb36
-rw-r--r--spec/ruby/core/fiber/kill_spec.rb90
-rw-r--r--spec/ruby/core/fiber/raise_spec.rb194
-rw-r--r--spec/ruby/core/fiber/resume_spec.rb15
-rw-r--r--spec/ruby/core/fiber/storage_spec.rb158
-rw-r--r--spec/ruby/core/file/absolute_path_spec.rb76
-rw-r--r--spec/ruby/core/file/atime_spec.rb7
-rw-r--r--spec/ruby/core/file/ctime_spec.rb5
-rw-r--r--spec/ruby/core/file/dirname_spec.rb39
-rw-r--r--spec/ruby/core/file/exist_spec.rb8
-rw-r--r--spec/ruby/core/file/expand_path_spec.rb2
-rw-r--r--spec/ruby/core/file/extname_spec.rb4
-rw-r--r--spec/ruby/core/file/flock_spec.rb4
-rw-r--r--spec/ruby/core/file/lutime_spec.rb9
-rw-r--r--spec/ruby/core/file/mtime_spec.rb21
-rw-r--r--spec/ruby/core/file/new_spec.rb65
-rw-r--r--spec/ruby/core/file/open_spec.rb25
-rw-r--r--spec/ruby/core/file/realpath_spec.rb4
-rw-r--r--spec/ruby/core/file/shared/fnmatch.rb55
-rw-r--r--spec/ruby/core/file/shared/path.rb18
-rw-r--r--spec/ruby/core/file/shared/update_time.rb105
-rw-r--r--spec/ruby/core/file/utime_spec.rb94
-rw-r--r--spec/ruby/core/filetest/exist_spec.rb8
-rw-r--r--spec/ruby/core/float/coerce_spec.rb4
-rw-r--r--spec/ruby/core/float/comparison_spec.rb35
-rw-r--r--spec/ruby/core/float/divide_spec.rb4
-rw-r--r--spec/ruby/core/float/divmod_spec.rb4
-rw-r--r--spec/ruby/core/float/gt_spec.rb21
-rw-r--r--spec/ruby/core/float/gte_spec.rb21
-rw-r--r--spec/ruby/core/float/lt_spec.rb21
-rw-r--r--spec/ruby/core/float/lte_spec.rb21
-rw-r--r--spec/ruby/core/float/magnitude_spec.rb1
-rw-r--r--spec/ruby/core/float/minus_spec.rb2
-rw-r--r--spec/ruby/core/float/multiply_spec.rb2
-rw-r--r--spec/ruby/core/float/plus_spec.rb2
-rw-r--r--spec/ruby/core/float/round_spec.rb64
-rw-r--r--spec/ruby/core/float/shared/equal.rb21
-rw-r--r--spec/ruby/core/float/shared/to_i.rb4
-rw-r--r--spec/ruby/core/gc/auto_compact_spec.rb36
-rw-r--r--spec/ruby/core/hash/assoc_spec.rb6
-rw-r--r--spec/ruby/core/hash/compact_spec.rb24
-rw-r--r--spec/ruby/core/hash/compare_by_identity_spec.rb19
-rw-r--r--spec/ruby/core/hash/constructor_spec.rb45
-rw-r--r--spec/ruby/core/hash/deconstruct_keys_spec.rb32
-rw-r--r--spec/ruby/core/hash/delete_spec.rb18
-rw-r--r--spec/ruby/core/hash/element_reference_spec.rb2
-rw-r--r--spec/ruby/core/hash/except_spec.rb50
-rw-r--r--spec/ruby/core/hash/fetch_spec.rb2
-rw-r--r--spec/ruby/core/hash/fetch_values_spec.rb2
-rw-r--r--spec/ruby/core/hash/hash_spec.rb9
-rw-r--r--spec/ruby/core/hash/index_spec.rb9
-rw-r--r--spec/ruby/core/hash/new_spec.rb13
-rw-r--r--spec/ruby/core/hash/rehash_spec.rb30
-rw-r--r--spec/ruby/core/hash/reject_spec.rb7
-rw-r--r--spec/ruby/core/hash/ruby2_keywords_hash_spec.rb106
-rw-r--r--spec/ruby/core/hash/shared/each.rb37
-rw-r--r--spec/ruby/core/hash/shared/eql.rb84
-rw-r--r--spec/ruby/core/hash/shared/equal.rb90
-rw-r--r--spec/ruby/core/hash/shared/store.rb8
-rw-r--r--spec/ruby/core/hash/shared/to_s.rb21
-rw-r--r--spec/ruby/core/hash/to_a_spec.rb20
-rw-r--r--spec/ruby/core/hash/to_proc_spec.rb16
-rw-r--r--spec/ruby/core/hash/transform_keys_spec.rb33
-rw-r--r--spec/ruby/core/hash/try_convert_spec.rb2
-rw-r--r--spec/ruby/core/integer/bit_and_spec.rb16
-rw-r--r--spec/ruby/core/integer/bit_or_spec.rb33
-rw-r--r--spec/ruby/core/integer/bit_xor_spec.rb35
-rw-r--r--spec/ruby/core/integer/ceildiv_spec.rb22
-rw-r--r--spec/ruby/core/integer/chr_spec.rb65
-rw-r--r--spec/ruby/core/integer/coerce_spec.rb13
-rw-r--r--spec/ruby/core/integer/complement_spec.rb6
-rw-r--r--spec/ruby/core/integer/div_spec.rb18
-rw-r--r--spec/ruby/core/integer/divide_spec.rb12
-rw-r--r--spec/ruby/core/integer/divmod_spec.rb12
-rw-r--r--spec/ruby/core/integer/element_reference_spec.rb122
-rw-r--r--spec/ruby/core/integer/fdiv_spec.rb51
-rw-r--r--spec/ruby/core/integer/left_shift_spec.rb55
-rw-r--r--spec/ruby/core/integer/minus_spec.rb6
-rw-r--r--spec/ruby/core/integer/multiply_spec.rb6
-rw-r--r--spec/ruby/core/integer/plus_spec.rb8
-rw-r--r--spec/ruby/core/integer/remainder_spec.rb2
-rw-r--r--spec/ruby/core/integer/right_shift_spec.rb59
-rw-r--r--spec/ruby/core/integer/shared/abs.rb4
-rw-r--r--spec/ruby/core/integer/shared/arithmetic_coerce.rb20
-rw-r--r--spec/ruby/core/integer/shared/exponent.rb11
-rw-r--r--spec/ruby/core/integer/shared/modulo.rb10
-rw-r--r--spec/ruby/core/integer/to_f_spec.rb6
-rw-r--r--spec/ruby/core/integer/to_s_spec.rb6
-rw-r--r--spec/ruby/core/integer/try_convert_spec.rb12
-rw-r--r--spec/ruby/core/integer/uminus_spec.rb8
-rw-r--r--spec/ruby/core/integer/zero_spec.rb12
-rw-r--r--spec/ruby/core/io/advise_spec.rb14
-rw-r--r--spec/ruby/core/io/binread_spec.rb10
-rw-r--r--spec/ruby/core/io/bytes_spec.rb47
-rw-r--r--spec/ruby/core/io/chars_spec.rb30
-rw-r--r--spec/ruby/core/io/close_read_spec.rb3
-rw-r--r--spec/ruby/core/io/close_spec.rb6
-rw-r--r--spec/ruby/core/io/close_write_spec.rb14
-rw-r--r--spec/ruby/core/io/codepoints_spec.rb38
-rw-r--r--spec/ruby/core/io/copy_stream_spec.rb33
-rw-r--r--spec/ruby/core/io/eof_spec.rb2
-rw-r--r--spec/ruby/core/io/fixtures/classes.rb26
-rw-r--r--spec/ruby/core/io/flush_spec.rb10
-rw-r--r--spec/ruby/core/io/foreach_spec.rb19
-rw-r--r--spec/ruby/core/io/getbyte_spec.rb16
-rw-r--r--spec/ruby/core/io/gets_spec.rb109
-rw-r--r--spec/ruby/core/io/initialize_spec.rb11
-rw-r--r--spec/ruby/core/io/ioctl_spec.rb2
-rw-r--r--spec/ruby/core/io/lineno_spec.rb15
-rw-r--r--spec/ruby/core/io/lines_spec.rb46
-rw-r--r--spec/ruby/core/io/new_spec.rb8
-rw-r--r--spec/ruby/core/io/nonblock_spec.rb46
-rw-r--r--spec/ruby/core/io/open_spec.rb13
-rw-r--r--spec/ruby/core/io/path_spec.rb14
-rw-r--r--spec/ruby/core/io/pipe_spec.rb11
-rw-r--r--spec/ruby/core/io/pread_spec.rb81
-rw-r--r--spec/ruby/core/io/print_spec.rb25
-rw-r--r--spec/ruby/core/io/puts_spec.rb2
-rw-r--r--spec/ruby/core/io/pwrite_spec.rb32
-rw-r--r--spec/ruby/core/io/read_nonblock_spec.rb53
-rw-r--r--spec/ruby/core/io/read_spec.rb180
-rw-r--r--spec/ruby/core/io/readchar_spec.rb66
-rw-r--r--spec/ruby/core/io/readline_spec.rb33
-rw-r--r--spec/ruby/core/io/readlines_spec.rb51
-rw-r--r--spec/ruby/core/io/readpartial_spec.rb19
-rw-r--r--spec/ruby/core/io/rewind_spec.rb15
-rw-r--r--spec/ruby/core/io/select_spec.rb48
-rw-r--r--spec/ruby/core/io/set_encoding_by_bom_spec.rb273
-rw-r--r--spec/ruby/core/io/set_encoding_spec.rb49
-rw-r--r--spec/ruby/core/io/shared/binwrite.rb13
-rw-r--r--spec/ruby/core/io/shared/each.rb86
-rw-r--r--spec/ruby/core/io/shared/new.rb50
-rw-r--r--spec/ruby/core/io/shared/pos.rb8
-rw-r--r--spec/ruby/core/io/shared/readlines.rb140
-rw-r--r--spec/ruby/core/io/shared/write.rb75
-rw-r--r--spec/ruby/core/io/stat_spec.rb3
-rw-r--r--spec/ruby/core/io/sysread_spec.rb39
-rw-r--r--spec/ruby/core/io/sysseek_spec.rb2
-rw-r--r--spec/ruby/core/io/syswrite_spec.rb11
-rw-r--r--spec/ruby/core/io/try_convert_spec.rb2
-rw-r--r--spec/ruby/core/io/ungetbyte_spec.rb18
-rw-r--r--spec/ruby/core/io/ungetc_spec.rb16
-rw-r--r--spec/ruby/core/io/write_nonblock_spec.rb11
-rw-r--r--spec/ruby/core/io/write_spec.rb157
-rw-r--r--spec/ruby/core/kernel/Complex_spec.rb93
-rw-r--r--spec/ruby/core/kernel/Float_spec.rb2
-rw-r--r--spec/ruby/core/kernel/Integer_spec.rb38
-rw-r--r--spec/ruby/core/kernel/String_spec.rb2
-rw-r--r--spec/ruby/core/kernel/__dir___spec.rb16
-rw-r--r--spec/ruby/core/kernel/at_exit_spec.rb61
-rw-r--r--spec/ruby/core/kernel/caller_locations_spec.rb40
-rw-r--r--spec/ruby/core/kernel/caller_spec.rb20
-rw-r--r--spec/ruby/core/kernel/catch_spec.rb2
-rw-r--r--spec/ruby/core/kernel/class_spec.rb2
-rw-r--r--spec/ruby/core/kernel/clone_spec.rb93
-rw-r--r--spec/ruby/core/kernel/define_singleton_method_spec.rb21
-rw-r--r--spec/ruby/core/kernel/eval_spec.rb86
-rw-r--r--spec/ruby/core/kernel/exec_spec.rb4
-rw-r--r--spec/ruby/core/kernel/exit_spec.rb10
-rw-r--r--spec/ruby/core/kernel/fixtures/Complex.rb5
-rw-r--r--spec/ruby/core/kernel/fixtures/at_exit.rb3
-rw-r--r--spec/ruby/core/kernel/fixtures/warn_core_method.rb2
-rw-r--r--spec/ruby/core/kernel/initialize_clone_spec.rb10
-rw-r--r--spec/ruby/core/kernel/initialize_copy_spec.rb9
-rw-r--r--spec/ruby/core/kernel/inspect_spec.rb10
-rw-r--r--spec/ruby/core/kernel/instance_variable_get_spec.rb6
-rw-r--r--spec/ruby/core/kernel/instance_variable_set_spec.rb12
-rw-r--r--spec/ruby/core/kernel/iterator_spec.rb14
-rw-r--r--spec/ruby/core/kernel/lambda_spec.rb74
-rw-r--r--spec/ruby/core/kernel/method_spec.rb45
-rw-r--r--spec/ruby/core/kernel/not_match_spec.rb14
-rw-r--r--spec/ruby/core/kernel/open_spec.rb89
-rw-r--r--spec/ruby/core/kernel/p_spec.rb6
-rw-r--r--spec/ruby/core/kernel/printf_spec.rb7
-rw-r--r--spec/ruby/core/kernel/proc_spec.rb26
-rw-r--r--spec/ruby/core/kernel/public_send_spec.rb4
-rw-r--r--spec/ruby/core/kernel/remove_instance_variable_spec.rb13
-rw-r--r--spec/ruby/core/kernel/require_relative_spec.rb10
-rw-r--r--spec/ruby/core/kernel/require_spec.rb20
-rw-r--r--spec/ruby/core/kernel/shared/dup_clone.rb24
-rw-r--r--spec/ruby/core/kernel/shared/load.rb83
-rw-r--r--spec/ruby/core/kernel/shared/require.rb84
-rw-r--r--spec/ruby/core/kernel/shared/sprintf.rb85
-rw-r--r--spec/ruby/core/kernel/shared/sprintf_encoding.rb39
-rw-r--r--spec/ruby/core/kernel/singleton_class_spec.rb51
-rw-r--r--spec/ruby/core/kernel/sleep_spec.rb28
-rw-r--r--spec/ruby/core/kernel/sprintf_spec.rb16
-rw-r--r--spec/ruby/core/kernel/system_spec.rb17
-rw-r--r--spec/ruby/core/kernel/taint_spec.rb59
-rw-r--r--spec/ruby/core/kernel/tainted_spec.rb30
-rw-r--r--spec/ruby/core/kernel/test_spec.rb4
-rw-r--r--spec/ruby/core/kernel/to_s_spec.rb10
-rw-r--r--spec/ruby/core/kernel/trust_spec.rb41
-rw-r--r--spec/ruby/core/kernel/untaint_spec.rb41
-rw-r--r--spec/ruby/core/kernel/untrust_spec.rb39
-rw-r--r--spec/ruby/core/kernel/untrusted_spec.rb44
-rw-r--r--spec/ruby/core/kernel/warn_spec.rb141
-rw-r--r--spec/ruby/core/main/fixtures/using.rb1
-rw-r--r--spec/ruby/core/main/fixtures/using_in_main.rb5
-rw-r--r--spec/ruby/core/main/fixtures/using_in_method.rb5
-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/ruby2_keywords_spec.rb10
-rw-r--r--spec/ruby/core/main/using_spec.rb20
-rw-r--r--spec/ruby/core/marshal/dump_spec.rb319
-rw-r--r--spec/ruby/core/marshal/fixtures/classes.rb4
-rw-r--r--spec/ruby/core/marshal/fixtures/marshal_data.rb102
-rw-r--r--spec/ruby/core/marshal/shared/load.rb415
-rw-r--r--spec/ruby/core/matchdata/allocate_spec.rb8
-rw-r--r--spec/ruby/core/matchdata/begin_spec.rb28
-rw-r--r--spec/ruby/core/matchdata/byteoffset_spec.rb95
-rw-r--r--spec/ruby/core/matchdata/captures_spec.rb13
-rw-r--r--spec/ruby/core/matchdata/deconstruct_keys_spec.rb65
-rw-r--r--spec/ruby/core/matchdata/deconstruct_spec.rb8
-rw-r--r--spec/ruby/core/matchdata/element_reference_spec.rb36
-rw-r--r--spec/ruby/core/matchdata/named_captures_spec.rb12
-rw-r--r--spec/ruby/core/matchdata/post_match_spec.rb30
-rw-r--r--spec/ruby/core/matchdata/pre_match_spec.rb30
-rw-r--r--spec/ruby/core/matchdata/shared/captures.rb13
-rw-r--r--spec/ruby/core/matchdata/string_spec.rb5
-rw-r--r--spec/ruby/core/matchdata/to_a_spec.rb8
-rw-r--r--spec/ruby/core/matchdata/to_s_spec.rb8
-rw-r--r--spec/ruby/core/matchdata/values_at_spec.rb71
-rw-r--r--spec/ruby/core/math/cos_spec.rb26
-rw-r--r--spec/ruby/core/math/ldexp_spec.rb6
-rw-r--r--spec/ruby/core/math/sqrt_spec.rb4
-rw-r--r--spec/ruby/core/method/clone_spec.rb15
-rw-r--r--spec/ruby/core/method/compose_spec.rb3
-rw-r--r--spec/ruby/core/method/dup_spec.rb15
-rw-r--r--spec/ruby/core/method/fixtures/classes.rb30
-rw-r--r--spec/ruby/core/method/owner_spec.rb6
-rw-r--r--spec/ruby/core/method/parameters_spec.rb63
-rw-r--r--spec/ruby/core/method/private_spec.rb28
-rw-r--r--spec/ruby/core/method/protected_spec.rb28
-rw-r--r--spec/ruby/core/method/public_spec.rb28
-rw-r--r--spec/ruby/core/method/shared/dup.rb32
-rw-r--r--spec/ruby/core/method/shared/to_s.rb56
-rw-r--r--spec/ruby/core/method/source_location_spec.rb9
-rw-r--r--spec/ruby/core/method/super_method_spec.rb19
-rw-r--r--spec/ruby/core/method/to_proc_spec.rb2
-rw-r--r--spec/ruby/core/method/unbind_spec.rb12
-rw-r--r--spec/ruby/core/module/alias_method_spec.rb20
-rw-r--r--spec/ruby/core/module/append_features_spec.rb14
-rw-r--r--spec/ruby/core/module/attr_accessor_spec.rb19
-rw-r--r--spec/ruby/core/module/attr_reader_spec.rb17
-rw-r--r--spec/ruby/core/module/attr_spec.rb23
-rw-r--r--spec/ruby/core/module/attr_writer_spec.rb17
-rw-r--r--spec/ruby/core/module/autoload_spec.rb153
-rw-r--r--spec/ruby/core/module/class_variables_spec.rb8
-rw-r--r--spec/ruby/core/module/const_added_spec.rb35
-rw-r--r--spec/ruby/core/module/const_defined_spec.rb28
-rw-r--r--spec/ruby/core/module/const_get_spec.rb14
-rw-r--r--spec/ruby/core/module/const_set_spec.rb18
-rw-r--r--spec/ruby/core/module/const_source_location_spec.rb347
-rw-r--r--spec/ruby/core/module/define_method_spec.rb89
-rw-r--r--spec/ruby/core/module/deprecate_constant_spec.rb20
-rw-r--r--spec/ruby/core/module/extend_object_spec.rb14
-rw-r--r--spec/ruby/core/module/fixtures/autoload_const_source_location.rb6
-rw-r--r--spec/ruby/core/module/fixtures/autoload_during_autoload_after_define.rb6
-rw-r--r--spec/ruby/core/module/fixtures/classes.rb39
-rw-r--r--spec/ruby/core/module/fixtures/module.rb4
-rw-r--r--spec/ruby/core/module/include_spec.rb4
-rw-r--r--spec/ruby/core/module/included_modules_spec.rb2
-rw-r--r--spec/ruby/core/module/instance_method_spec.rb42
-rw-r--r--spec/ruby/core/module/method_added_spec.rb73
-rw-r--r--spec/ruby/core/module/module_function_spec.rb136
-rw-r--r--spec/ruby/core/module/name_spec.rb78
-rw-r--r--spec/ruby/core/module/prepend_features_spec.rb14
-rw-r--r--spec/ruby/core/module/prepend_spec.rb95
-rw-r--r--spec/ruby/core/module/private_class_method_spec.rb14
-rw-r--r--spec/ruby/core/module/public_class_method_spec.rb20
-rw-r--r--spec/ruby/core/module/refine_spec.rb128
-rw-r--r--spec/ruby/core/module/refinements_spec.rb45
-rw-r--r--spec/ruby/core/module/ruby2_keywords_spec.rb327
-rw-r--r--spec/ruby/core/module/set_temporary_name_spec.rb68
-rw-r--r--spec/ruby/core/module/shared/attr_added.rb34
-rw-r--r--spec/ruby/core/module/shared/class_eval.rb27
-rw-r--r--spec/ruby/core/module/shared/set_visibility.rb28
-rw-r--r--spec/ruby/core/module/undef_method_spec.rb10
-rw-r--r--spec/ruby/core/module/undefined_instance_methods_spec.rb26
-rw-r--r--spec/ruby/core/module/used_refinements_spec.rb87
-rw-r--r--spec/ruby/core/module/using_spec.rb2
-rw-r--r--spec/ruby/core/mutex/lock_spec.rb4
-rw-r--r--spec/ruby/core/mutex/owned_spec.rb18
-rw-r--r--spec/ruby/core/nil/singleton_method_spec.rb15
-rw-r--r--spec/ruby/core/nil/to_s_spec.rb12
-rw-r--r--spec/ruby/core/numeric/clone_spec.rb10
-rw-r--r--spec/ruby/core/numeric/fdiv_spec.rb1
-rw-r--r--spec/ruby/core/numeric/magnitude_spec.rb1
-rw-r--r--spec/ruby/core/numeric/quo_spec.rb3
-rw-r--r--spec/ruby/core/numeric/remainder_spec.rb3
-rw-r--r--spec/ruby/core/numeric/shared/quo.rb7
-rw-r--r--spec/ruby/core/numeric/shared/step.rb8
-rw-r--r--spec/ruby/core/numeric/step_spec.rb85
-rw-r--r--spec/ruby/core/objectspace/define_finalizer_spec.rb108
-rw-r--r--spec/ruby/core/objectspace/weakkeymap/delete_spec.rb40
-rw-r--r--spec/ruby/core/objectspace/weakkeymap/element_reference_spec.rb26
-rw-r--r--spec/ruby/core/objectspace/weakkeymap/element_set_spec.rb71
-rw-r--r--spec/ruby/core/objectspace/weakkeymap/getkey_spec.rb14
-rw-r--r--spec/ruby/core/objectspace/weakkeymap/inspect_spec.rb17
-rw-r--r--spec/ruby/core/objectspace/weakkeymap/key_spec.rb33
-rw-r--r--spec/ruby/core/objectspace/weakmap/delete_spec.rb30
-rw-r--r--spec/ruby/core/objectspace/weakmap/element_set_spec.rb53
-rw-r--r--spec/ruby/core/objectspace/weakmap/shared/include.rb16
-rw-r--r--spec/ruby/core/proc/arity_spec.rb16
-rw-r--r--spec/ruby/core/proc/block_pass_spec.rb22
-rw-r--r--spec/ruby/core/proc/clone_spec.rb9
-rw-r--r--spec/ruby/core/proc/compose_spec.rb46
-rw-r--r--spec/ruby/core/proc/dup_spec.rb7
-rw-r--r--spec/ruby/core/proc/eql_spec.rb8
-rw-r--r--spec/ruby/core/proc/equal_value_spec.rb8
-rw-r--r--spec/ruby/core/proc/fixtures/proc_aref.rb1
-rw-r--r--spec/ruby/core/proc/lambda_spec.rb8
-rw-r--r--spec/ruby/core/proc/new_spec.rb72
-rw-r--r--spec/ruby/core/proc/parameters_spec.rb82
-rw-r--r--spec/ruby/core/proc/ruby2_keywords_spec.rb88
-rw-r--r--spec/ruby/core/proc/shared/compose.rb51
-rw-r--r--spec/ruby/core/proc/shared/dup.rb31
-rw-r--r--spec/ruby/core/proc/shared/equal.rb17
-rw-r--r--spec/ruby/core/proc/shared/to_s.rb22
-rw-r--r--spec/ruby/core/proc/source_location_spec.rb13
-rw-r--r--spec/ruby/core/process/_fork_spec.rb24
-rw-r--r--spec/ruby/core/process/argv0_spec.rb25
-rw-r--r--spec/ruby/core/process/clock_gettime_spec.rb101
-rw-r--r--spec/ruby/core/process/constants_spec.rb9
-rw-r--r--spec/ruby/core/process/detach_spec.rb35
-rw-r--r--spec/ruby/core/process/egid_spec.rb41
-rw-r--r--spec/ruby/core/process/euid_spec.rb12
-rw-r--r--spec/ruby/core/process/exec_spec.rb44
-rw-r--r--spec/ruby/core/process/exit_spec.rb2
-rw-r--r--spec/ruby/core/process/fixtures/argv0.rb6
-rw-r--r--spec/ruby/core/process/fixtures/kill.rb2
-rw-r--r--spec/ruby/core/process/spawn_spec.rb32
-rw-r--r--spec/ruby/core/process/status/equal_value_spec.rb2
-rw-r--r--spec/ruby/core/process/status/exited_spec.rb2
-rw-r--r--spec/ruby/core/process/status/exitstatus_spec.rb2
-rw-r--r--spec/ruby/core/process/status/signaled_spec.rb2
-rw-r--r--spec/ruby/core/process/status/success_spec.rb2
-rw-r--r--spec/ruby/core/process/status/termsig_spec.rb6
-rw-r--r--spec/ruby/core/process/status/to_i_spec.rb2
-rw-r--r--spec/ruby/core/process/status/wait_spec.rb158
-rw-r--r--spec/ruby/core/process/times_spec.rb32
-rw-r--r--spec/ruby/core/process/wait2_spec.rb13
-rw-r--r--spec/ruby/core/process/wait_spec.rb2
-rw-r--r--spec/ruby/core/process/waitpid_spec.rb3
-rw-r--r--spec/ruby/core/process/warmup_spec.rb11
-rw-r--r--spec/ruby/core/queue/deq_spec.rb7
-rw-r--r--spec/ruby/core/queue/initialize_spec.rb46
-rw-r--r--spec/ruby/core/queue/pop_spec.rb7
-rw-r--r--spec/ruby/core/queue/shift_spec.rb7
-rw-r--r--spec/ruby/core/random/bytes_spec.rb3
-rw-r--r--spec/ruby/core/random/default_spec.rb24
-rw-r--r--spec/ruby/core/random/new_spec.rb1
-rw-r--r--spec/ruby/core/random/rand_spec.rb5
-rw-r--r--spec/ruby/core/range/bsearch_spec.rb226
-rw-r--r--spec/ruby/core/range/case_compare_spec.rb10
-rw-r--r--spec/ruby/core/range/clone_spec.rb26
-rw-r--r--spec/ruby/core/range/count_spec.rb16
-rw-r--r--spec/ruby/core/range/cover_spec.rb4
-rw-r--r--spec/ruby/core/range/dup_spec.rb10
-rw-r--r--spec/ruby/core/range/each_spec.rb6
-rw-r--r--spec/ruby/core/range/equal_value_spec.rb6
-rw-r--r--spec/ruby/core/range/first_spec.rb6
-rw-r--r--spec/ruby/core/range/frozen_spec.rb25
-rw-r--r--spec/ruby/core/range/include_spec.rb4
-rw-r--r--spec/ruby/core/range/initialize_spec.rb15
-rw-r--r--spec/ruby/core/range/inspect_spec.rb28
-rw-r--r--spec/ruby/core/range/last_spec.rb6
-rw-r--r--spec/ruby/core/range/max_spec.rb24
-rw-r--r--spec/ruby/core/range/min_spec.rb6
-rw-r--r--spec/ruby/core/range/minmax_spec.rb146
-rw-r--r--spec/ruby/core/range/new_spec.rb30
-rw-r--r--spec/ruby/core/range/shared/cover.rb56
-rw-r--r--spec/ruby/core/range/shared/cover_and_include.rb9
-rw-r--r--spec/ruby/core/range/size_spec.rb85
-rw-r--r--spec/ruby/core/range/step_spec.rb68
-rw-r--r--spec/ruby/core/range/to_a_spec.rb6
-rw-r--r--spec/ruby/core/range/to_s_spec.rb22
-rw-r--r--spec/ruby/core/rational/abs_spec.rb1
-rw-r--r--spec/ruby/core/rational/ceil_spec.rb1
-rw-r--r--spec/ruby/core/rational/coerce_spec.rb5
-rw-r--r--spec/ruby/core/rational/comparison_spec.rb1
-rw-r--r--spec/ruby/core/rational/denominator_spec.rb1
-rw-r--r--spec/ruby/core/rational/div_spec.rb1
-rw-r--r--spec/ruby/core/rational/divide_spec.rb1
-rw-r--r--spec/ruby/core/rational/divmod_spec.rb1
-rw-r--r--spec/ruby/core/rational/equal_value_spec.rb1
-rw-r--r--spec/ruby/core/rational/exponent_spec.rb1
-rw-r--r--spec/ruby/core/rational/fdiv_spec.rb1
-rw-r--r--spec/ruby/core/rational/floor_spec.rb1
-rw-r--r--spec/ruby/core/rational/hash_spec.rb1
-rw-r--r--spec/ruby/core/rational/inspect_spec.rb1
-rw-r--r--spec/ruby/core/rational/integer_spec.rb1
-rw-r--r--spec/ruby/core/rational/magnitude_spec.rb1
-rw-r--r--spec/ruby/core/rational/minus_spec.rb48
-rw-r--r--spec/ruby/core/rational/modulo_spec.rb1
-rw-r--r--spec/ruby/core/rational/multiply_spec.rb1
-rw-r--r--spec/ruby/core/rational/numerator_spec.rb1
-rw-r--r--spec/ruby/core/rational/plus_spec.rb1
-rw-r--r--spec/ruby/core/rational/quo_spec.rb1
-rw-r--r--spec/ruby/core/rational/remainder_spec.rb1
-rw-r--r--spec/ruby/core/rational/to_f_spec.rb1
-rw-r--r--spec/ruby/core/rational/to_i_spec.rb1
-rw-r--r--spec/ruby/core/rational/to_r_spec.rb1
-rw-r--r--spec/ruby/core/rational/to_s_spec.rb1
-rw-r--r--spec/ruby/core/rational/truncate_spec.rb1
-rw-r--r--spec/ruby/core/rational/zero_spec.rb1
-rw-r--r--spec/ruby/core/refinement/extend_object_spec.rb6
-rw-r--r--spec/ruby/core/refinement/fixtures/classes.rb10
-rw-r--r--spec/ruby/core/refinement/import_methods_spec.rb269
-rw-r--r--spec/ruby/core/refinement/include_spec.rb27
-rw-r--r--spec/ruby/core/refinement/prepend_spec.rb27
-rw-r--r--spec/ruby/core/refinement/refined_class_spec.rb17
-rw-r--r--spec/ruby/core/regexp/compile_spec.rb4
-rw-r--r--spec/ruby/core/regexp/initialize_spec.rb14
-rw-r--r--spec/ruby/core/regexp/linear_time_spec.rb25
-rw-r--r--spec/ruby/core/regexp/new_spec.rb14
-rw-r--r--spec/ruby/core/regexp/shared/new.rb212
-rw-r--r--spec/ruby/core/regexp/shared/quote.rb16
-rw-r--r--spec/ruby/core/regexp/source_spec.rb22
-rw-r--r--spec/ruby/core/regexp/timeout_spec.rb35
-rw-r--r--spec/ruby/core/regexp/try_convert_spec.rb6
-rw-r--r--spec/ruby/core/regexp/union_spec.rb51
-rw-r--r--spec/ruby/core/signal/signame_spec.rb12
-rw-r--r--spec/ruby/core/signal/trap_spec.rb43
-rw-r--r--spec/ruby/core/sizedqueue/append_spec.rb7
-rw-r--r--spec/ruby/core/sizedqueue/deq_spec.rb7
-rw-r--r--spec/ruby/core/sizedqueue/enq_spec.rb7
-rw-r--r--spec/ruby/core/sizedqueue/pop_spec.rb7
-rw-r--r--spec/ruby/core/sizedqueue/push_spec.rb7
-rw-r--r--spec/ruby/core/sizedqueue/shift_spec.rb7
-rw-r--r--spec/ruby/core/string/append_spec.rb6
-rw-r--r--spec/ruby/core/string/ascii_only_spec.rb23
-rw-r--r--spec/ruby/core/string/b_spec.rb10
-rw-r--r--spec/ruby/core/string/byteindex_spec.rb304
-rw-r--r--spec/ruby/core/string/byterindex_spec.rb359
-rw-r--r--spec/ruby/core/string/bytes_spec.rb2
-rw-r--r--spec/ruby/core/string/bytesize_spec.rb10
-rw-r--r--spec/ruby/core/string/byteslice_spec.rb14
-rw-r--r--spec/ruby/core/string/bytesplice_spec.rb134
-rw-r--r--spec/ruby/core/string/capitalize_spec.rb51
-rw-r--r--spec/ruby/core/string/casecmp_spec.rb10
-rw-r--r--spec/ruby/core/string/center_spec.rb47
-rw-r--r--spec/ruby/core/string/chars_spec.rb8
-rw-r--r--spec/ruby/core/string/chilled_string_spec.rb69
-rw-r--r--spec/ruby/core/string/chomp_spec.rb78
-rw-r--r--spec/ruby/core/string/chop_spec.rb25
-rw-r--r--spec/ruby/core/string/clear_spec.rb1
-rw-r--r--spec/ruby/core/string/clone_spec.rb4
-rw-r--r--spec/ruby/core/string/codepoints_spec.rb2
-rw-r--r--spec/ruby/core/string/comparison_spec.rb10
-rw-r--r--spec/ruby/core/string/concat_spec.rb7
-rw-r--r--spec/ruby/core/string/crypt_spec.rb30
-rw-r--r--spec/ruby/core/string/dedup_spec.rb8
-rw-r--r--spec/ruby/core/string/delete_prefix_spec.rb23
-rw-r--r--spec/ruby/core/string/delete_spec.rb22
-rw-r--r--spec/ruby/core/string/delete_suffix_spec.rb23
-rw-r--r--spec/ruby/core/string/downcase_spec.rb29
-rw-r--r--spec/ruby/core/string/dump_spec.rb34
-rw-r--r--spec/ruby/core/string/dup_spec.rb13
-rw-r--r--spec/ruby/core/string/each_byte_spec.rb16
-rw-r--r--spec/ruby/core/string/each_char_spec.rb1
-rw-r--r--spec/ruby/core/string/each_grapheme_cluster_spec.rb11
-rw-r--r--spec/ruby/core/string/element_set_spec.rb29
-rw-r--r--spec/ruby/core/string/encode_spec.rb26
-rw-r--r--spec/ruby/core/string/encoding_spec.rb25
-rw-r--r--spec/ruby/core/string/fixtures/iso-8859-9-encoding.rb2
-rw-r--r--spec/ruby/core/string/fixtures/to_c.rb5
-rw-r--r--spec/ruby/core/string/fixtures/utf-8-encoding.rb7
-rw-r--r--spec/ruby/core/string/force_encoding_spec.rb1
-rw-r--r--spec/ruby/core/string/freeze_spec.rb1
-rw-r--r--spec/ruby/core/string/grapheme_clusters_spec.rb1
-rw-r--r--spec/ruby/core/string/gsub_spec.rb195
-rw-r--r--spec/ruby/core/string/include_spec.rb14
-rw-r--r--spec/ruby/core/string/index_spec.rb26
-rw-r--r--spec/ruby/core/string/insert_spec.rb23
-rw-r--r--spec/ruby/core/string/inspect_spec.rb32
-rw-r--r--spec/ruby/core/string/lines_spec.rb1
-rw-r--r--spec/ruby/core/string/ljust_spec.rb47
-rw-r--r--spec/ruby/core/string/lstrip_spec.rb51
-rw-r--r--spec/ruby/core/string/modulo_spec.rb62
-rw-r--r--spec/ruby/core/string/ord_spec.rb5
-rw-r--r--spec/ruby/core/string/partition_spec.rb22
-rw-r--r--spec/ruby/core/string/plus_spec.rb18
-rw-r--r--spec/ruby/core/string/prepend_spec.rb11
-rw-r--r--spec/ruby/core/string/reverse_spec.rb43
-rw-r--r--spec/ruby/core/string/rindex_spec.rb24
-rw-r--r--spec/ruby/core/string/rjust_spec.rb47
-rw-r--r--spec/ruby/core/string/rpartition_spec.rb22
-rw-r--r--spec/ruby/core/string/rstrip_spec.rb53
-rw-r--r--spec/ruby/core/string/scan_spec.rb56
-rw-r--r--spec/ruby/core/string/scrub_spec.rb48
-rw-r--r--spec/ruby/core/string/setbyte_spec.rb7
-rw-r--r--spec/ruby/core/string/shared/byte_index_common.rb63
-rw-r--r--spec/ruby/core/string/shared/chars.rb26
-rw-r--r--spec/ruby/core/string/shared/codepoints.rb6
-rw-r--r--spec/ruby/core/string/shared/concat.rb45
-rw-r--r--spec/ruby/core/string/shared/dedup.rb56
-rw-r--r--spec/ruby/core/string/shared/each_codepoint_without_block.rb4
-rw-r--r--spec/ruby/core/string/shared/each_line.rb34
-rw-r--r--spec/ruby/core/string/shared/encode.rb1
-rw-r--r--spec/ruby/core/string/shared/eql.rb10
-rw-r--r--spec/ruby/core/string/shared/length.rb10
-rw-r--r--spec/ruby/core/string/shared/partition.rb43
-rw-r--r--spec/ruby/core/string/shared/replace.rb31
-rw-r--r--spec/ruby/core/string/shared/slice.rb273
-rw-r--r--spec/ruby/core/string/shared/strip.rb18
-rw-r--r--spec/ruby/core/string/shared/succ.rb27
-rw-r--r--spec/ruby/core/string/shared/to_a.rb9
-rw-r--r--spec/ruby/core/string/shared/to_s.rb7
-rw-r--r--spec/ruby/core/string/shared/to_sym.rb11
-rw-r--r--spec/ruby/core/string/slice_spec.rb180
-rw-r--r--spec/ruby/core/string/split_spec.rb265
-rw-r--r--spec/ruby/core/string/squeeze_spec.rb28
-rw-r--r--spec/ruby/core/string/start_with_spec.rb19
-rw-r--r--spec/ruby/core/string/strip_spec.rb31
-rw-r--r--spec/ruby/core/string/sub_spec.rb158
-rw-r--r--spec/ruby/core/string/swapcase_spec.rb27
-rw-r--r--spec/ruby/core/string/to_c_spec.rb114
-rw-r--r--spec/ruby/core/string/to_i_spec.rb12
-rw-r--r--spec/ruby/core/string/tr_s_spec.rb35
-rw-r--r--spec/ruby/core/string/tr_spec.rb35
-rw-r--r--spec/ruby/core/string/try_convert_spec.rb2
-rw-r--r--spec/ruby/core/string/uminus_spec.rb47
-rw-r--r--spec/ruby/core/string/undump_spec.rb12
-rw-r--r--spec/ruby/core/string/unicode_normalize_spec.rb1
-rw-r--r--spec/ruby/core/string/unicode_normalized_spec.rb1
-rw-r--r--spec/ruby/core/string/unpack/a_spec.rb2
-rw-r--r--spec/ruby/core/string/unpack/b_spec.rb40
-rw-r--r--spec/ruby/core/string/unpack/c_spec.rb16
-rw-r--r--spec/ruby/core/string/unpack/h_spec.rb32
-rw-r--r--spec/ruby/core/string/unpack/m_spec.rb5
-rw-r--r--spec/ruby/core/string/unpack/p_spec.rb12
-rw-r--r--spec/ruby/core/string/unpack/shared/basic.rb28
-rw-r--r--spec/ruby/core/string/unpack/shared/float.rb68
-rw-r--r--spec/ruby/core/string/unpack/shared/integer.rb100
-rw-r--r--spec/ruby/core/string/unpack/shared/taint.rb81
-rw-r--r--spec/ruby/core/string/unpack/shared/unicode.rb16
-rw-r--r--spec/ruby/core/string/unpack/u_spec.rb2
-rw-r--r--spec/ruby/core/string/unpack/w_spec.rb16
-rw-r--r--spec/ruby/core/string/unpack/z_spec.rb5
-rw-r--r--spec/ruby/core/string/unpack1_spec.rb12
-rw-r--r--spec/ruby/core/string/unpack_spec.rb34
-rw-r--r--spec/ruby/core/string/upcase_spec.rb29
-rw-r--r--spec/ruby/core/string/uplus_spec.rb4
-rw-r--r--spec/ruby/core/string/upto_spec.rb6
-rw-r--r--spec/ruby/core/string/valid_encoding/utf_8_spec.rb214
-rw-r--r--spec/ruby/core/string/valid_encoding_spec.rb30
-rw-r--r--spec/ruby/core/struct/constants_spec.rb15
-rw-r--r--spec/ruby/core/struct/deconstruct_keys_spec.rb146
-rw-r--r--spec/ruby/core/struct/deconstruct_spec.rb12
-rw-r--r--spec/ruby/core/struct/fixtures/classes.rb6
-rw-r--r--spec/ruby/core/struct/initialize_spec.rb18
-rw-r--r--spec/ruby/core/struct/inspect_spec.rb5
-rw-r--r--spec/ruby/core/struct/keyword_init_spec.rb40
-rw-r--r--spec/ruby/core/struct/new_spec.rb35
-rw-r--r--spec/ruby/core/struct/shared/inspect.rb35
-rw-r--r--spec/ruby/core/struct/values_at_spec.rb55
-rw-r--r--spec/ruby/core/symbol/casecmp_spec.rb8
-rw-r--r--spec/ruby/core/symbol/end_with_spec.rb6
-rw-r--r--spec/ruby/core/symbol/inspect_spec.rb2
-rw-r--r--spec/ruby/core/symbol/name_spec.rb24
-rw-r--r--spec/ruby/core/symbol/shared/id2name.rb7
-rw-r--r--spec/ruby/core/symbol/shared/slice.rb20
-rw-r--r--spec/ruby/core/symbol/start_with_spec.rb6
-rw-r--r--spec/ruby/core/symbol/to_proc_spec.rb58
-rw-r--r--spec/ruby/core/thread/backtrace/limit_spec.rb15
-rw-r--r--spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb11
-rw-r--r--spec/ruby/core/thread/backtrace/location/fixtures/subdir/absolute_path_main_chdir.rb11
-rw-r--r--spec/ruby/core/thread/backtrace/location/fixtures/subdir/sibling.rb1
-rw-r--r--spec/ruby/core/thread/backtrace/location/label_spec.rb10
-rw-r--r--spec/ruby/core/thread/backtrace/location/lineno_spec.rb2
-rw-r--r--spec/ruby/core/thread/backtrace/location/path_spec.rb2
-rw-r--r--spec/ruby/core/thread/backtrace_locations_spec.rb12
-rw-r--r--spec/ruby/core/thread/backtrace_spec.rb2
-rw-r--r--spec/ruby/core/thread/each_caller_location_spec.rb49
-rw-r--r--spec/ruby/core/thread/exclusive_spec.rb49
-rw-r--r--spec/ruby/core/thread/fetch_spec.rb30
-rw-r--r--spec/ruby/core/thread/ignore_deadlock_spec.rb26
-rw-r--r--spec/ruby/core/thread/kill_spec.rb4
-rw-r--r--spec/ruby/core/thread/native_thread_id_spec.rb37
-rw-r--r--spec/ruby/core/thread/raise_spec.rb24
-rw-r--r--spec/ruby/core/thread/report_on_exception_spec.rb49
-rw-r--r--spec/ruby/core/thread/shared/exit.rb41
-rw-r--r--spec/ruby/core/thread/shared/to_s.rb4
-rw-r--r--spec/ruby/core/thread/thread_variable_get_spec.rb2
-rw-r--r--spec/ruby/core/time/_load_spec.rb3
-rw-r--r--spec/ruby/core/time/at_spec.rb30
-rw-r--r--spec/ruby/core/time/ceil_spec.rb64
-rw-r--r--spec/ruby/core/time/deconstruct_keys_spec.rb45
-rw-r--r--spec/ruby/core/time/fixtures/classes.rb1
-rw-r--r--spec/ruby/core/time/floor_spec.rb52
-rw-r--r--spec/ruby/core/time/inspect_spec.rb44
-rw-r--r--spec/ruby/core/time/localtime_spec.rb16
-rw-r--r--spec/ruby/core/time/new_spec.rb343
-rw-r--r--spec/ruby/core/time/now_spec.rb51
-rw-r--r--spec/ruby/core/time/shared/gmtime.rb4
-rw-r--r--spec/ruby/core/time/shared/local.rb11
-rw-r--r--spec/ruby/core/time/shared/time_params.rb11
-rw-r--r--spec/ruby/core/time/strftime_spec.rb41
-rw-r--r--spec/ruby/core/time/succ_spec.rb39
-rw-r--r--spec/ruby/core/time/utc_spec.rb51
-rw-r--r--spec/ruby/core/time/zone_spec.rb31
-rw-r--r--spec/ruby/core/tracepoint/allow_reentry_spec.rb32
-rw-r--r--spec/ruby/core/tracepoint/enable_spec.rb63
-rw-r--r--spec/ruby/core/tracepoint/inspect_spec.rb27
-rw-r--r--spec/ruby/core/tracepoint/path_spec.rb31
-rw-r--r--spec/ruby/core/true/singleton_method_spec.rb15
-rw-r--r--spec/ruby/core/true/to_s_spec.rb12
-rw-r--r--spec/ruby/core/unboundmethod/bind_call_spec.rb82
-rw-r--r--spec/ruby/core/unboundmethod/bind_spec.rb8
-rw-r--r--spec/ruby/core/unboundmethod/clone_spec.rb13
-rw-r--r--spec/ruby/core/unboundmethod/dup_spec.rb15
-rw-r--r--spec/ruby/core/unboundmethod/equal_value_spec.rb76
-rw-r--r--spec/ruby/core/unboundmethod/fixtures/classes.rb20
-rw-r--r--spec/ruby/core/unboundmethod/hash_spec.rb7
-rw-r--r--spec/ruby/core/unboundmethod/owner_spec.rb7
-rw-r--r--spec/ruby/core/unboundmethod/private_spec.rb28
-rw-r--r--spec/ruby/core/unboundmethod/protected_spec.rb28
-rw-r--r--spec/ruby/core/unboundmethod/public_spec.rb28
-rw-r--r--spec/ruby/core/unboundmethod/shared/dup.rb32
-rw-r--r--spec/ruby/core/unboundmethod/shared/to_s.rb16
-rw-r--r--spec/ruby/core/unboundmethod/source_location_spec.rb9
-rw-r--r--spec/ruby/core/unboundmethod/super_method_spec.rb21
-rw-r--r--spec/ruby/core/warning/element_reference_spec.rb33
-rw-r--r--spec/ruby/core/warning/element_set_spec.rb56
-rw-r--r--spec/ruby/core/warning/warn_spec.rb103
-rw-r--r--spec/ruby/default.mspec1
-rw-r--r--spec/ruby/fixtures/code/c/load_fixture.rb1
-rw-r--r--spec/ruby/fixtures/code/concurrent_require_fixture.rb4
-rw-r--r--spec/ruby/fixtures/code/d/load_fixture.rb.rb1
-rw-r--r--spec/ruby/fixtures/code/load_wrap_fixture.rb12
-rw-r--r--spec/ruby/fixtures/code/wrap_fixture.rb9
-rw-r--r--spec/ruby/fixtures/constants.rb24
-rw-r--r--spec/ruby/language/END_spec.rb26
-rw-r--r--spec/ruby/language/alias_spec.rb33
-rw-r--r--spec/ruby/language/assignments_spec.rb529
-rw-r--r--spec/ruby/language/block_spec.rb403
-rw-r--r--spec/ruby/language/break_spec.rb2
-rw-r--r--spec/ruby/language/case_spec.rb137
-rw-r--r--spec/ruby/language/class_spec.rb18
-rw-r--r--spec/ruby/language/class_variable_spec.rb56
-rw-r--r--spec/ruby/language/comment_spec.rb16
-rw-r--r--spec/ruby/language/constants_spec.rb38
-rw-r--r--spec/ruby/language/def_spec.rb35
-rw-r--r--spec/ruby/language/defined_spec.rb161
-rw-r--r--spec/ruby/language/delegation_spec.rb109
-rw-r--r--spec/ruby/language/encoding_spec.rb8
-rw-r--r--spec/ruby/language/ensure_spec.rb17
-rw-r--r--spec/ruby/language/execution_spec.rb78
-rw-r--r--spec/ruby/language/file_spec.rb22
-rw-r--r--spec/ruby/language/fixtures/defined.rb3
-rw-r--r--spec/ruby/language/fixtures/freeze_magic_comment_required_diff_enc.rbbin181 -> 120 bytes
-rw-r--r--spec/ruby/language/fixtures/freeze_magic_comment_two_literals.rb2
-rw-r--r--spec/ruby/language/fixtures/rescue/top_level.rb7
-rw-r--r--spec/ruby/language/fixtures/super.rb62
-rw-r--r--spec/ruby/language/fixtures/variables.rb72
-rw-r--r--spec/ruby/language/hash_spec.rb67
-rw-r--r--spec/ruby/language/heredoc_spec.rb18
-rw-r--r--spec/ruby/language/if_spec.rb53
-rw-r--r--spec/ruby/language/keyword_arguments_spec.rb398
-rw-r--r--spec/ruby/language/lambda_spec.rb132
-rw-r--r--spec/ruby/language/method_spec.rb996
-rw-r--r--spec/ruby/language/module_spec.rb33
-rw-r--r--spec/ruby/language/numbered_parameters_spec.rb186
-rw-r--r--spec/ruby/language/optional_assignments_spec.rb314
-rw-r--r--spec/ruby/language/pattern_matching_spec.rb2196
-rw-r--r--spec/ruby/language/precedence_spec.rb78
-rw-r--r--spec/ruby/language/predefined_spec.rb498
-rw-r--r--spec/ruby/language/proc_spec.rb35
-rw-r--r--spec/ruby/language/range_spec.rb22
-rw-r--r--spec/ruby/language/regexp/character_classes_spec.rb11
-rw-r--r--spec/ruby/language/regexp/encoding_spec.rb42
-rw-r--r--spec/ruby/language/regexp/escapes_spec.rb84
-rw-r--r--spec/ruby/language/regexp/repetition_spec.rb8
-rw-r--r--spec/ruby/language/regexp_spec.rb29
-rw-r--r--spec/ruby/language/rescue_spec.rb113
-rw-r--r--spec/ruby/language/return_spec.rb61
-rw-r--r--spec/ruby/language/safe_navigator_spec.rb80
-rw-r--r--spec/ruby/language/safe_spec.rb120
-rw-r--r--spec/ruby/language/send_spec.rb56
-rw-r--r--spec/ruby/language/singleton_class_spec.rb26
-rw-r--r--spec/ruby/language/source_encoding_spec.rb2
-rw-r--r--spec/ruby/language/string_spec.rb64
-rw-r--r--spec/ruby/language/super_spec.rb30
-rw-r--r--spec/ruby/language/symbol_spec.rb14
-rw-r--r--spec/ruby/language/undef_spec.rb9
-rw-r--r--spec/ruby/language/variables_spec.rb126
-rw-r--r--spec/ruby/language/yield_spec.rb33
-rw-r--r--spec/ruby/library/English/English_spec.rb16
-rw-r--r--spec/ruby/library/bigdecimal/add_spec.rb4
-rw-r--r--spec/ruby/library/bigdecimal/core_spec.rb59
-rw-r--r--spec/ruby/library/bigdecimal/exponent_spec.rb11
-rw-r--r--spec/ruby/library/bigdecimal/remainder_spec.rb28
-rw-r--r--spec/ruby/library/bigdecimal/round_spec.rb12
-rw-r--r--spec/ruby/library/bigdecimal/shared/to_int.rb2
-rw-r--r--spec/ruby/library/bigdecimal/sqrt_spec.rb6
-rw-r--r--spec/ruby/library/bigdecimal/to_r_spec.rb12
-rw-r--r--spec/ruby/library/bigdecimal/to_s_spec.rb27
-rw-r--r--spec/ruby/library/bigmath/log_spec.rb10
-rw-r--r--spec/ruby/library/cgi/cookie/name_spec.rb12
-rw-r--r--spec/ruby/library/cgi/cookie/parse_spec.rb10
-rw-r--r--spec/ruby/library/cgi/escapeURIComponent_spec.rb57
-rw-r--r--spec/ruby/library/cgi/initialize_spec.rb2
-rw-r--r--spec/ruby/library/cmath/math/acos_spec.rb18
-rw-r--r--spec/ruby/library/cmath/math/acosh_spec.rb18
-rw-r--r--spec/ruby/library/cmath/math/asin_spec.rb18
-rw-r--r--spec/ruby/library/cmath/math/asinh_spec.rb18
-rw-r--r--spec/ruby/library/cmath/math/atan2_spec.rb18
-rw-r--r--spec/ruby/library/cmath/math/atan_spec.rb18
-rw-r--r--spec/ruby/library/cmath/math/atanh_spec.rb20
-rw-r--r--spec/ruby/library/cmath/math/cos_spec.rb18
-rw-r--r--spec/ruby/library/cmath/math/cosh_spec.rb18
-rw-r--r--spec/ruby/library/cmath/math/exp_spec.rb18
-rw-r--r--spec/ruby/library/cmath/math/fixtures/classes.rb4
-rw-r--r--spec/ruby/library/cmath/math/log10_spec.rb18
-rw-r--r--spec/ruby/library/cmath/math/log_spec.rb18
-rw-r--r--spec/ruby/library/cmath/math/shared/acos.rb41
-rw-r--r--spec/ruby/library/cmath/math/shared/acosh.rb37
-rw-r--r--spec/ruby/library/cmath/math/shared/asin.rb47
-rw-r--r--spec/ruby/library/cmath/math/shared/asinh.rb32
-rw-r--r--spec/ruby/library/cmath/math/shared/atan.rb32
-rw-r--r--spec/ruby/library/cmath/math/shared/atan2.rb34
-rw-r--r--spec/ruby/library/cmath/math/shared/atanh.rb30
-rw-r--r--spec/ruby/library/cmath/math/shared/cos.rb30
-rw-r--r--spec/ruby/library/cmath/math/shared/cosh.rb28
-rw-r--r--spec/ruby/library/cmath/math/shared/exp.rb28
-rw-r--r--spec/ruby/library/cmath/math/shared/log.rb39
-rw-r--r--spec/ruby/library/cmath/math/shared/log10.rb41
-rw-r--r--spec/ruby/library/cmath/math/shared/sin.rb30
-rw-r--r--spec/ruby/library/cmath/math/shared/sinh.rb28
-rw-r--r--spec/ruby/library/cmath/math/shared/sqrt.rb34
-rw-r--r--spec/ruby/library/cmath/math/shared/tan.rb28
-rw-r--r--spec/ruby/library/cmath/math/shared/tanh.rb32
-rw-r--r--spec/ruby/library/cmath/math/sin_spec.rb18
-rw-r--r--spec/ruby/library/cmath/math/sinh_spec.rb18
-rw-r--r--spec/ruby/library/cmath/math/sqrt_spec.rb18
-rw-r--r--spec/ruby/library/cmath/math/tan_spec.rb18
-rw-r--r--spec/ruby/library/cmath/math/tanh_spec.rb18
-rw-r--r--spec/ruby/library/coverage/result_spec.rb284
-rw-r--r--spec/ruby/library/coverage/running_spec.rb20
-rw-r--r--spec/ruby/library/coverage/start_spec.rb87
-rw-r--r--spec/ruby/library/coverage/supported_spec.rb32
-rw-r--r--spec/ruby/library/csv/generate_spec.rb2
-rw-r--r--spec/ruby/library/date/civil_spec.rb7
-rw-r--r--spec/ruby/library/date/deconstruct_keys_spec.rb44
-rw-r--r--spec/ruby/library/date/iso8601_spec.rb26
-rw-r--r--spec/ruby/library/date/new_spec.rb1
-rw-r--r--spec/ruby/library/date/parse_spec.rb12
-rw-r--r--spec/ruby/library/date/shared/new_bang.rb14
-rw-r--r--spec/ruby/library/date/shared/parse.rb4
-rw-r--r--spec/ruby/library/date/shared/parse_eu.rb8
-rw-r--r--spec/ruby/library/date/shared/parse_us.rb8
-rw-r--r--spec/ruby/library/date/shared/valid_jd.rb20
-rw-r--r--spec/ruby/library/date/strftime_spec.rb6
-rw-r--r--spec/ruby/library/datetime/deconstruct_keys_spec.rb46
-rw-r--r--spec/ruby/library/datetime/rfc2822_spec.rb4
-rw-r--r--spec/ruby/library/datetime/strftime_spec.rb5
-rw-r--r--spec/ruby/library/datetime/to_time_spec.rb18
-rw-r--r--spec/ruby/library/delegate/delegate_class/respond_to_missing_spec.rb1
-rw-r--r--spec/ruby/library/delegate/delegator/taint_spec.rb17
-rw-r--r--spec/ruby/library/delegate/delegator/trust_spec.rb16
-rw-r--r--spec/ruby/library/delegate/delegator/untaint_spec.rb18
-rw-r--r--spec/ruby/library/delegate/delegator/untrust_spec.rb17
-rw-r--r--spec/ruby/library/digest/instance/shared/update.rb2
-rw-r--r--spec/ruby/library/digest/md5/shared/sample.rb17
-rw-r--r--spec/ruby/library/drb/start_service_spec.rb47
-rw-r--r--spec/ruby/library/erb/new_spec.rb16
-rw-r--r--spec/ruby/library/erb/run_spec.rb2
-rw-r--r--spec/ruby/library/etc/confstr_spec.rb2
-rw-r--r--spec/ruby/library/etc/passwd_spec.rb2
-rw-r--r--spec/ruby/library/etc/sysconf_spec.rb2
-rw-r--r--spec/ruby/library/etc/sysconfdir_spec.rb2
-rw-r--r--spec/ruby/library/etc/systmpdir_spec.rb2
-rw-r--r--spec/ruby/library/etc/uname_spec.rb14
-rw-r--r--spec/ruby/library/expect/expect_spec.rb3
-rw-r--r--spec/ruby/library/fiber/current_spec.rb21
-rw-r--r--spec/ruby/library/fiber/resume_spec.rb35
-rw-r--r--spec/ruby/library/fiber/transfer_spec.rb56
-rw-r--r--spec/ruby/library/fiddle/handle/initialize_spec.rb10
-rw-r--r--spec/ruby/library/io-wait/fixtures/classes.rb12
-rw-r--r--spec/ruby/library/io-wait/wait_readable_spec.rb27
-rw-r--r--spec/ruby/library/io-wait/wait_spec.rb155
-rw-r--r--spec/ruby/library/io-wait/wait_writable_spec.rb20
-rw-r--r--spec/ruby/library/ipaddr/new_spec.rb10
-rw-r--r--spec/ruby/library/logger/device/close_spec.rb15
-rw-r--r--spec/ruby/library/logger/device/write_spec.rb15
-rw-r--r--spec/ruby/library/matrix/I_spec.rb9
-rw-r--r--spec/ruby/library/matrix/antisymmetric_spec.rb54
-rw-r--r--spec/ruby/library/matrix/build_spec.rb117
-rw-r--r--spec/ruby/library/matrix/clone_spec.rb37
-rw-r--r--spec/ruby/library/matrix/coerce_spec.rb11
-rw-r--r--spec/ruby/library/matrix/collect_spec.rb9
-rw-r--r--spec/ruby/library/matrix/column_size_spec.rb19
-rw-r--r--spec/ruby/library/matrix/column_spec.rb53
-rw-r--r--spec/ruby/library/matrix/column_vector_spec.rb37
-rw-r--r--spec/ruby/library/matrix/column_vectors_spec.rb37
-rw-r--r--spec/ruby/library/matrix/columns_spec.rb67
-rw-r--r--spec/ruby/library/matrix/conj_spec.rb9
-rw-r--r--spec/ruby/library/matrix/conjugate_spec.rb9
-rw-r--r--spec/ruby/library/matrix/constructor_spec.rb103
-rw-r--r--spec/ruby/library/matrix/det_spec.rb11
-rw-r--r--spec/ruby/library/matrix/determinant_spec.rb11
-rw-r--r--spec/ruby/library/matrix/diagonal_spec.rb105
-rw-r--r--spec/ruby/library/matrix/divide_spec.rb83
-rw-r--r--spec/ruby/library/matrix/each_spec.rb119
-rw-r--r--spec/ruby/library/matrix/each_with_index_spec.rb133
-rw-r--r--spec/ruby/library/matrix/eigenvalue_decomposition/eigenvalue_matrix_spec.rb13
-rw-r--r--spec/ruby/library/matrix/eigenvalue_decomposition/eigenvalues_spec.rb35
-rw-r--r--spec/ruby/library/matrix/eigenvalue_decomposition/eigenvector_matrix_spec.rb33
-rw-r--r--spec/ruby/library/matrix/eigenvalue_decomposition/eigenvectors_spec.rb37
-rw-r--r--spec/ruby/library/matrix/eigenvalue_decomposition/initialize_spec.rb39
-rw-r--r--spec/ruby/library/matrix/eigenvalue_decomposition/to_a_spec.rb27
-rw-r--r--spec/ruby/library/matrix/element_reference_spec.rb31
-rw-r--r--spec/ruby/library/matrix/empty_spec.rb107
-rw-r--r--spec/ruby/library/matrix/eql_spec.rb15
-rw-r--r--spec/ruby/library/matrix/equal_value_spec.rb15
-rw-r--r--spec/ruby/library/matrix/exponent_spec.rb93
-rw-r--r--spec/ruby/library/matrix/find_index_spec.rb221
-rw-r--r--spec/ruby/library/matrix/hash_spec.rb21
-rw-r--r--spec/ruby/library/matrix/hermitian_spec.rb53
-rw-r--r--spec/ruby/library/matrix/identity_spec.rb9
-rw-r--r--spec/ruby/library/matrix/imag_spec.rb9
-rw-r--r--spec/ruby/library/matrix/imaginary_spec.rb9
-rw-r--r--spec/ruby/library/matrix/inspect_spec.rb39
-rw-r--r--spec/ruby/library/matrix/inv_spec.rb11
-rw-r--r--spec/ruby/library/matrix/inverse_from_spec.rb9
-rw-r--r--spec/ruby/library/matrix/inverse_spec.rb11
-rw-r--r--spec/ruby/library/matrix/lower_triangular_spec.rb39
-rw-r--r--spec/ruby/library/matrix/lup_decomposition/determinant_spec.rb33
-rw-r--r--spec/ruby/library/matrix/lup_decomposition/initialize_spec.rb21
-rw-r--r--spec/ruby/library/matrix/lup_decomposition/l_spec.rb27
-rw-r--r--spec/ruby/library/matrix/lup_decomposition/p_spec.rb27
-rw-r--r--spec/ruby/library/matrix/lup_decomposition/solve_spec.rb85
-rw-r--r--spec/ruby/library/matrix/lup_decomposition/to_a_spec.rb53
-rw-r--r--spec/ruby/library/matrix/lup_decomposition/u_spec.rb27
-rw-r--r--spec/ruby/library/matrix/map_spec.rb9
-rw-r--r--spec/ruby/library/matrix/minor_spec.rb135
-rw-r--r--spec/ruby/library/matrix/minus_spec.rb65
-rw-r--r--spec/ruby/library/matrix/multiply_spec.rb104
-rw-r--r--spec/ruby/library/matrix/new_spec.rb11
-rw-r--r--spec/ruby/library/matrix/normal_spec.rb41
-rw-r--r--spec/ruby/library/matrix/orthogonal_spec.rb41
-rw-r--r--spec/ruby/library/matrix/permutation_spec.rb51
-rw-r--r--spec/ruby/library/matrix/plus_spec.rb65
-rw-r--r--spec/ruby/library/matrix/rank_spec.rb29
-rw-r--r--spec/ruby/library/matrix/real_spec.rb63
-rw-r--r--spec/ruby/library/matrix/rect_spec.rb9
-rw-r--r--spec/ruby/library/matrix/rectangular_spec.rb9
-rw-r--r--spec/ruby/library/matrix/regular_spec.rb45
-rw-r--r--spec/ruby/library/matrix/round_spec.rb31
-rw-r--r--spec/ruby/library/matrix/row_size_spec.rb19
-rw-r--r--spec/ruby/library/matrix/row_spec.rb55
-rw-r--r--spec/ruby/library/matrix/row_vector_spec.rb33
-rw-r--r--spec/ruby/library/matrix/row_vectors_spec.rb37
-rw-r--r--spec/ruby/library/matrix/rows_spec.rb65
-rw-r--r--spec/ruby/library/matrix/scalar/Fail_spec.rb9
-rw-r--r--spec/ruby/library/matrix/scalar/Raise_spec.rb9
-rw-r--r--spec/ruby/library/matrix/scalar/divide_spec.rb9
-rw-r--r--spec/ruby/library/matrix/scalar/exponent_spec.rb9
-rw-r--r--spec/ruby/library/matrix/scalar/included_spec.rb9
-rw-r--r--spec/ruby/library/matrix/scalar/initialize_spec.rb9
-rw-r--r--spec/ruby/library/matrix/scalar/minus_spec.rb9
-rw-r--r--spec/ruby/library/matrix/scalar/multiply_spec.rb9
-rw-r--r--spec/ruby/library/matrix/scalar/plus_spec.rb9
-rw-r--r--spec/ruby/library/matrix/scalar_spec.rb93
-rw-r--r--spec/ruby/library/matrix/singular_spec.rb47
-rw-r--r--spec/ruby/library/matrix/square_spec.rb41
-rw-r--r--spec/ruby/library/matrix/symmetric_spec.rb45
-rw-r--r--spec/ruby/library/matrix/t_spec.rb9
-rw-r--r--spec/ruby/library/matrix/to_a_spec.rb17
-rw-r--r--spec/ruby/library/matrix/to_s_spec.rb9
-rw-r--r--spec/ruby/library/matrix/tr_spec.rb11
-rw-r--r--spec/ruby/library/matrix/trace_spec.rb11
-rw-r--r--spec/ruby/library/matrix/transpose_spec.rb9
-rw-r--r--spec/ruby/library/matrix/unit_spec.rb9
-rw-r--r--spec/ruby/library/matrix/unitary_spec.rb50
-rw-r--r--spec/ruby/library/matrix/upper_triangular_spec.rb39
-rw-r--r--spec/ruby/library/matrix/vector/cross_product_spec.rb21
-rw-r--r--spec/ruby/library/matrix/vector/each2_spec.rb81
-rw-r--r--spec/ruby/library/matrix/vector/eql_spec.rb23
-rw-r--r--spec/ruby/library/matrix/vector/inner_product_spec.rb33
-rw-r--r--spec/ruby/library/matrix/vector/normalize_spec.rb29
-rw-r--r--spec/ruby/library/matrix/zero_spec.rb75
-rw-r--r--spec/ruby/library/monitor/exit_spec.rb10
-rw-r--r--spec/ruby/library/net-ftp/FTPError_spec.rb8
-rw-r--r--spec/ruby/library/net-ftp/FTPPermError_spec.rb12
-rw-r--r--spec/ruby/library/net-ftp/FTPProtoError_spec.rb12
-rw-r--r--spec/ruby/library/net-ftp/FTPReplyError_spec.rb12
-rw-r--r--spec/ruby/library/net-ftp/FTPTempError_spec.rb12
-rw-r--r--spec/ruby/library/net-ftp/abort_spec.rb62
-rw-r--r--spec/ruby/library/net-ftp/acct_spec.rb58
-rw-r--r--spec/ruby/library/net-ftp/binary_spec.rb24
-rw-r--r--spec/ruby/library/net-ftp/chdir_spec.rb99
-rw-r--r--spec/ruby/library/net-ftp/close_spec.rb30
-rw-r--r--spec/ruby/library/net-ftp/closed_spec.rb21
-rw-r--r--spec/ruby/library/net-ftp/connect_spec.rb51
-rw-r--r--spec/ruby/library/net-ftp/debug_mode_spec.rb23
-rw-r--r--spec/ruby/library/net-ftp/default_passive_spec.rb8
-rw-r--r--spec/ruby/library/net-ftp/delete_spec.rb59
-rw-r--r--spec/ruby/library/net-ftp/dir_spec.rb8
-rw-r--r--spec/ruby/library/net-ftp/fixtures/default_passive.rb (renamed from spec/ruby/library/net/ftp/fixtures/default_passive.rb)0
-rw-r--r--spec/ruby/library/net-ftp/fixtures/passive.rb (renamed from spec/ruby/library/net/ftp/fixtures/passive.rb)0
-rw-r--r--spec/ruby/library/net-ftp/fixtures/putbinaryfile (renamed from spec/ruby/library/net/ftp/fixtures/putbinaryfile)0
-rw-r--r--spec/ruby/library/net-ftp/fixtures/puttextfile (renamed from spec/ruby/library/net/ftp/fixtures/puttextfile)0
-rw-r--r--spec/ruby/library/net-ftp/fixtures/server.rb (renamed from spec/ruby/library/net/ftp/fixtures/server.rb)0
-rw-r--r--spec/ruby/library/net-ftp/get_spec.rb21
-rw-r--r--spec/ruby/library/net-ftp/getbinaryfile_spec.rb8
-rw-r--r--spec/ruby/library/net-ftp/getdir_spec.rb7
-rw-r--r--spec/ruby/library/net-ftp/gettextfile_spec.rb8
-rw-r--r--spec/ruby/library/net-ftp/help_spec.rb66
-rw-r--r--spec/ruby/library/net-ftp/initialize_spec.rb405
-rw-r--r--spec/ruby/library/net-ftp/last_response_code_spec.rb8
-rw-r--r--spec/ruby/library/net-ftp/last_response_spec.rb25
-rw-r--r--spec/ruby/library/net-ftp/lastresp_spec.rb8
-rw-r--r--spec/ruby/library/net-ftp/list_spec.rb8
-rw-r--r--spec/ruby/library/net-ftp/login_spec.rb195
-rw-r--r--spec/ruby/library/net-ftp/ls_spec.rb8
-rw-r--r--spec/ruby/library/net-ftp/mdtm_spec.rb38
-rw-r--r--spec/ruby/library/net-ftp/mkdir_spec.rb61
-rw-r--r--spec/ruby/library/net-ftp/mtime_spec.rb50
-rw-r--r--spec/ruby/library/net-ftp/nlst_spec.rb92
-rw-r--r--spec/ruby/library/net-ftp/noop_spec.rb38
-rw-r--r--spec/ruby/library/net-ftp/open_spec.rb55
-rw-r--r--spec/ruby/library/net-ftp/passive_spec.rb28
-rw-r--r--spec/ruby/library/net-ftp/put_spec.rb21
-rw-r--r--spec/ruby/library/net-ftp/putbinaryfile_spec.rb8
-rw-r--r--spec/ruby/library/net-ftp/puttextfile_spec.rb8
-rw-r--r--spec/ruby/library/net-ftp/pwd_spec.rb53
-rw-r--r--spec/ruby/library/net-ftp/quit_spec.rb33
-rw-r--r--spec/ruby/library/net-ftp/rename_spec.rb94
-rw-r--r--spec/ruby/library/net-ftp/resume_spec.rb23
-rw-r--r--spec/ruby/library/net-ftp/retrbinary_spec.rb30
-rw-r--r--spec/ruby/library/net-ftp/retrlines_spec.rb34
-rw-r--r--spec/ruby/library/net-ftp/return_code_spec.rb24
-rw-r--r--spec/ruby/library/net-ftp/rmdir_spec.rb58
-rw-r--r--spec/ruby/library/net-ftp/sendcmd_spec.rb54
-rw-r--r--spec/ruby/library/net-ftp/set_socket_spec.rb8
-rw-r--r--spec/ruby/library/net-ftp/shared/getbinaryfile.rb150
-rw-r--r--spec/ruby/library/net-ftp/shared/gettextfile.rb100
-rw-r--r--spec/ruby/library/net-ftp/shared/last_response_code.rb (renamed from spec/ruby/library/net/ftp/shared/last_response_code.rb)0
-rw-r--r--spec/ruby/library/net-ftp/shared/list.rb (renamed from spec/ruby/library/net/ftp/shared/list.rb)0
-rw-r--r--spec/ruby/library/net-ftp/shared/putbinaryfile.rb167
-rw-r--r--spec/ruby/library/net-ftp/shared/puttextfile.rb120
-rw-r--r--spec/ruby/library/net-ftp/shared/pwd.rb (renamed from spec/ruby/library/net/ftp/shared/pwd.rb)0
-rw-r--r--spec/ruby/library/net-ftp/site_spec.rb53
-rw-r--r--spec/ruby/library/net-ftp/size_spec.rb48
-rw-r--r--spec/ruby/library/net-ftp/spec_helper.rb (renamed from spec/ruby/library/net/ftp/spec_helper.rb)0
-rw-r--r--spec/ruby/library/net-ftp/status_spec.rb67
-rw-r--r--spec/ruby/library/net-ftp/storbinary_spec.rb49
-rw-r--r--spec/ruby/library/net-ftp/storlines_spec.rb44
-rw-r--r--spec/ruby/library/net-ftp/system_spec.rb48
-rw-r--r--spec/ruby/library/net-ftp/voidcmd_spec.rb54
-rw-r--r--spec/ruby/library/net-ftp/welcome_spec.rb25
-rw-r--r--spec/ruby/library/net-http/HTTPBadResponse_spec.rb8
-rw-r--r--spec/ruby/library/net-http/HTTPClientExcepton_spec.rb12
-rw-r--r--spec/ruby/library/net-http/HTTPError_spec.rb12
-rw-r--r--spec/ruby/library/net-http/HTTPFatalError_spec.rb12
-rw-r--r--spec/ruby/library/net-http/HTTPHeaderSyntaxError_spec.rb8
-rw-r--r--spec/ruby/library/net-http/HTTPRetriableError_spec.rb12
-rw-r--r--spec/ruby/library/net-http/HTTPServerException_spec.rb12
-rw-r--r--spec/ruby/library/net-http/http/Proxy_spec.rb35
-rw-r--r--spec/ruby/library/net-http/http/active_spec.rb8
-rw-r--r--spec/ruby/library/net-http/http/address_spec.rb9
-rw-r--r--spec/ruby/library/net-http/http/close_on_empty_response_spec.rb10
-rw-r--r--spec/ruby/library/net-http/http/copy_spec.rb21
-rw-r--r--spec/ruby/library/net-http/http/default_port_spec.rb8
-rw-r--r--spec/ruby/library/net-http/http/delete_spec.rb21
-rw-r--r--spec/ruby/library/net-http/http/finish_spec.rb29
-rw-r--r--spec/ruby/library/net-http/http/fixtures/http_server.rb (renamed from spec/ruby/library/net/http/http/fixtures/http_server.rb)0
-rw-r--r--spec/ruby/library/net-http/http/get2_spec.rb8
-rw-r--r--spec/ruby/library/net-http/http/get_print_spec.rb30
-rw-r--r--spec/ruby/library/net-http/http/get_response_spec.rb30
-rw-r--r--spec/ruby/library/net-http/http/get_spec.rb94
-rw-r--r--spec/ruby/library/net-http/http/head2_spec.rb8
-rw-r--r--spec/ruby/library/net-http/http/head_spec.rb25
-rw-r--r--spec/ruby/library/net-http/http/http_default_port_spec.rb8
-rw-r--r--spec/ruby/library/net-http/http/https_default_port_spec.rb8
-rw-r--r--spec/ruby/library/net-http/http/initialize_spec.rb46
-rw-r--r--spec/ruby/library/net-http/http/inspect_spec.rb24
-rw-r--r--spec/ruby/library/net-http/http/is_version_1_1_spec.rb7
-rw-r--r--spec/ruby/library/net-http/http/is_version_1_2_spec.rb7
-rw-r--r--spec/ruby/library/net-http/http/lock_spec.rb21
-rw-r--r--spec/ruby/library/net-http/http/mkcol_spec.rb21
-rw-r--r--spec/ruby/library/net-http/http/move_spec.rb25
-rw-r--r--spec/ruby/library/net-http/http/new_spec.rb86
-rw-r--r--spec/ruby/library/net-http/http/newobj_spec.rb48
-rw-r--r--spec/ruby/library/net-http/http/open_timeout_spec.rb24
-rw-r--r--spec/ruby/library/net-http/http/options_spec.rb25
-rw-r--r--spec/ruby/library/net-http/http/port_spec.rb9
-rw-r--r--spec/ruby/library/net-http/http/post2_spec.rb8
-rw-r--r--spec/ruby/library/net-http/http/post_form_spec.rb22
-rw-r--r--spec/ruby/library/net-http/http/post_spec.rb74
-rw-r--r--spec/ruby/library/net-http/http/propfind_spec.rb24
-rw-r--r--spec/ruby/library/net-http/http/proppatch_spec.rb24
-rw-r--r--spec/ruby/library/net-http/http/proxy_address_spec.rb31
-rw-r--r--spec/ruby/library/net-http/http/proxy_class_spec.rb9
-rw-r--r--spec/ruby/library/net-http/http/proxy_pass_spec.rb39
-rw-r--r--spec/ruby/library/net-http/http/proxy_port_spec.rb39
-rw-r--r--spec/ruby/library/net-http/http/proxy_user_spec.rb39
-rw-r--r--spec/ruby/library/net-http/http/put2_spec.rb8
-rw-r--r--spec/ruby/library/net-http/http/put_spec.rb24
-rw-r--r--spec/ruby/library/net-http/http/read_timeout_spec.rb24
-rw-r--r--spec/ruby/library/net-http/http/request_get_spec.rb8
-rw-r--r--spec/ruby/library/net-http/http/request_head_spec.rb8
-rw-r--r--spec/ruby/library/net-http/http/request_post_spec.rb8
-rw-r--r--spec/ruby/library/net-http/http/request_put_spec.rb8
-rw-r--r--spec/ruby/library/net-http/http/request_spec.rb109
-rw-r--r--spec/ruby/library/net-http/http/request_types_spec.rb254
-rw-r--r--spec/ruby/library/net-http/http/send_request_spec.rb61
-rw-r--r--spec/ruby/library/net-http/http/set_debug_output_spec.rb33
-rw-r--r--spec/ruby/library/net-http/http/shared/request_get.rb (renamed from spec/ruby/library/net/http/http/shared/request_get.rb)0
-rw-r--r--spec/ruby/library/net-http/http/shared/request_head.rb (renamed from spec/ruby/library/net/http/http/shared/request_head.rb)0
-rw-r--r--spec/ruby/library/net-http/http/shared/request_post.rb (renamed from spec/ruby/library/net/http/http/shared/request_post.rb)0
-rw-r--r--spec/ruby/library/net-http/http/shared/request_put.rb (renamed from spec/ruby/library/net/http/http/shared/request_put.rb)0
-rw-r--r--spec/ruby/library/net-http/http/shared/started.rb (renamed from spec/ruby/library/net/http/http/shared/started.rb)0
-rw-r--r--spec/ruby/library/net-http/http/shared/version_1_1.rb (renamed from spec/ruby/library/net/http/http/shared/version_1_1.rb)0
-rw-r--r--spec/ruby/library/net-http/http/shared/version_1_2.rb (renamed from spec/ruby/library/net/http/http/shared/version_1_2.rb)0
-rw-r--r--spec/ruby/library/net-http/http/socket_type_spec.rb8
-rw-r--r--spec/ruby/library/net-http/http/start_spec.rb111
-rw-r--r--spec/ruby/library/net-http/http/started_spec.rb8
-rw-r--r--spec/ruby/library/net-http/http/trace_spec.rb24
-rw-r--r--spec/ruby/library/net-http/http/unlock_spec.rb24
-rw-r--r--spec/ruby/library/net-http/http/use_ssl_spec.rb9
-rw-r--r--spec/ruby/library/net-http/http/version_1_1_spec.rb7
-rw-r--r--spec/ruby/library/net-http/http/version_1_2_spec.rb20
-rw-r--r--spec/ruby/library/net-http/httpexceptions/fixtures/classes.rb (renamed from spec/ruby/library/net/http/httpexceptions/fixtures/classes.rb)0
-rw-r--r--spec/ruby/library/net-http/httpexceptions/initialize_spec.rb17
-rw-r--r--spec/ruby/library/net-http/httpexceptions/response_spec.rb10
-rw-r--r--spec/ruby/library/net-http/httpgenericrequest/body_exist_spec.rb21
-rw-r--r--spec/ruby/library/net-http/httpgenericrequest/body_spec.rb30
-rw-r--r--spec/ruby/library/net-http/httpgenericrequest/body_stream_spec.rb32
-rw-r--r--spec/ruby/library/net-http/httpgenericrequest/exec_spec.rb131
-rw-r--r--spec/ruby/library/net-http/httpgenericrequest/inspect_spec.rb25
-rw-r--r--spec/ruby/library/net-http/httpgenericrequest/method_spec.rb15
-rw-r--r--spec/ruby/library/net-http/httpgenericrequest/path_spec.rb12
-rw-r--r--spec/ruby/library/net-http/httpgenericrequest/request_body_permitted_spec.rb12
-rw-r--r--spec/ruby/library/net-http/httpgenericrequest/response_body_permitted_spec.rb12
-rw-r--r--spec/ruby/library/net-http/httpgenericrequest/set_body_internal_spec.rb21
-rw-r--r--spec/ruby/library/net-http/httpheader/add_field_spec.rb31
-rw-r--r--spec/ruby/library/net-http/httpheader/basic_auth_spec.rb14
-rw-r--r--spec/ruby/library/net-http/httpheader/canonical_each_spec.rb8
-rw-r--r--spec/ruby/library/net-http/httpheader/chunked_spec.rb22
-rw-r--r--spec/ruby/library/net-http/httpheader/content_length_spec.rb54
-rw-r--r--spec/ruby/library/net-http/httpheader/content_range_spec.rb32
-rw-r--r--spec/ruby/library/net-http/httpheader/content_type_spec.rb26
-rw-r--r--spec/ruby/library/net-http/httpheader/delete_spec.rb30
-rw-r--r--spec/ruby/library/net-http/httpheader/each_capitalized_name_spec.rb35
-rw-r--r--spec/ruby/library/net-http/httpheader/each_capitalized_spec.rb8
-rw-r--r--spec/ruby/library/net-http/httpheader/each_header_spec.rb8
-rw-r--r--spec/ruby/library/net-http/httpheader/each_key_spec.rb8
-rw-r--r--spec/ruby/library/net-http/httpheader/each_name_spec.rb8
-rw-r--r--spec/ruby/library/net-http/httpheader/each_spec.rb8
-rw-r--r--spec/ruby/library/net-http/httpheader/each_value_spec.rb35
-rw-r--r--spec/ruby/library/net-http/httpheader/element_reference_spec.rb39
-rw-r--r--spec/ruby/library/net-http/httpheader/element_set_spec.rb41
-rw-r--r--spec/ruby/library/net-http/httpheader/fetch_spec.rb68
-rw-r--r--spec/ruby/library/net-http/httpheader/fixtures/classes.rb (renamed from spec/ruby/library/net/http/httpheader/fixtures/classes.rb)0
-rw-r--r--spec/ruby/library/net-http/httpheader/form_data_spec.rb8
-rw-r--r--spec/ruby/library/net-http/httpheader/get_fields_spec.rb39
-rw-r--r--spec/ruby/library/net-http/httpheader/initialize_http_header_spec.rb21
-rw-r--r--spec/ruby/library/net-http/httpheader/key_spec.rb21
-rw-r--r--spec/ruby/library/net-http/httpheader/length_spec.rb8
-rw-r--r--spec/ruby/library/net-http/httpheader/main_type_spec.rb24
-rw-r--r--spec/ruby/library/net-http/httpheader/proxy_basic_auth_spec.rb14
-rw-r--r--spec/ruby/library/net-http/httpheader/range_length_spec.rb32
-rw-r--r--spec/ruby/library/net-http/httpheader/range_spec.rb48
-rw-r--r--spec/ruby/library/net-http/httpheader/set_content_type_spec.rb8
-rw-r--r--spec/ruby/library/net-http/httpheader/set_form_data_spec.rb8
-rw-r--r--spec/ruby/library/net-http/httpheader/set_range_spec.rb8
-rw-r--r--spec/ruby/library/net-http/httpheader/shared/each_capitalized.rb (renamed from spec/ruby/library/net/http/httpheader/shared/each_capitalized.rb)0
-rw-r--r--spec/ruby/library/net-http/httpheader/shared/each_header.rb (renamed from spec/ruby/library/net/http/httpheader/shared/each_header.rb)0
-rw-r--r--spec/ruby/library/net-http/httpheader/shared/each_name.rb (renamed from spec/ruby/library/net/http/httpheader/shared/each_name.rb)0
-rw-r--r--spec/ruby/library/net-http/httpheader/shared/set_content_type.rb (renamed from spec/ruby/library/net/http/httpheader/shared/set_content_type.rb)0
-rw-r--r--spec/ruby/library/net-http/httpheader/shared/set_form_data.rb (renamed from spec/ruby/library/net/http/httpheader/shared/set_form_data.rb)0
-rw-r--r--spec/ruby/library/net-http/httpheader/shared/set_range.rb (renamed from spec/ruby/library/net/http/httpheader/shared/set_range.rb)0
-rw-r--r--spec/ruby/library/net-http/httpheader/shared/size.rb (renamed from spec/ruby/library/net/http/httpheader/shared/size.rb)0
-rw-r--r--spec/ruby/library/net-http/httpheader/size_spec.rb8
-rw-r--r--spec/ruby/library/net-http/httpheader/sub_type_spec.rb32
-rw-r--r--spec/ruby/library/net-http/httpheader/to_hash_spec.rb25
-rw-r--r--spec/ruby/library/net-http/httpheader/type_params_spec.rb24
-rw-r--r--spec/ruby/library/net-http/httprequest/initialize_spec.rb45
-rw-r--r--spec/ruby/library/net-http/httpresponse/body_permitted_spec.rb13
-rw-r--r--spec/ruby/library/net-http/httpresponse/body_spec.rb7
-rw-r--r--spec/ruby/library/net-http/httpresponse/code_spec.rb24
-rw-r--r--spec/ruby/library/net-http/httpresponse/code_type_spec.rb24
-rw-r--r--spec/ruby/library/net-http/httpresponse/entity_spec.rb7
-rw-r--r--spec/ruby/library/net-http/httpresponse/error_spec.rb24
-rw-r--r--spec/ruby/library/net-http/httpresponse/error_type_spec.rb24
-rw-r--r--spec/ruby/library/net-http/httpresponse/exception_type_spec.rb13
-rw-r--r--spec/ruby/library/net-http/httpresponse/header_spec.rb9
-rw-r--r--spec/ruby/library/net-http/httpresponse/http_version_spec.rb12
-rw-r--r--spec/ruby/library/net-http/httpresponse/initialize_spec.rb11
-rw-r--r--spec/ruby/library/net-http/httpresponse/inspect_spec.rb15
-rw-r--r--spec/ruby/library/net-http/httpresponse/message_spec.rb9
-rw-r--r--spec/ruby/library/net-http/httpresponse/msg_spec.rb9
-rw-r--r--spec/ruby/library/net-http/httpresponse/read_body_spec.rb86
-rw-r--r--spec/ruby/library/net-http/httpresponse/read_header_spec.rb9
-rw-r--r--spec/ruby/library/net-http/httpresponse/read_new_spec.rb23
-rw-r--r--spec/ruby/library/net-http/httpresponse/reading_body_spec.rb58
-rw-r--r--spec/ruby/library/net-http/httpresponse/response_spec.rb9
-rw-r--r--spec/ruby/library/net-http/httpresponse/shared/body.rb (renamed from spec/ruby/library/net/http/httpresponse/shared/body.rb)0
-rw-r--r--spec/ruby/library/net-http/httpresponse/value_spec.rb24
-rw-r--r--spec/ruby/library/net/FTPError_spec.rb11
-rw-r--r--spec/ruby/library/net/FTPPermError_spec.rb15
-rw-r--r--spec/ruby/library/net/FTPProtoError_spec.rb15
-rw-r--r--spec/ruby/library/net/FTPReplyError_spec.rb15
-rw-r--r--spec/ruby/library/net/FTPTempError_spec.rb15
-rw-r--r--spec/ruby/library/net/ftp/abort_spec.rb65
-rw-r--r--spec/ruby/library/net/ftp/acct_spec.rb61
-rw-r--r--spec/ruby/library/net/ftp/binary_spec.rb27
-rw-r--r--spec/ruby/library/net/ftp/chdir_spec.rb102
-rw-r--r--spec/ruby/library/net/ftp/close_spec.rb33
-rw-r--r--spec/ruby/library/net/ftp/closed_spec.rb24
-rw-r--r--spec/ruby/library/net/ftp/connect_spec.rb52
-rw-r--r--spec/ruby/library/net/ftp/debug_mode_spec.rb26
-rw-r--r--spec/ruby/library/net/ftp/default_passive_spec.rb11
-rw-r--r--spec/ruby/library/net/ftp/delete_spec.rb62
-rw-r--r--spec/ruby/library/net/ftp/dir_spec.rb11
-rw-r--r--spec/ruby/library/net/ftp/get_spec.rb24
-rw-r--r--spec/ruby/library/net/ftp/getbinaryfile_spec.rb11
-rw-r--r--spec/ruby/library/net/ftp/getdir_spec.rb10
-rw-r--r--spec/ruby/library/net/ftp/gettextfile_spec.rb11
-rw-r--r--spec/ruby/library/net/ftp/help_spec.rb69
-rw-r--r--spec/ruby/library/net/ftp/initialize_spec.rb408
-rw-r--r--spec/ruby/library/net/ftp/last_response_code_spec.rb11
-rw-r--r--spec/ruby/library/net/ftp/last_response_spec.rb28
-rw-r--r--spec/ruby/library/net/ftp/lastresp_spec.rb11
-rw-r--r--spec/ruby/library/net/ftp/list_spec.rb11
-rw-r--r--spec/ruby/library/net/ftp/login_spec.rb198
-rw-r--r--spec/ruby/library/net/ftp/ls_spec.rb11
-rw-r--r--spec/ruby/library/net/ftp/mdtm_spec.rb41
-rw-r--r--spec/ruby/library/net/ftp/mkdir_spec.rb64
-rw-r--r--spec/ruby/library/net/ftp/mtime_spec.rb53
-rw-r--r--spec/ruby/library/net/ftp/nlst_spec.rb95
-rw-r--r--spec/ruby/library/net/ftp/noop_spec.rb41
-rw-r--r--spec/ruby/library/net/ftp/open_spec.rb58
-rw-r--r--spec/ruby/library/net/ftp/passive_spec.rb31
-rw-r--r--spec/ruby/library/net/ftp/put_spec.rb24
-rw-r--r--spec/ruby/library/net/ftp/putbinaryfile_spec.rb11
-rw-r--r--spec/ruby/library/net/ftp/puttextfile_spec.rb11
-rw-r--r--spec/ruby/library/net/ftp/pwd_spec.rb56
-rw-r--r--spec/ruby/library/net/ftp/quit_spec.rb36
-rw-r--r--spec/ruby/library/net/ftp/rename_spec.rb97
-rw-r--r--spec/ruby/library/net/ftp/resume_spec.rb26
-rw-r--r--spec/ruby/library/net/ftp/retrbinary_spec.rb33
-rw-r--r--spec/ruby/library/net/ftp/retrlines_spec.rb37
-rw-r--r--spec/ruby/library/net/ftp/return_code_spec.rb27
-rw-r--r--spec/ruby/library/net/ftp/rmdir_spec.rb61
-rw-r--r--spec/ruby/library/net/ftp/sendcmd_spec.rb57
-rw-r--r--spec/ruby/library/net/ftp/set_socket_spec.rb11
-rw-r--r--spec/ruby/library/net/ftp/shared/getbinaryfile.rb150
-rw-r--r--spec/ruby/library/net/ftp/shared/gettextfile.rb100
-rw-r--r--spec/ruby/library/net/ftp/shared/putbinaryfile.rb167
-rw-r--r--spec/ruby/library/net/ftp/shared/puttextfile.rb120
-rw-r--r--spec/ruby/library/net/ftp/site_spec.rb56
-rw-r--r--spec/ruby/library/net/ftp/size_spec.rb51
-rw-r--r--spec/ruby/library/net/ftp/status_spec.rb70
-rw-r--r--spec/ruby/library/net/ftp/storbinary_spec.rb51
-rw-r--r--spec/ruby/library/net/ftp/storlines_spec.rb46
-rw-r--r--spec/ruby/library/net/ftp/system_spec.rb51
-rw-r--r--spec/ruby/library/net/ftp/voidcmd_spec.rb57
-rw-r--r--spec/ruby/library/net/ftp/welcome_spec.rb28
-rw-r--r--spec/ruby/library/net/http/HTTPBadResponse_spec.rb8
-rw-r--r--spec/ruby/library/net/http/HTTPClientExcepton_spec.rb12
-rw-r--r--spec/ruby/library/net/http/HTTPError_spec.rb12
-rw-r--r--spec/ruby/library/net/http/HTTPFatalError_spec.rb12
-rw-r--r--spec/ruby/library/net/http/HTTPHeaderSyntaxError_spec.rb8
-rw-r--r--spec/ruby/library/net/http/HTTPRetriableError_spec.rb12
-rw-r--r--spec/ruby/library/net/http/HTTPServerException_spec.rb12
-rw-r--r--spec/ruby/library/net/http/http/Proxy_spec.rb35
-rw-r--r--spec/ruby/library/net/http/http/active_spec.rb8
-rw-r--r--spec/ruby/library/net/http/http/address_spec.rb9
-rw-r--r--spec/ruby/library/net/http/http/close_on_empty_response_spec.rb10
-rw-r--r--spec/ruby/library/net/http/http/copy_spec.rb21
-rw-r--r--spec/ruby/library/net/http/http/default_port_spec.rb8
-rw-r--r--spec/ruby/library/net/http/http/delete_spec.rb21
-rw-r--r--spec/ruby/library/net/http/http/finish_spec.rb29
-rw-r--r--spec/ruby/library/net/http/http/get2_spec.rb8
-rw-r--r--spec/ruby/library/net/http/http/get_print_spec.rb30
-rw-r--r--spec/ruby/library/net/http/http/get_response_spec.rb30
-rw-r--r--spec/ruby/library/net/http/http/get_spec.rb96
-rw-r--r--spec/ruby/library/net/http/http/head2_spec.rb8
-rw-r--r--spec/ruby/library/net/http/http/head_spec.rb25
-rw-r--r--spec/ruby/library/net/http/http/http_default_port_spec.rb8
-rw-r--r--spec/ruby/library/net/http/http/https_default_port_spec.rb8
-rw-r--r--spec/ruby/library/net/http/http/initialize_spec.rb46
-rw-r--r--spec/ruby/library/net/http/http/inspect_spec.rb24
-rw-r--r--spec/ruby/library/net/http/http/is_version_1_1_spec.rb7
-rw-r--r--spec/ruby/library/net/http/http/is_version_1_2_spec.rb7
-rw-r--r--spec/ruby/library/net/http/http/lock_spec.rb21
-rw-r--r--spec/ruby/library/net/http/http/mkcol_spec.rb21
-rw-r--r--spec/ruby/library/net/http/http/move_spec.rb25
-rw-r--r--spec/ruby/library/net/http/http/new_spec.rb86
-rw-r--r--spec/ruby/library/net/http/http/newobj_spec.rb48
-rw-r--r--spec/ruby/library/net/http/http/open_timeout_spec.rb24
-rw-r--r--spec/ruby/library/net/http/http/options_spec.rb25
-rw-r--r--spec/ruby/library/net/http/http/port_spec.rb9
-rw-r--r--spec/ruby/library/net/http/http/post2_spec.rb8
-rw-r--r--spec/ruby/library/net/http/http/post_form_spec.rb22
-rw-r--r--spec/ruby/library/net/http/http/post_spec.rb74
-rw-r--r--spec/ruby/library/net/http/http/propfind_spec.rb24
-rw-r--r--spec/ruby/library/net/http/http/proppatch_spec.rb24
-rw-r--r--spec/ruby/library/net/http/http/proxy_address_spec.rb31
-rw-r--r--spec/ruby/library/net/http/http/proxy_class_spec.rb9
-rw-r--r--spec/ruby/library/net/http/http/proxy_pass_spec.rb39
-rw-r--r--spec/ruby/library/net/http/http/proxy_port_spec.rb39
-rw-r--r--spec/ruby/library/net/http/http/proxy_user_spec.rb39
-rw-r--r--spec/ruby/library/net/http/http/put2_spec.rb8
-rw-r--r--spec/ruby/library/net/http/http/put_spec.rb24
-rw-r--r--spec/ruby/library/net/http/http/read_timeout_spec.rb24
-rw-r--r--spec/ruby/library/net/http/http/request_get_spec.rb8
-rw-r--r--spec/ruby/library/net/http/http/request_head_spec.rb8
-rw-r--r--spec/ruby/library/net/http/http/request_post_spec.rb8
-rw-r--r--spec/ruby/library/net/http/http/request_put_spec.rb8
-rw-r--r--spec/ruby/library/net/http/http/request_spec.rb109
-rw-r--r--spec/ruby/library/net/http/http/request_types_spec.rb254
-rw-r--r--spec/ruby/library/net/http/http/send_request_spec.rb61
-rw-r--r--spec/ruby/library/net/http/http/set_debug_output_spec.rb33
-rw-r--r--spec/ruby/library/net/http/http/socket_type_spec.rb8
-rw-r--r--spec/ruby/library/net/http/http/start_spec.rb111
-rw-r--r--spec/ruby/library/net/http/http/started_spec.rb8
-rw-r--r--spec/ruby/library/net/http/http/trace_spec.rb24
-rw-r--r--spec/ruby/library/net/http/http/unlock_spec.rb24
-rw-r--r--spec/ruby/library/net/http/http/use_ssl_spec.rb9
-rw-r--r--spec/ruby/library/net/http/http/version_1_1_spec.rb7
-rw-r--r--spec/ruby/library/net/http/http/version_1_2_spec.rb20
-rw-r--r--spec/ruby/library/net/http/httpexceptions/initialize_spec.rb17
-rw-r--r--spec/ruby/library/net/http/httpexceptions/response_spec.rb10
-rw-r--r--spec/ruby/library/net/http/httpgenericrequest/body_exist_spec.rb21
-rw-r--r--spec/ruby/library/net/http/httpgenericrequest/body_spec.rb30
-rw-r--r--spec/ruby/library/net/http/httpgenericrequest/body_stream_spec.rb32
-rw-r--r--spec/ruby/library/net/http/httpgenericrequest/exec_spec.rb131
-rw-r--r--spec/ruby/library/net/http/httpgenericrequest/inspect_spec.rb25
-rw-r--r--spec/ruby/library/net/http/httpgenericrequest/method_spec.rb15
-rw-r--r--spec/ruby/library/net/http/httpgenericrequest/path_spec.rb12
-rw-r--r--spec/ruby/library/net/http/httpgenericrequest/request_body_permitted_spec.rb12
-rw-r--r--spec/ruby/library/net/http/httpgenericrequest/response_body_permitted_spec.rb12
-rw-r--r--spec/ruby/library/net/http/httpgenericrequest/set_body_internal_spec.rb21
-rw-r--r--spec/ruby/library/net/http/httpheader/add_field_spec.rb31
-rw-r--r--spec/ruby/library/net/http/httpheader/basic_auth_spec.rb14
-rw-r--r--spec/ruby/library/net/http/httpheader/canonical_each_spec.rb8
-rw-r--r--spec/ruby/library/net/http/httpheader/chunked_spec.rb22
-rw-r--r--spec/ruby/library/net/http/httpheader/content_length_spec.rb54
-rw-r--r--spec/ruby/library/net/http/httpheader/content_range_spec.rb32
-rw-r--r--spec/ruby/library/net/http/httpheader/content_type_spec.rb26
-rw-r--r--spec/ruby/library/net/http/httpheader/delete_spec.rb30
-rw-r--r--spec/ruby/library/net/http/httpheader/each_capitalized_name_spec.rb35
-rw-r--r--spec/ruby/library/net/http/httpheader/each_capitalized_spec.rb8
-rw-r--r--spec/ruby/library/net/http/httpheader/each_header_spec.rb8
-rw-r--r--spec/ruby/library/net/http/httpheader/each_key_spec.rb8
-rw-r--r--spec/ruby/library/net/http/httpheader/each_name_spec.rb8
-rw-r--r--spec/ruby/library/net/http/httpheader/each_spec.rb8
-rw-r--r--spec/ruby/library/net/http/httpheader/each_value_spec.rb35
-rw-r--r--spec/ruby/library/net/http/httpheader/element_reference_spec.rb39
-rw-r--r--spec/ruby/library/net/http/httpheader/element_set_spec.rb41
-rw-r--r--spec/ruby/library/net/http/httpheader/fetch_spec.rb68
-rw-r--r--spec/ruby/library/net/http/httpheader/form_data_spec.rb8
-rw-r--r--spec/ruby/library/net/http/httpheader/get_fields_spec.rb39
-rw-r--r--spec/ruby/library/net/http/httpheader/initialize_http_header_spec.rb21
-rw-r--r--spec/ruby/library/net/http/httpheader/key_spec.rb21
-rw-r--r--spec/ruby/library/net/http/httpheader/length_spec.rb8
-rw-r--r--spec/ruby/library/net/http/httpheader/main_type_spec.rb24
-rw-r--r--spec/ruby/library/net/http/httpheader/proxy_basic_auth_spec.rb14
-rw-r--r--spec/ruby/library/net/http/httpheader/range_length_spec.rb32
-rw-r--r--spec/ruby/library/net/http/httpheader/range_spec.rb48
-rw-r--r--spec/ruby/library/net/http/httpheader/set_content_type_spec.rb8
-rw-r--r--spec/ruby/library/net/http/httpheader/set_form_data_spec.rb8
-rw-r--r--spec/ruby/library/net/http/httpheader/set_range_spec.rb8
-rw-r--r--spec/ruby/library/net/http/httpheader/size_spec.rb8
-rw-r--r--spec/ruby/library/net/http/httpheader/sub_type_spec.rb32
-rw-r--r--spec/ruby/library/net/http/httpheader/to_hash_spec.rb25
-rw-r--r--spec/ruby/library/net/http/httpheader/type_params_spec.rb24
-rw-r--r--spec/ruby/library/net/http/httprequest/initialize_spec.rb45
-rw-r--r--spec/ruby/library/net/http/httpresponse/body_permitted_spec.rb13
-rw-r--r--spec/ruby/library/net/http/httpresponse/body_spec.rb7
-rw-r--r--spec/ruby/library/net/http/httpresponse/code_spec.rb24
-rw-r--r--spec/ruby/library/net/http/httpresponse/code_type_spec.rb24
-rw-r--r--spec/ruby/library/net/http/httpresponse/entity_spec.rb7
-rw-r--r--spec/ruby/library/net/http/httpresponse/error_spec.rb24
-rw-r--r--spec/ruby/library/net/http/httpresponse/error_type_spec.rb24
-rw-r--r--spec/ruby/library/net/http/httpresponse/exception_type_spec.rb13
-rw-r--r--spec/ruby/library/net/http/httpresponse/header_spec.rb9
-rw-r--r--spec/ruby/library/net/http/httpresponse/http_version_spec.rb12
-rw-r--r--spec/ruby/library/net/http/httpresponse/initialize_spec.rb11
-rw-r--r--spec/ruby/library/net/http/httpresponse/inspect_spec.rb15
-rw-r--r--spec/ruby/library/net/http/httpresponse/message_spec.rb9
-rw-r--r--spec/ruby/library/net/http/httpresponse/msg_spec.rb9
-rw-r--r--spec/ruby/library/net/http/httpresponse/read_body_spec.rb86
-rw-r--r--spec/ruby/library/net/http/httpresponse/read_header_spec.rb9
-rw-r--r--spec/ruby/library/net/http/httpresponse/read_new_spec.rb23
-rw-r--r--spec/ruby/library/net/http/httpresponse/reading_body_spec.rb58
-rw-r--r--spec/ruby/library/net/http/httpresponse/response_spec.rb9
-rw-r--r--spec/ruby/library/net/http/httpresponse/value_spec.rb24
-rw-r--r--spec/ruby/library/objectspace/dump_all_spec.rb112
-rw-r--r--spec/ruby/library/objectspace/dump_spec.rb70
-rw-r--r--spec/ruby/library/objectspace/fixtures/trace.rb6
-rw-r--r--spec/ruby/library/objectspace/reachable_objects_from_spec.rb2
-rw-r--r--spec/ruby/library/objectspace/trace_object_allocations_spec.rb18
-rw-r--r--spec/ruby/library/objectspace/trace_spec.rb15
-rw-r--r--spec/ruby/library/openssl/config/freeze_spec.rb22
-rw-r--r--spec/ruby/library/openssl/digest/append_spec.rb6
-rw-r--r--spec/ruby/library/openssl/digest/block_length_spec.rb44
-rw-r--r--spec/ruby/library/openssl/digest/digest_length_spec.rb44
-rw-r--r--spec/ruby/library/openssl/digest/digest_spec.rb62
-rw-r--r--spec/ruby/library/openssl/digest/initialize_spec.rb141
-rw-r--r--spec/ruby/library/openssl/digest/name_spec.rb16
-rw-r--r--spec/ruby/library/openssl/digest/reset_spec.rb36
-rw-r--r--spec/ruby/library/openssl/digest/shared/update.rb123
-rw-r--r--spec/ruby/library/openssl/digest/update_spec.rb6
-rw-r--r--spec/ruby/library/openssl/digest_spec.rb63
-rw-r--r--spec/ruby/library/openssl/fixed_length_secure_compare_spec.rb42
-rw-r--r--spec/ruby/library/openssl/kdf/pbkdf2_hmac_spec.rb168
-rw-r--r--spec/ruby/library/openssl/kdf/scrypt_spec.rb209
-rw-r--r--spec/ruby/library/openssl/random/shared/random_bytes.rb2
-rw-r--r--spec/ruby/library/openssl/secure_compare_spec.rb38
-rw-r--r--spec/ruby/library/openssl/x509/store/verify_spec.rb78
-rw-r--r--spec/ruby/library/openstruct/method_missing_spec.rb8
-rw-r--r--spec/ruby/library/pathname/birthtime_spec.rb16
-rw-r--r--spec/ruby/library/pathname/glob_spec.rb53
-rw-r--r--spec/ruby/library/pathname/new_spec.rb7
-rw-r--r--spec/ruby/library/pathname/pathname_spec.rb19
-rw-r--r--spec/ruby/library/pathname/relative_path_from_spec.rb4
-rw-r--r--spec/ruby/library/prime/each_spec.rb247
-rw-r--r--spec/ruby/library/prime/instance_spec.rb31
-rw-r--r--spec/ruby/library/prime/int_from_prime_division_spec.rb19
-rw-r--r--spec/ruby/library/prime/integer/each_prime_spec.rb19
-rw-r--r--spec/ruby/library/prime/integer/from_prime_division_spec.rb19
-rw-r--r--spec/ruby/library/prime/integer/prime_division_spec.rb31
-rw-r--r--spec/ruby/library/prime/integer/prime_spec.rb27
-rw-r--r--spec/ruby/library/prime/next_spec.rb11
-rw-r--r--spec/ruby/library/prime/prime_division_spec.rb37
-rw-r--r--spec/ruby/library/prime/prime_spec.rb27
-rw-r--r--spec/ruby/library/prime/succ_spec.rb11
-rw-r--r--spec/ruby/library/rbconfig/unicode_emoji_version_spec.rb25
-rw-r--r--spec/ruby/library/rbconfig/unicode_version_spec.rb25
-rw-r--r--spec/ruby/library/readline/history/delete_at_spec.rb9
-rw-r--r--spec/ruby/library/readline/history/each_spec.rb8
-rw-r--r--spec/ruby/library/readline/history/element_reference_spec.rb7
-rw-r--r--spec/ruby/library/readline/history/pop_spec.rb9
-rw-r--r--spec/ruby/library/readline/history/shift_spec.rb9
-rw-r--r--spec/ruby/library/readline/readline_spec.rb7
-rw-r--r--spec/ruby/library/rexml/attribute/clone_spec.rb14
-rw-r--r--spec/ruby/library/rexml/attribute/element_spec.rb26
-rw-r--r--spec/ruby/library/rexml/attribute/equal_value_spec.rb21
-rw-r--r--spec/ruby/library/rexml/attribute/hash_spec.rb16
-rw-r--r--spec/ruby/library/rexml/attribute/initialize_spec.rb32
-rw-r--r--spec/ruby/library/rexml/attribute/inspect_spec.rb22
-rw-r--r--spec/ruby/library/rexml/attribute/namespace_spec.rb27
-rw-r--r--spec/ruby/library/rexml/attribute/node_type_spec.rb13
-rw-r--r--spec/ruby/library/rexml/attribute/prefix_spec.rb21
-rw-r--r--spec/ruby/library/rexml/attribute/remove_spec.rb23
-rw-r--r--spec/ruby/library/rexml/attribute/to_s_spec.rb17
-rw-r--r--spec/ruby/library/rexml/attribute/to_string_spec.rb17
-rw-r--r--spec/ruby/library/rexml/attribute/value_spec.rb17
-rw-r--r--spec/ruby/library/rexml/attribute/write_spec.rb26
-rw-r--r--spec/ruby/library/rexml/attribute/xpath_spec.rb22
-rw-r--r--spec/ruby/library/rexml/attributes/add_spec.rb10
-rw-r--r--spec/ruby/library/rexml/attributes/append_spec.rb10
-rw-r--r--spec/ruby/library/rexml/attributes/delete_all_spec.rb34
-rw-r--r--spec/ruby/library/rexml/attributes/delete_spec.rb30
-rw-r--r--spec/ruby/library/rexml/attributes/each_attribute_spec.rb25
-rw-r--r--spec/ruby/library/rexml/attributes/each_spec.rb26
-rw-r--r--spec/ruby/library/rexml/attributes/element_reference_spec.rb21
-rw-r--r--spec/ruby/library/rexml/attributes/element_set_spec.rb28
-rw-r--r--spec/ruby/library/rexml/attributes/get_attribute_ns_spec.rb17
-rw-r--r--spec/ruby/library/rexml/attributes/get_attribute_spec.rb32
-rw-r--r--spec/ruby/library/rexml/attributes/initialize_spec.rb21
-rw-r--r--spec/ruby/library/rexml/attributes/length_spec.rb10
-rw-r--r--spec/ruby/library/rexml/attributes/namespaces_spec.rb9
-rw-r--r--spec/ruby/library/rexml/attributes/prefixes_spec.rb27
-rw-r--r--spec/ruby/library/rexml/attributes/shared/add.rb17
-rw-r--r--spec/ruby/library/rexml/attributes/shared/length.rb13
-rw-r--r--spec/ruby/library/rexml/attributes/size_spec.rb10
-rw-r--r--spec/ruby/library/rexml/attributes/to_a_spec.rb22
-rw-r--r--spec/ruby/library/rexml/cdata/clone_spec.rb13
-rw-r--r--spec/ruby/library/rexml/cdata/initialize_spec.rb27
-rw-r--r--spec/ruby/library/rexml/cdata/shared/to_s.rb11
-rw-r--r--spec/ruby/library/rexml/cdata/to_s_spec.rb10
-rw-r--r--spec/ruby/library/rexml/cdata/value_spec.rb10
-rw-r--r--spec/ruby/library/rexml/document/add_element_spec.rb34
-rw-r--r--spec/ruby/library/rexml/document/add_spec.rb60
-rw-r--r--spec/ruby/library/rexml/document/clone_spec.rb23
-rw-r--r--spec/ruby/library/rexml/document/doctype_spec.rb18
-rw-r--r--spec/ruby/library/rexml/document/encoding_spec.rb25
-rw-r--r--spec/ruby/library/rexml/document/expanded_name_spec.rb19
-rw-r--r--spec/ruby/library/rexml/document/new_spec.rb39
-rw-r--r--spec/ruby/library/rexml/document/node_type_spec.rb11
-rw-r--r--spec/ruby/library/rexml/document/root_spec.rb15
-rw-r--r--spec/ruby/library/rexml/document/stand_alone_spec.rb22
-rw-r--r--spec/ruby/library/rexml/document/version_spec.rb17
-rw-r--r--spec/ruby/library/rexml/document/write_spec.rb38
-rw-r--r--spec/ruby/library/rexml/document/xml_decl_spec.rb18
-rw-r--r--spec/ruby/library/rexml/element/add_attribute_spec.rb44
-rw-r--r--spec/ruby/library/rexml/element/add_attributes_spec.rb25
-rw-r--r--spec/ruby/library/rexml/element/add_element_spec.rb41
-rw-r--r--spec/ruby/library/rexml/element/add_namespace_spec.rb26
-rw-r--r--spec/ruby/library/rexml/element/add_text_spec.rb27
-rw-r--r--spec/ruby/library/rexml/element/attribute_spec.rb20
-rw-r--r--spec/ruby/library/rexml/element/attributes_spec.rb22
-rw-r--r--spec/ruby/library/rexml/element/cdatas_spec.rb27
-rw-r--r--spec/ruby/library/rexml/element/clone_spec.rb32
-rw-r--r--spec/ruby/library/rexml/element/comments_spec.rb23
-rw-r--r--spec/ruby/library/rexml/element/delete_attribute_spec.rb42
-rw-r--r--spec/ruby/library/rexml/element/delete_element_spec.rb52
-rw-r--r--spec/ruby/library/rexml/element/delete_namespace_spec.rb28
-rw-r--r--spec/ruby/library/rexml/element/document_spec.rb19
-rw-r--r--spec/ruby/library/rexml/element/each_element_with_attribute_spec.rb38
-rw-r--r--spec/ruby/library/rexml/element/each_element_with_text_spec.rb34
-rw-r--r--spec/ruby/library/rexml/element/element_reference_spec.rb23
-rw-r--r--spec/ruby/library/rexml/element/get_text_spec.rb21
-rw-r--r--spec/ruby/library/rexml/element/has_attributes_spec.rb20
-rw-r--r--spec/ruby/library/rexml/element/has_elements_spec.rb21
-rw-r--r--spec/ruby/library/rexml/element/has_text_spec.rb19
-rw-r--r--spec/ruby/library/rexml/element/inspect_spec.rb30
-rw-r--r--spec/ruby/library/rexml/element/instructions_spec.rb24
-rw-r--r--spec/ruby/library/rexml/element/namespace_spec.rb30
-rw-r--r--spec/ruby/library/rexml/element/namespaces_spec.rb35
-rw-r--r--spec/ruby/library/rexml/element/new_spec.rb38
-rw-r--r--spec/ruby/library/rexml/element/next_element_spec.rb22
-rw-r--r--spec/ruby/library/rexml/element/node_type_spec.rb11
-rw-r--r--spec/ruby/library/rexml/element/prefixes_spec.rb26
-rw-r--r--spec/ruby/library/rexml/element/previous_element_spec.rb23
-rw-r--r--spec/ruby/library/rexml/element/raw_spec.rb27
-rw-r--r--spec/ruby/library/rexml/element/root_spec.rb31
-rw-r--r--spec/ruby/library/rexml/element/text_spec.rb49
-rw-r--r--spec/ruby/library/rexml/element/texts_spec.rb19
-rw-r--r--spec/ruby/library/rexml/element/whitespace_spec.rb26
-rw-r--r--spec/ruby/library/rexml/node/each_recursive_spec.rb24
-rw-r--r--spec/ruby/library/rexml/node/find_first_recursive_spec.rb28
-rw-r--r--spec/ruby/library/rexml/node/index_in_parent_spec.rb18
-rw-r--r--spec/ruby/library/rexml/node/next_sibling_node_spec.rb24
-rw-r--r--spec/ruby/library/rexml/node/parent_spec.rb23
-rw-r--r--spec/ruby/library/rexml/node/previous_sibling_node_spec.rb24
-rw-r--r--spec/ruby/library/rexml/shared/each_element.rb36
-rw-r--r--spec/ruby/library/rexml/shared/elements_to_a.rb34
-rw-r--r--spec/ruby/library/rexml/text/append_spec.rb13
-rw-r--r--spec/ruby/library/rexml/text/clone_spec.rb13
-rw-r--r--spec/ruby/library/rexml/text/comparison_spec.rb28
-rw-r--r--spec/ruby/library/rexml/text/empty_spec.rb15
-rw-r--r--spec/ruby/library/rexml/text/indent_text_spec.rb26
-rw-r--r--spec/ruby/library/rexml/text/inspect_spec.rb11
-rw-r--r--spec/ruby/library/rexml/text/new_spec.rb51
-rw-r--r--spec/ruby/library/rexml/text/node_type_spec.rb11
-rw-r--r--spec/ruby/library/rexml/text/normalize_spec.rb11
-rw-r--r--spec/ruby/library/rexml/text/read_with_substitution_spec.rb15
-rw-r--r--spec/ruby/library/rexml/text/to_s_spec.rb20
-rw-r--r--spec/ruby/library/rexml/text/unnormalize_spec.rb11
-rw-r--r--spec/ruby/library/rexml/text/value_spec.rb40
-rw-r--r--spec/ruby/library/rexml/text/wrap_spec.rb23
-rw-r--r--spec/ruby/library/rexml/text/write_with_substitution_spec.rb36
-rw-r--r--spec/ruby/library/rubygems/gem/load_path_insert_index_spec.rb2
-rw-r--r--spec/ruby/library/scanf/io/block_scanf_spec.rb10
-rw-r--r--spec/ruby/library/scanf/io/fixtures/date.txt4
-rw-r--r--spec/ruby/library/scanf/io/fixtures/helloworld.txt1
-rw-r--r--spec/ruby/library/scanf/io/scanf_spec.rb38
-rw-r--r--spec/ruby/library/scanf/io/shared/block_scanf.rb28
-rw-r--r--spec/ruby/library/scanf/string/block_scanf_spec.rb10
-rw-r--r--spec/ruby/library/scanf/string/scanf_spec.rb56
-rw-r--r--spec/ruby/library/scanf/string/shared/block_scanf.rb25
-rw-r--r--spec/ruby/library/set/compare_by_identity_spec.rb2
-rw-r--r--spec/ruby/library/set/comparison_spec.rb56
-rw-r--r--spec/ruby/library/set/divide_spec.rb35
-rw-r--r--spec/ruby/library/set/each_spec.rb1
-rw-r--r--spec/ruby/library/set/enumerable/to_set_spec.rb8
-rw-r--r--spec/ruby/library/set/flatten_spec.rb9
-rw-r--r--spec/ruby/library/set/initialize_clone_spec.rb22
-rw-r--r--spec/ruby/library/set/join_spec.rb42
-rw-r--r--spec/ruby/library/set/proper_subset_spec.rb9
-rw-r--r--spec/ruby/library/set/set_spec.rb12
-rw-r--r--spec/ruby/library/set/shared/inspect.rb20
-rw-r--r--spec/ruby/library/set/sortedset/add_spec.rb42
-rw-r--r--spec/ruby/library/set/sortedset/append_spec.rb10
-rw-r--r--spec/ruby/library/set/sortedset/case_equality_spec.rb10
-rw-r--r--spec/ruby/library/set/sortedset/classify_spec.rb30
-rw-r--r--spec/ruby/library/set/sortedset/clear_spec.rb20
-rw-r--r--spec/ruby/library/set/sortedset/collect_spec.rb10
-rw-r--r--spec/ruby/library/set/sortedset/constructor_spec.rb18
-rw-r--r--spec/ruby/library/set/sortedset/delete_if_spec.rb41
-rw-r--r--spec/ruby/library/set/sortedset/delete_spec.rb40
-rw-r--r--spec/ruby/library/set/sortedset/difference_spec.rb10
-rw-r--r--spec/ruby/library/set/sortedset/divide_spec.rb37
-rw-r--r--spec/ruby/library/set/sortedset/each_spec.rb29
-rw-r--r--spec/ruby/library/set/sortedset/empty_spec.rb13
-rw-r--r--spec/ruby/library/set/sortedset/eql_spec.rb19
-rw-r--r--spec/ruby/library/set/sortedset/equal_value_spec.rb16
-rw-r--r--spec/ruby/library/set/sortedset/exclusion_spec.rb21
-rw-r--r--spec/ruby/library/set/sortedset/filter_spec.rb10
-rw-r--r--spec/ruby/library/set/sortedset/flatten_merge_spec.rb11
-rw-r--r--spec/ruby/library/set/sortedset/flatten_spec.rb47
-rw-r--r--spec/ruby/library/set/sortedset/hash_spec.rb16
-rw-r--r--spec/ruby/library/set/sortedset/include_spec.rb10
-rw-r--r--spec/ruby/library/set/sortedset/initialize_spec.rb33
-rw-r--r--spec/ruby/library/set/sortedset/inspect_spec.rb13
-rw-r--r--spec/ruby/library/set/sortedset/intersection_spec.rb14
-rw-r--r--spec/ruby/library/set/sortedset/keep_if_spec.rb34
-rw-r--r--spec/ruby/library/set/sortedset/length_spec.rb10
-rw-r--r--spec/ruby/library/set/sortedset/map_spec.rb10
-rw-r--r--spec/ruby/library/set/sortedset/member_spec.rb10
-rw-r--r--spec/ruby/library/set/sortedset/merge_spec.rb22
-rw-r--r--spec/ruby/library/set/sortedset/minus_spec.rb10
-rw-r--r--spec/ruby/library/set/sortedset/plus_spec.rb10
-rw-r--r--spec/ruby/library/set/sortedset/pretty_print_cycle_spec.rb13
-rw-r--r--spec/ruby/library/set/sortedset/pretty_print_spec.rb20
-rw-r--r--spec/ruby/library/set/sortedset/proper_subset_spec.rb36
-rw-r--r--spec/ruby/library/set/sortedset/proper_superset_spec.rb36
-rw-r--r--spec/ruby/library/set/sortedset/reject_spec.rb45
-rw-r--r--spec/ruby/library/set/sortedset/replace_spec.rb20
-rw-r--r--spec/ruby/library/set/sortedset/select_spec.rb10
-rw-r--r--spec/ruby/library/set/sortedset/shared/add.rb14
-rw-r--r--spec/ruby/library/set/sortedset/shared/collect.rb20
-rw-r--r--spec/ruby/library/set/sortedset/shared/difference.rb15
-rw-r--r--spec/ruby/library/set/sortedset/shared/include.rb7
-rw-r--r--spec/ruby/library/set/sortedset/shared/intersection.rb15
-rw-r--r--spec/ruby/library/set/sortedset/shared/length.rb6
-rw-r--r--spec/ruby/library/set/sortedset/shared/select.rb35
-rw-r--r--spec/ruby/library/set/sortedset/shared/union.rb15
-rw-r--r--spec/ruby/library/set/sortedset/size_spec.rb10
-rw-r--r--spec/ruby/library/set/sortedset/sortedset_spec.rb24
-rw-r--r--spec/ruby/library/set/sortedset/subset_spec.rb36
-rw-r--r--spec/ruby/library/set/sortedset/subtract_spec.rb20
-rw-r--r--spec/ruby/library/set/sortedset/superset_spec.rb36
-rw-r--r--spec/ruby/library/set/sortedset/to_a_spec.rb20
-rw-r--r--spec/ruby/library/set/sortedset/union_spec.rb14
-rw-r--r--spec/ruby/library/set/subset_spec.rb9
-rw-r--r--spec/ruby/library/set/to_s_spec.rb1
-rw-r--r--spec/ruby/library/shellwords/shellwords_spec.rb15
-rw-r--r--spec/ruby/library/socket/addrinfo/initialize_spec.rb2
-rw-r--r--spec/ruby/library/socket/addrinfo/shared/to_sockaddr.rb4
-rw-r--r--spec/ruby/library/socket/basicsocket/read_nonblock_spec.rb32
-rw-r--r--spec/ruby/library/socket/basicsocket/read_spec.rb47
-rw-r--r--spec/ruby/library/socket/basicsocket/recv_nonblock_spec.rb2
-rw-r--r--spec/ruby/library/socket/basicsocket/recv_spec.rb21
-rw-r--r--spec/ruby/library/socket/basicsocket/send_spec.rb8
-rw-r--r--spec/ruby/library/socket/basicsocket/shutdown_spec.rb20
-rw-r--r--spec/ruby/library/socket/fixtures/classes.rb6
-rw-r--r--spec/ruby/library/socket/ipsocket/getaddress_spec.rb2
-rw-r--r--spec/ruby/library/socket/shared/pack_sockaddr.rb10
-rw-r--r--spec/ruby/library/socket/shared/partially_closable_sockets.rb2
-rw-r--r--spec/ruby/library/socket/socket/getnameinfo_spec.rb2
-rw-r--r--spec/ruby/library/socket/socket/new_spec.rb2
-rw-r--r--spec/ruby/library/socket/socket/pack_sockaddr_in_spec.rb2
-rw-r--r--spec/ruby/library/socket/socket/pair_spec.rb2
-rw-r--r--spec/ruby/library/socket/socket/socketpair_spec.rb2
-rw-r--r--spec/ruby/library/socket/tcpserver/accept_spec.rb15
-rw-r--r--spec/ruby/library/socket/tcpserver/new_spec.rb6
-rw-r--r--spec/ruby/library/socket/tcpsocket/initialize_spec.rb34
-rw-r--r--spec/ruby/library/socket/tcpsocket/open_spec.rb1
-rw-r--r--spec/ruby/library/socket/tcpsocket/partially_closable_spec.rb2
-rw-r--r--spec/ruby/library/socket/tcpsocket/shared/new.rb24
-rw-r--r--spec/ruby/library/socket/udpsocket/initialize_spec.rb13
-rw-r--r--spec/ruby/library/socket/udpsocket/new_spec.rb6
-rw-r--r--spec/ruby/library/socket/udpsocket/send_spec.rb2
-rw-r--r--spec/ruby/library/socket/unixserver/accept_nonblock_spec.rb7
-rw-r--r--spec/ruby/library/socket/unixserver/accept_spec.rb13
-rw-r--r--spec/ruby/library/socket/unixserver/for_fd_spec.rb4
-rw-r--r--spec/ruby/library/socket/unixserver/new_spec.rb12
-rw-r--r--spec/ruby/library/socket/unixserver/open_spec.rb6
-rw-r--r--spec/ruby/library/socket/unixserver/shared/new.rb26
-rw-r--r--spec/ruby/library/socket/unixsocket/addr_spec.rb5
-rw-r--r--spec/ruby/library/socket/unixsocket/initialize_spec.rb10
-rw-r--r--spec/ruby/library/socket/unixsocket/inspect_spec.rb4
-rw-r--r--spec/ruby/library/socket/unixsocket/local_address_spec.rb2
-rw-r--r--spec/ruby/library/socket/unixsocket/new_spec.rb12
-rw-r--r--spec/ruby/library/socket/unixsocket/open_spec.rb10
-rw-r--r--spec/ruby/library/socket/unixsocket/pair_spec.rb7
-rw-r--r--spec/ruby/library/socket/unixsocket/partially_closable_spec.rb6
-rw-r--r--spec/ruby/library/socket/unixsocket/path_spec.rb6
-rw-r--r--spec/ruby/library/socket/unixsocket/peeraddr_spec.rb6
-rw-r--r--spec/ruby/library/socket/unixsocket/recv_io_spec.rb7
-rw-r--r--spec/ruby/library/socket/unixsocket/recvfrom_spec.rb7
-rw-r--r--spec/ruby/library/socket/unixsocket/send_io_spec.rb7
-rw-r--r--spec/ruby/library/socket/unixsocket/shared/new.rb28
-rw-r--r--spec/ruby/library/stringio/append_spec.rb22
-rw-r--r--spec/ruby/library/stringio/binmode_spec.rb2
-rw-r--r--spec/ruby/library/stringio/bytes_spec.rb29
-rw-r--r--spec/ruby/library/stringio/chars_spec.rb29
-rw-r--r--spec/ruby/library/stringio/close_read_spec.rb4
-rw-r--r--spec/ruby/library/stringio/close_write_spec.rb6
-rw-r--r--spec/ruby/library/stringio/closed_read_spec.rb2
-rw-r--r--spec/ruby/library/stringio/closed_spec.rb4
-rw-r--r--spec/ruby/library/stringio/closed_write_spec.rb2
-rw-r--r--spec/ruby/library/stringio/codepoints_spec.rb19
-rw-r--r--spec/ruby/library/stringio/each_line_spec.rb4
-rw-r--r--spec/ruby/library/stringio/each_spec.rb8
-rw-r--r--spec/ruby/library/stringio/flush_spec.rb2
-rw-r--r--spec/ruby/library/stringio/fsync_spec.rb2
-rw-r--r--spec/ruby/library/stringio/gets_spec.rb6
-rw-r--r--spec/ruby/library/stringio/initialize_spec.rb152
-rw-r--r--spec/ruby/library/stringio/lines_spec.rb53
-rw-r--r--spec/ruby/library/stringio/new_spec.rb10
-rw-r--r--spec/ruby/library/stringio/open_spec.rb68
-rw-r--r--spec/ruby/library/stringio/print_spec.rb8
-rw-r--r--spec/ruby/library/stringio/printf_spec.rb33
-rw-r--r--spec/ruby/library/stringio/putc_spec.rb25
-rw-r--r--spec/ruby/library/stringio/puts_spec.rb22
-rw-r--r--spec/ruby/library/stringio/read_nonblock_spec.rb13
-rw-r--r--spec/ruby/library/stringio/read_spec.rb2
-rw-r--r--spec/ruby/library/stringio/readline_spec.rb22
-rw-r--r--spec/ruby/library/stringio/readlines_spec.rb20
-rw-r--r--spec/ruby/library/stringio/readpartial_spec.rb6
-rw-r--r--spec/ruby/library/stringio/reopen_spec.rb85
-rw-r--r--spec/ruby/library/stringio/set_encoding_spec.rb8
-rw-r--r--spec/ruby/library/stringio/shared/codepoints.rb2
-rw-r--r--spec/ruby/library/stringio/shared/each.rb60
-rw-r--r--spec/ruby/library/stringio/shared/each_byte.rb2
-rw-r--r--spec/ruby/library/stringio/shared/each_char.rb2
-rw-r--r--spec/ruby/library/stringio/shared/getc.rb2
-rw-r--r--spec/ruby/library/stringio/shared/isatty.rb2
-rw-r--r--spec/ruby/library/stringio/shared/read.rb18
-rw-r--r--spec/ruby/library/stringio/shared/readchar.rb2
-rw-r--r--spec/ruby/library/stringio/shared/sysread.rb2
-rw-r--r--spec/ruby/library/stringio/shared/write.rb74
-rw-r--r--spec/ruby/library/stringio/truncate_spec.rb20
-rw-r--r--spec/ruby/library/stringio/ungetc_spec.rb10
-rw-r--r--spec/ruby/library/stringio/write_nonblock_spec.rb6
-rw-r--r--spec/ruby/library/stringscanner/check_spec.rb14
-rw-r--r--spec/ruby/library/stringscanner/getch_spec.rb2
-rw-r--r--spec/ruby/library/stringscanner/scan_spec.rb44
-rw-r--r--spec/ruby/library/stringscanner/shared/concat.rb2
-rw-r--r--spec/ruby/library/stringscanner/shared/extract_range.rb13
-rw-r--r--spec/ruby/library/stringscanner/shared/extract_range_matched.rb11
-rw-r--r--spec/ruby/library/stringscanner/shared/peek.rb10
-rw-r--r--spec/ruby/library/stringscanner/string_spec.rb2
-rw-r--r--spec/ruby/library/time/to_datetime_spec.rb19
-rw-r--r--spec/ruby/library/uri/generic/host_spec.rb7
-rw-r--r--spec/ruby/library/uri/generic/to_s_spec.rb7
-rw-r--r--spec/ruby/library/win32ole/win32ole/_getproperty_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/_invoke_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/codepage_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/connect_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/const_load_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/constants_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/create_guid_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/invoke_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/locale_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/new_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/ole_func_methods_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/ole_get_methods_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/ole_method_help_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/ole_method_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/ole_methods_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/ole_obj_help_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/ole_put_methods_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole/setproperty_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_event/new_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_event/on_event_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/dispid_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/event_interface_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/event_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/helpcontext_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/helpfile_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/helpstring_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/invkind_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/invoke_kind_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/name_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/new_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/offset_vtbl_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/params_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/return_type_detail_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/return_type_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/return_vtype_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/size_opt_params_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/size_params_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/to_s_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_method/visible_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_param/default_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_param/input_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_param/name_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_param/ole_type_detail_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_param/ole_type_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_param/optional_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_param/retval_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_param/to_s_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/guid_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/helpcontext_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/helpfile_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/helpstring_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/major_version_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/minor_version_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/name_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/new_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/ole_classes_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/ole_methods_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/ole_type_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/progid_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/progids_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/src_type_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/to_s_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/typekind_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/typelibs_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/variables_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_type/visible_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_variable/name_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_variable/ole_type_detail_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_variable/ole_type_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_variable/to_s_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_variable/value_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_variable/variable_kind_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_variable/varkind_spec.rb1
-rw-r--r--spec/ruby/library/win32ole/win32ole_variable/visible_spec.rb1
-rw-r--r--spec/ruby/library/yaml/dump_spec.rb14
-rw-r--r--spec/ruby/library/yaml/dump_stream_spec.rb3
-rw-r--r--spec/ruby/library/yaml/fixtures/common.rb4
-rw-r--r--spec/ruby/library/yaml/fixtures/strings.rb56
-rw-r--r--spec/ruby/library/yaml/load_file_spec.rb13
-rw-r--r--spec/ruby/library/yaml/load_stream_spec.rb3
-rw-r--r--spec/ruby/library/yaml/parse_file_spec.rb8
-rw-r--r--spec/ruby/library/yaml/parse_spec.rb7
-rw-r--r--spec/ruby/library/yaml/shared/each_document.rb5
-rw-r--r--spec/ruby/library/yaml/shared/load.rb12
-rw-r--r--spec/ruby/library/yaml/to_yaml_spec.rb32
-rw-r--r--spec/ruby/library/zlib/crc_table_spec.rb143
-rw-r--r--spec/ruby/library/zlib/deflate/deflate_spec.rb9
-rw-r--r--spec/ruby/library/zlib/deflate/new_spec.rb1
-rw-r--r--spec/ruby/library/zlib/deflate/params_spec.rb2
-rw-r--r--spec/ruby/library/zlib/gzipreader/each_line_spec.rb1
-rw-r--r--spec/ruby/library/zlib/gzipreader/each_spec.rb1
-rw-r--r--spec/ruby/library/zlib/gzipreader/mtime_spec.rb11
-rw-r--r--spec/ruby/library/zlib/gzipreader/new_spec.rb1
-rw-r--r--spec/ruby/library/zlib/inflate/finish_spec.rb1
-rw-r--r--spec/ruby/library/zlib/inflate/inflate_spec.rb15
-rw-r--r--spec/ruby/library/zlib/inflate/new_spec.rb1
-rw-r--r--spec/ruby/optional/capi/array_spec.rb34
-rw-r--r--spec/ruby/optional/capi/binding_spec.rb21
-rw-r--r--spec/ruby/optional/capi/class_spec.rb63
-rw-r--r--spec/ruby/optional/capi/debug_spec.rb9
-rw-r--r--spec/ruby/optional/capi/encoding_spec.rb135
-rw-r--r--spec/ruby/optional/capi/exception_spec.rb34
-rw-r--r--spec/ruby/optional/capi/ext/array_spec.c28
-rw-r--r--spec/ruby/optional/capi/ext/class_spec.c45
-rw-r--r--spec/ruby/optional/capi/ext/debug_spec.c2
-rw-r--r--spec/ruby/optional/capi/ext/encoding_spec.c61
-rw-r--r--spec/ruby/optional/capi/ext/exception_spec.c19
-rw-r--r--spec/ruby/optional/capi/ext/gc_spec.c79
-rw-r--r--spec/ruby/optional/capi/ext/globals_spec.c34
-rw-r--r--spec/ruby/optional/capi/ext/hash_spec.c9
-rw-r--r--spec/ruby/optional/capi/ext/integer_spec.c5
-rw-r--r--spec/ruby/optional/capi/ext/io_spec.c130
-rw-r--r--spec/ruby/optional/capi/ext/kernel_spec.c61
-rw-r--r--spec/ruby/optional/capi/ext/module_spec.c56
-rw-r--r--spec/ruby/optional/capi/ext/object_spec.c97
-rw-r--r--spec/ruby/optional/capi/ext/proc_spec.c15
-rw-r--r--spec/ruby/optional/capi/ext/range_spec.c2
-rw-r--r--spec/ruby/optional/capi/ext/rbasic_spec.c54
-rw-r--r--spec/ruby/optional/capi/ext/regexp_spec.c7
-rw-r--r--spec/ruby/optional/capi/ext/rubyspec.h64
-rw-r--r--spec/ruby/optional/capi/ext/string_spec.c65
-rw-r--r--spec/ruby/optional/capi/ext/struct_spec.c13
-rw-r--r--spec/ruby/optional/capi/ext/symbol_spec.c11
-rw-r--r--spec/ruby/optional/capi/ext/thread_spec.c21
-rw-r--r--spec/ruby/optional/capi/ext/tracepoint_spec.c2
-rw-r--r--spec/ruby/optional/capi/ext/typed_data_spec.c12
-rw-r--r--spec/ruby/optional/capi/ext/util_spec.c34
-rw-r--r--spec/ruby/optional/capi/file_spec.rb2
-rw-r--r--spec/ruby/optional/capi/fixtures/class.rb10
-rw-r--r--spec/ruby/optional/capi/fixtures/kernel.rb19
-rw-r--r--spec/ruby/optional/capi/fixtures/object.rb29
-rw-r--r--spec/ruby/optional/capi/gc_spec.rb57
-rw-r--r--spec/ruby/optional/capi/globals_spec.rb54
-rw-r--r--spec/ruby/optional/capi/hash_spec.rb16
-rw-r--r--spec/ruby/optional/capi/integer_spec.rb17
-rw-r--r--spec/ruby/optional/capi/io_spec.rb132
-rw-r--r--spec/ruby/optional/capi/kernel_spec.rb202
-rw-r--r--spec/ruby/optional/capi/module_spec.rb30
-rw-r--r--spec/ruby/optional/capi/object_spec.rb159
-rw-r--r--spec/ruby/optional/capi/proc_spec.rb81
-rw-r--r--spec/ruby/optional/capi/rbasic_spec.rb3
-rw-r--r--spec/ruby/optional/capi/regexp_spec.rb16
-rw-r--r--spec/ruby/optional/capi/shared/rbasic.rb37
-rw-r--r--spec/ruby/optional/capi/spec_helper.rb8
-rw-r--r--spec/ruby/optional/capi/string_spec.rb230
-rw-r--r--spec/ruby/optional/capi/symbol_spec.rb8
-rw-r--r--spec/ruby/optional/capi/thread_spec.rb28
-rw-r--r--spec/ruby/optional/capi/time_spec.rb5
-rw-r--r--spec/ruby/optional/capi/typed_data_spec.rb12
-rw-r--r--spec/ruby/optional/capi/util_spec.rb107
-rw-r--r--spec/ruby/security/cve_2010_1330_spec.rb2
-rw-r--r--spec/ruby/security/cve_2014_8080_spec.rb34
-rw-r--r--spec/ruby/security/cve_2017_17742_spec.rb37
-rw-r--r--spec/ruby/security/cve_2018_16396_spec.rb14
-rw-r--r--spec/ruby/security/cve_2019_8322_spec.rb24
-rw-r--r--spec/ruby/security/cve_2019_8323_spec.rb64
-rw-r--r--spec/ruby/security/cve_2019_8325_spec.rb62
-rw-r--r--spec/ruby/security/cve_2020_10663_spec.rb25
-rw-r--r--spec/ruby/shared/file/executable.rb35
-rw-r--r--spec/ruby/shared/file/executable_real.rb35
-rw-r--r--spec/ruby/shared/file/exist.rb5
-rw-r--r--spec/ruby/shared/file/readable.rb16
-rw-r--r--spec/ruby/shared/file/readable_real.rb16
-rw-r--r--spec/ruby/shared/file/writable.rb16
-rw-r--r--spec/ruby/shared/file/writable_real.rb16
-rw-r--r--spec/ruby/shared/kernel/at_exit.rb70
-rw-r--r--spec/ruby/shared/kernel/complex.rb133
-rw-r--r--spec/ruby/shared/kernel/fixtures/END.rb3
-rw-r--r--spec/ruby/shared/kernel/fixtures/at_exit.rb3
-rw-r--r--spec/ruby/shared/kernel/object_id.rb28
-rw-r--r--spec/ruby/shared/kernel/raise.rb45
-rw-r--r--spec/ruby/shared/process/exit.rb12
-rw-r--r--spec/ruby/shared/queue/deque.rb81
-rw-r--r--spec/ruby/shared/rational/Rational.rb57
-rw-r--r--spec/ruby/shared/rational/coerce.rb34
-rw-r--r--spec/ruby/shared/rational/divmod.rb4
-rw-r--r--spec/ruby/shared/rational/exponent.rb8
-rw-r--r--spec/ruby/shared/rational/marshal_dump.rb5
-rw-r--r--spec/ruby/shared/rational/marshal_load.rb5
-rw-r--r--spec/ruby/shared/rational/minus.rb48
-rw-r--r--spec/ruby/shared/rational/quo.rb5
-rw-r--r--spec/ruby/shared/rational/to_f.rb6
-rw-r--r--spec/ruby/shared/rational/truncate.rb26
-rw-r--r--spec/ruby/shared/sizedqueue/enque.rb83
-rw-r--r--spec/ruby/shared/sizedqueue/new.rb9
-rw-r--r--spec/ruby/shared/string/end_with.rb9
-rw-r--r--spec/ruby/shared/string/start_with.rb12
-rw-r--r--spec/ruby/shared/string/times.rb32
-rw-r--r--spec/ruby/shared/types/rb_num2dbl_fails.rb17
-rw-r--r--spec/ruby/spec_helper.rb12
2075 files changed, 37989 insertions, 28586 deletions
diff --git a/spec/ruby/.mspec.constants b/spec/ruby/.mspec.constants
index 6b70274c52..6e09a44362 100644
--- a/spec/ruby/.mspec.constants
+++ b/spec/ruby/.mspec.constants
@@ -39,6 +39,8 @@ CodingUS_ASCII
CodingUTF_8
ComparisonTest
ConstantSpecsIncludedModule
+ConstantSpecsTwo
+ConstantSpecsThree
ConstantVisibility
Coverage
CoverageSpecs
@@ -73,6 +75,7 @@ EvalBindingProcA
Exception2MessageMapper
ExceptionForMatrix
Fcntl
+Fiddle
FileStat
FileUtils
Find
@@ -201,6 +204,7 @@ UserArray
UserCustomConstructorString
UserDefined
UserDefinedImmediate
+UserDefinedString
UserDefinedWithIvar
UserHash
UserHashInitParams
diff --git a/spec/ruby/.rubocop.yml b/spec/ruby/.rubocop.yml
index eab4c3c4a6..be32ce8900 100644
--- a/spec/ruby/.rubocop.yml
+++ b/spec/ruby/.rubocop.yml
@@ -1,11 +1,12 @@
inherit_from: .rubocop_todo.yml
AllCops:
- TargetRubyVersion: 2.6
+ TargetRubyVersion: 3.0
DisplayCopNames: true
Exclude:
- command_line/fixtures/bad_syntax.rb
DisabledByDefault: true
+ NewCops: disable
Layout/TrailingWhitespace:
Enabled: true
@@ -32,15 +33,16 @@ Lint/AssignmentInCondition:
Lint/BooleanSymbol:
Enabled: false
+Lint/DeprecatedOpenSSLConstant:
+ Exclude:
+ - library/openssl/digest/**/*.rb
+
Lint/InterpolationCheck:
Enabled: false
Lint/LiteralAsCondition:
Enabled: false
-Lint/RedundantRequireStatement:
- Enabled: false
-
Lint/RedundantSplatExpansion:
Enabled: false
@@ -56,12 +58,58 @@ Lint/UnusedMethodArgument:
Lint/UselessAssignment:
Enabled: false
-Lint/UselessComparison:
+Lint/BinaryOperatorWithIdenticalOperands:
Enabled: false
+Lint/EmptyConditionalBody:
+ Enabled: false # buggy
+
Lint/Void:
Enabled: false
+Lint/ConstantDefinitionInBlock:
+ Enabled: false
+
+Lint/RaiseException:
+ Enabled: false
+
+Lint/FloatComparison:
+ Enabled: false
+
+Lint/DeprecatedClassMethods:
+ Enabled: false
+
+Lint/UnreachableLoop:
+ Enabled: false
+
+Lint/MissingSuper:
+ Enabled: false
+
+Lint/UselessMethodDefinition:
+ Enabled: false
+
+Lint/UselessTimes:
+ Enabled: false
+
+Lint/MixedRegexpCaptureTypes:
+ Enabled: false
+
+Lint/DuplicateElsifCondition:
+ Enabled: false
+
+Lint/OutOfRangeRegexpRef:
+ Enabled: false
+
+Lint/InheritException:
+ Enabled: false
+
+Lint/SafeNavigationChain:
+ Enabled: false
+
+Lint/ElseLayout:
+ Exclude:
+ - 'language/if_spec.rb'
+
Lint/EmptyExpression:
Exclude:
- 'language/**/*.rb'
@@ -71,6 +119,10 @@ Lint/EmptyWhen:
- language/case_spec.rb
- optional/capi/spec_helper.rb
+Lint/ErbNewArguments:
+ Exclude:
+ - 'library/erb/new_spec.rb'
+
Lint/FormatParameterMismatch:
Exclude:
- 'core/kernel/shared/sprintf.rb'
@@ -117,6 +169,9 @@ Lint/Debugger:
Lint/Loop:
Enabled: false
+Style/BlockComments:
+ Enabled: true
+
Style/Lambda:
Enabled: true
EnforcedStyle: literal
diff --git a/spec/ruby/.rubocop_todo.yml b/spec/ruby/.rubocop_todo.yml
index a469213841..3ebb23a8bb 100644
--- a/spec/ruby/.rubocop_todo.yml
+++ b/spec/ruby/.rubocop_todo.yml
@@ -50,17 +50,6 @@ Lint/IneffectiveAccessModifier:
- 'core/module/fixtures/classes.rb'
- 'language/fixtures/private.rb'
-# Offense count: 6
-# Cop supports --auto-correct.
-# Configuration parameters: EnforcedStyle.
-# SupportedStyles: runtime_error, standard_error
-Lint/InheritException:
- Exclude:
- - 'core/enumerator/lazy/fixtures/classes.rb'
- - 'core/exception/fixtures/common.rb'
- - 'core/module/fixtures/autoload_ex1.rb'
- - 'shared/kernel/raise.rb'
-
# Offense count: 72
# Cop supports --auto-correct.
Lint/LiteralInInterpolation:
@@ -74,7 +63,6 @@ Lint/LiteralInInterpolation:
- 'language/string_spec.rb'
- 'language/symbol_spec.rb'
- 'language/undef_spec.rb'
- - 'library/net/ftp/connect_spec.rb'
# Offense count: 8
# Cop supports --auto-correct.
@@ -109,6 +97,7 @@ Lint/RescueException:
- 'core/dir/fileno_spec.rb'
- 'core/exception/cause_spec.rb'
- 'core/exception/no_method_error_spec.rb'
+ - 'core/fiber/kill_spec.rb'
- 'core/kernel/fixtures/autoload_frozen.rb'
- 'core/kernel/raise_spec.rb'
- 'core/module/autoload_spec.rb'
diff --git a/spec/ruby/CONTRIBUTING.md b/spec/ruby/CONTRIBUTING.md
index 30941677e0..c82eb5ea4f 100644
--- a/spec/ruby/CONTRIBUTING.md
+++ b/spec/ruby/CONTRIBUTING.md
@@ -13,12 +13,14 @@ Spec are grouped in 5 separate top-level groups:
* `optional/capi`: for functions available to the Ruby C-extension API
The exact file for methods is decided by the `#owner` of a method, for instance for `#group_by`:
+
```ruby
> [].method(:group_by)
=> #<Method: Array(Enumerable)#group_by>
> [].method(:group_by).owner
=> Enumerable
```
+
Which should therefore be specified in `core/enumerable/group_by_spec.rb`.
### MkSpec - a tool to generate the spec structure
@@ -136,12 +138,12 @@ Here is a list of the most commonly-used guards:
#### Version guards
```ruby
-ruby_version_is ""..."2.6" do
- # Specs for RUBY_VERSION < 2.6
+ruby_version_is ""..."3.2" do
+ # Specs for RUBY_VERSION < 3.2
end
-ruby_version_is "2.6" do
- # Specs for RUBY_VERSION >= 2.6
+ruby_version_is "3.2" do
+ # Specs for RUBY_VERSION >= 3.2
end
```
@@ -173,12 +175,14 @@ end
#### Guard for bug
-In case there is a bug in MRI but the expected behavior is obvious.
+In case there is a bug in MRI and the fix will be backported to previous versions.
+If it is not backported or not likely, use `ruby_version_is` instead.
First, file a bug at https://bugs.ruby-lang.org/.
-It is better to use a `ruby_version_is` guard if there was a release with the fix.
+The problem is `ruby_bug` would make non-MRI implementations fail this spec while MRI itself does not pass it, so it should only be used if the bug is/will be fixed and backported.
+Otherwise, non-MRI implementations would have to choose between being incompatible with the latest release of MRI to pass the spec or fail the spec, both which make no sense.
```ruby
-ruby_bug '#13669', ''...'2.7' do
+ruby_bug '#13669', ''...'3.2' do
it "works like this" do
# Specify the expected behavior here, not the bug
end
@@ -188,11 +192,11 @@ end
#### Combining guards
```ruby
-guard -> { platform_is :windows and ruby_version_is ""..."2.6" } do
- # Windows and RUBY_VERSION < 2.6
+guard -> { platform_is :windows and ruby_version_is ""..."3.2" } do
+ # Windows and RUBY_VERSION < 3.2
end
-guard_not -> { platform_is :windows and ruby_version_is ""..."2.6" } do
+guard_not -> { platform_is :windows and ruby_version_is ""..."3.2" } do
# The opposite
end
```
@@ -220,7 +224,7 @@ If an implementation does not support some feature, simply tag the related specs
### Shared Specs
Often throughout Ruby, identical functionality is used by different methods and modules. In order
-to avoid duplication of specs, we have shared specs that are re-used in other specs. The use is a
+to avoid duplication of specs, we have shared specs that are re-used in other specs. The use is a
bit tricky however, so let's go over it.
Commonly, if a shared spec is only reused within its own module, the shared spec will live within a
@@ -232,7 +236,7 @@ An example of this is the `shared/file/socket.rb` which is used by `core/file/so
`core/filetest/socket_spec.rb`, and `core/file/state/socket_spec.rb` and so it lives in the root `shared/`.
Defining a shared spec involves adding a `shared: true` option to the top-level `describe` block. This
-will signal not to run the specs directly by the runner. Shared specs have access to two instance
+will signal not to run the specs directly by the runner. Shared specs have access to two instance
variables from the implementor spec: `@method` and `@object`, which the implementor spec will pass in.
Here's an example of a snippet of a shared spec and two specs which integrates it:
@@ -257,12 +261,12 @@ end
```
In the example, the first `describe` defines the shared spec `:hash_key_p`, which defines a spec that
-calls the `@method` method with an expectation. In the implementor spec, we use `it_behaves_like` to
-integrate the shared spec. `it_behaves_like` takes 3 parameters: the key of the shared spec, a method,
-and an object. These last two parameters are accessible via `@method` and `@object` in the shared spec.
+calls the `@method` method with an expectation. In the implementor spec, we use `it_behaves_like` to
+integrate the shared spec. `it_behaves_like` takes 3 parameters: the key of the shared spec, a method,
+and an object. These last two parameters are accessible via `@method` and `@object` in the shared spec.
Sometimes, shared specs require more context from the implementor class than a simple object. We can address
-this by passing a lambda as the method, which will have the scope of the implementor. Here's an example of
+this by passing a lambda as the method, which will have the scope of the implementor. Here's an example of
how this is used currently:
```ruby
diff --git a/spec/ruby/README.md b/spec/ruby/README.md
index e62ddc7dce..115392835f 100644
--- a/spec/ruby/README.md
+++ b/spec/ruby/README.md
@@ -1,7 +1,6 @@
# The Ruby Spec Suite
[![Actions Build Status](https://github.com/ruby/spec/workflows/CI/badge.svg)](https://github.com/ruby/spec/actions)
-[![Gitter](https://badges.gitter.im/ruby/spec.svg)](https://gitter.im/ruby/spec)
The Ruby Spec Suite, abbreviated `ruby/spec`, is a test suite for the behavior of the Ruby programming language.
@@ -18,20 +17,21 @@ Every example code has a textual description, which presents several advantages:
The specs are written with syntax similar to RSpec 2.
They are run with MSpec, the purpose-built framework for running the Ruby Spec Suite.
-For more information, see the [MSpec](http://github.com/ruby/mspec) project.
+For more information, see the [MSpec](https://github.com/ruby/mspec) project.
The specs describe the [language syntax](language/), the [core library](core/), the [standard library](library/), the [C API for extensions](optional/capi) and the [command line flags](command_line/).
The language specs are grouped by keyword while the core and standard library specs are grouped by class and method.
ruby/spec is known to be tested in these implementations for every commit:
-* [MRI](http://rubyci.org/) on 30 platforms and 4 versions
+
+* [MRI](https://rubyci.org/) on 30 platforms and 4 versions
* [JRuby](https://github.com/jruby/jruby/tree/master/spec/ruby) for both 1.7 and 9.x
* [TruffleRuby](https://github.com/oracle/truffleruby/tree/master/spec/ruby)
* [Opal](https://github.com/opal/opal/tree/master/spec)
* [Artichoke](https://github.com/artichoke/spec/tree/artichoke-vendor)
-ruby/spec describes the behavior of Ruby 2.6 and more recent Ruby versions.
-More precisely, every latest stable MRI release should [pass](https://github.com/ruby/spec/actions/workflows/ci.yml) all specs of ruby/spec (2.6.x, 2.7.x, 3.0.x, etc), and those are tested in CI.
+ruby/spec describes the behavior of Ruby 3.0 and more recent Ruby versions.
+More precisely, every latest stable MRI release should [pass](https://github.com/ruby/spec/actions/workflows/ci.yml) all specs of ruby/spec (3.0.x, 3.1.x, 3.2.x, etc), and those are tested in CI.
### Synchronization with Ruby Implementations
@@ -53,12 +53,15 @@ $ ../mspec/bin/mspec
### Specs for old Ruby versions
For older specs try these commits:
+
* Ruby 2.0.0-p647 - [Suite](https://github.com/ruby/spec/commit/245862558761d5abc676843ef74f86c9bcc8ea8d) using [MSpec](https://github.com/ruby/mspec/commit/f90efa068791064f955de7a843e96e2d7d3041c2) (may encounter 2 failures)
* Ruby 2.1.9 - [Suite](https://github.com/ruby/spec/commit/f029e65241374386077ac500add557ae65069b55) using [MSpec](https://github.com/ruby/mspec/commit/55568ea3918c6380e64db8c567d732fa5781efed)
* Ruby 2.2.10 - [Suite](https://github.com/ruby/spec/commit/cbaa0e412270c944df0c2532fc500c920dba0e92) using [MSpec](https://github.com/ruby/mspec/commit/d84d7668449e96856c5f6bac8cb1526b6d357ce3)
* Ruby 2.3.8 - [Suite](https://github.com/ruby/spec/commit/dc733114d8ae66a3368ba3a98422c50147a76ba5) using [MSpec](https://github.com/ruby/mspec/commit/4599bc195fb109f2a482a01c32a7d659518369ea)
* Ruby 2.4.10 - [Suite](https://github.com/ruby/spec/commit/bce4f2b81d6c31db67cf4d023a0625ceadde59bd) using [MSpec](https://github.com/ruby/mspec/commit/e7eb8aa4c26495b7b461e687d950b96eb08b3ff2)
* Ruby 2.5.9 - [Suite](https://github.com/ruby/spec/commit/c503335d3d9f6ec6ef24de60a0716c34af69b64f) using [MSpec](https://github.com/ruby/mspec/commit/0091e8a62e954717cd54641f935eaf1403692041)
+* Ruby 2.6.10 - [Suite](https://github.com/ruby/spec/commit/aaf998fb8c92c4e63ad423a2e7ca6e6921818c6e) using [MSpec](https://github.com/ruby/mspec/commit/5e36c684e9e2b92b1187589bba1df22c640a8661)
+* Ruby 2.7.8 - [Suite](https://github.com/ruby/spec/commit/93787e6035c925b593a9c0c6fb0e7e07a6f1df1f) using [MSpec](https://github.com/ruby/mspec/commit/1d8cf64722d8a7529f7cd205be5f16a89b7a67fd)
### Running the specs
@@ -70,7 +73,7 @@ Then move to it:
$ cd spec
-Clone [MSpec](http://github.com/ruby/mspec):
+Clone [MSpec](https://github.com/ruby/mspec):
$ git clone https://github.com/ruby/mspec.git ../mspec
@@ -125,6 +128,12 @@ MSpec can automatically add new top-level constants in this file with:
$ CHECK_LEAKS=save mspec ../mspec/bin/mspec file
+### Running Specs on S390x CPU Architecture
+
+Run the specs with `DFLTCC=0` if you see failing specs related to the zlib library on s390x CPU architecture. The failures can happen with the zlib library applying the patch madler/zlib#410 to enable the deflate algorithm producing a different compressed byte stream.
+
+ $ DFLTCC=0 ../mspec/bin/mspec
+
### Contributing and Writing Specs
See [CONTRIBUTING.md](https://github.com/ruby/spec/blob/master/CONTRIBUTING.md) for documentation about contributing and writing specs (guards, matchers, etc).
@@ -141,10 +150,9 @@ The file `/etc/services` is required for socket specs (package `netbase` on Debi
### Socket specs from rubysl-socket
-Most specs under `library/socket` were imported from [the rubysl-socket project](https://github.com/rubysl/rubysl-socket).
+Most specs under `library/socket` were imported from the rubysl-socket project (which is no longer on GitHub).
The 3 copyright holders of rubysl-socket, Yorick Peterse, Chuck Remes and
-Brian Shirai, [agreed to relicense those specs](https://github.com/rubysl/rubysl-socket/issues/15)
-under the MIT license in ruby/spec.
+Brian Shirai, agreed to relicense those specs under the MIT license in ruby/spec.
### History and RubySpec
@@ -152,5 +160,5 @@ This project was originally born from [Rubinius](https://github.com/rubinius/rub
The revision history of these specs is available [here](https://github.com/ruby/spec/blob/2b886623/CHANGES.before-2008-05-10).
These specs were later extracted to their own project, RubySpec, with a specific vision and principles.
At the end of 2014, Brian Shirai, the creator of RubySpec, decided to [end RubySpec](http://rubinius.com/2014/12/31/matz-s-ruby-developers-don-t-use-rubyspec/).
-A couple months later, the different repositories were merged and [the project was revived](http://eregon.github.io/rubyspec/2015/07/29/rubyspec-is-reborn.html).
+A couple months later, the different repositories were merged and [the project was revived](https://eregon.github.io/rubyspec/2015/07/29/rubyspec-is-reborn.html).
On 12 January 2016, the name was changed to "The Ruby Spec Suite" for clarity and to let the RubySpec ideology rest in peace.
diff --git a/spec/ruby/command_line/backtrace_limit_spec.rb b/spec/ruby/command_line/backtrace_limit_spec.rb
index 56afa8efef..4d57bc268b 100644
--- a/spec/ruby/command_line/backtrace_limit_spec.rb
+++ b/spec/ruby/command_line/backtrace_limit_spec.rb
@@ -1,7 +1,7 @@
require_relative '../spec_helper'
-ruby_version_is "3.0" do
- describe "The --backtrace-limit command line option" do
+describe "The --backtrace-limit command line option" do
+ ruby_version_is ""..."3.4" do
it "limits top-level backtraces to a given number of entries" do
file = fixture(__FILE__ , "backtrace.rb")
out = ruby_exe(file, options: "--backtrace-limit=2", args: "top 2>&1", exit_status: 1)
@@ -45,4 +45,49 @@ backtrace
MSG
end
end
+
+ ruby_version_is "3.4" do
+ it "limits top-level backtraces to a given number of entries" do
+ file = fixture(__FILE__ , "backtrace.rb")
+ out = ruby_exe(file, options: "--backtrace-limit=2", args: "top 2>&1", exit_status: 1)
+ out = out.gsub(__dir__, '')
+
+ out.should == <<-MSG
+top
+/fixtures/backtrace.rb:2:in 'Object#a': oops (RuntimeError)
+\tfrom /fixtures/backtrace.rb:6:in 'Object#b'
+\tfrom /fixtures/backtrace.rb:10:in 'Object#c'
+\t ... 2 levels...
+ MSG
+ end
+
+ it "affects Exception#full_message" do
+ file = fixture(__FILE__ , "backtrace.rb")
+ out = ruby_exe(file, options: "--backtrace-limit=2", args: "full_message 2>&1")
+ out = out.gsub(__dir__, '')
+
+ out.should == <<-MSG
+full_message
+/fixtures/backtrace.rb:2:in 'Object#a': oops (RuntimeError)
+\tfrom /fixtures/backtrace.rb:6:in 'Object#b'
+\tfrom /fixtures/backtrace.rb:10:in 'Object#c'
+\t ... 2 levels...
+ MSG
+ end
+
+ it "does not affect Exception#backtrace" do
+ file = fixture(__FILE__ , "backtrace.rb")
+ out = ruby_exe(file, options: "--backtrace-limit=2", args: "backtrace 2>&1")
+ out = out.gsub(__dir__, '')
+
+ out.should == <<-MSG
+backtrace
+/fixtures/backtrace.rb:2:in 'Object#a'
+/fixtures/backtrace.rb:6:in 'Object#b'
+/fixtures/backtrace.rb:10:in 'Object#c'
+/fixtures/backtrace.rb:14:in 'Object#d'
+/fixtures/backtrace.rb:29:in '<main>'
+ MSG
+ end
+ end
end
diff --git a/spec/ruby/command_line/dash_a_spec.rb b/spec/ruby/command_line/dash_a_spec.rb
index 9ea135dc76..43d923ce16 100644
--- a/spec/ruby/command_line/dash_a_spec.rb
+++ b/spec/ruby/command_line/dash_a_spec.rb
@@ -6,13 +6,13 @@ describe "The -a command line option" do
end
it "runs the code in loop conditional on Kernel.gets()" do
- ruby_exe("puts $F.last", options: "-n -a", escape: true,
+ ruby_exe("puts $F.last", options: "-n -a",
args: " < #{@names}").should ==
"jones\nfield\ngrey\n"
end
it "sets $-a" do
- ruby_exe("puts $-a", options: "-n -a", escape: true,
+ ruby_exe("puts $-a", options: "-n -a",
args: " < #{@names}").should ==
"true\ntrue\ntrue\n"
end
diff --git a/spec/ruby/command_line/dash_l_spec.rb b/spec/ruby/command_line/dash_l_spec.rb
index 5c1d3cf4cd..44a98445f3 100644
--- a/spec/ruby/command_line/dash_l_spec.rb
+++ b/spec/ruby/command_line/dash_l_spec.rb
@@ -6,25 +6,25 @@ describe "The -l command line option" do
end
it "chomps lines with default separator" do
- ruby_exe('puts $_.end_with?("\n")', options: "-n -l", escape: true,
+ ruby_exe('puts $_.end_with?("\n")', options: "-n -l",
args: " < #{@names}").should ==
"false\nfalse\nfalse\n"
end
it "chomps last line based on $/" do
- ruby_exe('BEGIN { $/ = "ones\n" }; puts $_', options: "-W0 -n -l", escape: true,
+ ruby_exe('BEGIN { $/ = "ones\n" }; puts $_', options: "-W0 -n -l",
args: " < #{@names}").should ==
"alice j\nbob field\njames grey\n"
end
it "sets $\\ to the value of $/" do
- ruby_exe("puts $\\ == $/", options: "-W0 -n -l", escape: true,
+ ruby_exe("puts $\\ == $/", options: "-W0 -n -l",
args: " < #{@names}").should ==
"true\ntrue\ntrue\n"
end
it "sets $-l" do
- ruby_exe("puts $-l", options: "-n -l", escape: true,
+ ruby_exe("puts $-l", options: "-n -l",
args: " < #{@names}").should ==
"true\ntrue\ntrue\n"
end
diff --git a/spec/ruby/command_line/dash_n_spec.rb b/spec/ruby/command_line/dash_n_spec.rb
index 9d331d6065..1dd9379259 100644
--- a/spec/ruby/command_line/dash_n_spec.rb
+++ b/spec/ruby/command_line/dash_n_spec.rb
@@ -6,19 +6,19 @@ describe "The -n command line option" do
end
it "runs the code in loop conditional on Kernel.gets()" do
- ruby_exe("puts $_", options: "-n", escape: true,
+ ruby_exe("puts $_", options: "-n",
args: " < #{@names}").should ==
"alice\nbob\njames\n"
end
it "only evaluates BEGIN blocks once" do
- ruby_exe("BEGIN { puts \"hi\" }; puts $_", options: "-n", escape: true,
+ ruby_exe("BEGIN { puts \"hi\" }; puts $_", options: "-n",
args: " < #{@names}").should ==
"hi\nalice\nbob\njames\n"
end
it "only evaluates END blocks once" do
- ruby_exe("puts $_; END {puts \"bye\"}", options: "-n", escape: true,
+ ruby_exe("puts $_; END {puts \"bye\"}", options: "-n",
args: " < #{@names}").should ==
"alice\nbob\njames\nbye\n"
end
@@ -29,7 +29,7 @@ describe "The -n command line option" do
$total += 1
END { puts $total }
script
- ruby_exe(script, options: "-n", escape: true,
+ ruby_exe(script, options: "-n",
args: " < #{@names}").should ==
"3\n"
end
diff --git a/spec/ruby/command_line/dash_p_spec.rb b/spec/ruby/command_line/dash_p_spec.rb
index 39827c3868..967e3796de 100644
--- a/spec/ruby/command_line/dash_p_spec.rb
+++ b/spec/ruby/command_line/dash_p_spec.rb
@@ -6,13 +6,13 @@ describe "The -p command line option" do
end
it "runs the code in loop conditional on Kernel.gets() and prints $_" do
- ruby_exe("$_ = $_.upcase", options: "-p", escape: true,
+ ruby_exe("$_ = $_.upcase", options: "-p",
args: " < #{@names}").should ==
"ALICE\nBOB\nJAMES\n"
end
it "sets $-p" do
- ruby_exe("$_ = $-p", options: "-p", escape: true,
+ ruby_exe("$_ = $-p", options: "-p",
args: " < #{@names}").should ==
"truetruetrue"
end
diff --git a/spec/ruby/command_line/dash_r_spec.rb b/spec/ruby/command_line/dash_r_spec.rb
index ea5bde5adf..9f673c53dc 100644
--- a/spec/ruby/command_line/dash_r_spec.rb
+++ b/spec/ruby/command_line/dash_r_spec.rb
@@ -16,7 +16,10 @@ describe "The -r command line option" do
out = ruby_exe(fixture(__FILE__, "bad_syntax.rb"), options: "-r #{@test_file}", args: "2>&1", exit_status: 1)
$?.should_not.success?
out.should include("REQUIRED")
- out.should include("syntax error")
+
+ # it's tempting not to rely on error message and rely only on exception class name,
+ # but CRuby before 3.2 doesn't print class name for syntax error
+ out.should include_any_of("syntax error", "SyntaxError")
end
it "does not require the file if the main script file does not exist" do
diff --git a/spec/ruby/command_line/dash_upper_f_spec.rb b/spec/ruby/command_line/dash_upper_f_spec.rb
index 967acc2ece..5c10a7140d 100644
--- a/spec/ruby/command_line/dash_upper_f_spec.rb
+++ b/spec/ruby/command_line/dash_upper_f_spec.rb
@@ -6,7 +6,7 @@ describe "the -F command line option" do
end
it "specifies the field separator pattern for -a" do
- ruby_exe("puts $F[0]", options: "-naF:", escape: true,
+ ruby_exe("puts $F[0]", options: "-naF:",
args: " < #{@passwd}").should ==
"nobody\nroot\ndaemon\n"
end
diff --git a/spec/ruby/command_line/dash_upper_u_spec.rb b/spec/ruby/command_line/dash_upper_u_spec.rb
index d62718b095..15854e7b73 100644
--- a/spec/ruby/command_line/dash_upper_u_spec.rb
+++ b/spec/ruby/command_line/dash_upper_u_spec.rb
@@ -6,6 +6,13 @@ describe "ruby -U" do
options: '-U').should == 'UTF-8'
end
+ it "sets Encoding.default_internal to UTF-8 when RUBYOPT is empty or only spaces" do
+ ruby_exe('p Encoding.default_internal',
+ options: '-U', env: { 'RUBYOPT' => '' }).should == "#<Encoding:UTF-8>\n"
+ ruby_exe('p Encoding.default_internal',
+ options: '-U', env: { 'RUBYOPT' => ' ' }).should == "#<Encoding:UTF-8>\n"
+ end
+
it "does nothing different if specified multiple times" do
ruby_exe('print Encoding.default_internal.name',
options: '-U -U').should == 'UTF-8'
diff --git a/spec/ruby/command_line/dash_upper_w_spec.rb b/spec/ruby/command_line/dash_upper_w_spec.rb
index cbb040a8dd..4019510d42 100644
--- a/spec/ruby/command_line/dash_upper_w_spec.rb
+++ b/spec/ruby/command_line/dash_upper_w_spec.rb
@@ -19,29 +19,26 @@ describe "The -W command line option with 2" do
it_behaves_like :command_line_verbose, "-W2"
end
-# Regarding the defaults, see core/warning/element_reference_spec.rb
-ruby_version_is "2.7" do
- describe "The -W command line option with :deprecated" do
- it "enables deprecation warnings" do
- ruby_exe('p Warning[:deprecated]', options: '-W:deprecated').should == "true\n"
- end
+describe "The -W command line option with :deprecated" do
+ it "enables deprecation warnings" do
+ ruby_exe('p Warning[:deprecated]', options: '-W:deprecated').should == "true\n"
end
+end
- describe "The -W command line option with :no-deprecated" do
- it "suppresses deprecation warnings" do
- ruby_exe('p Warning[:deprecated]', options: '-w -W:no-deprecated').should == "false\n"
- end
+describe "The -W command line option with :no-deprecated" do
+ it "suppresses deprecation warnings" do
+ ruby_exe('p Warning[:deprecated]', options: '-w -W:no-deprecated').should == "false\n"
end
+end
- describe "The -W command line option with :experimental" do
- it "enables experimental warnings" do
- ruby_exe('p Warning[:experimental]', options: '-W:experimental').should == "true\n"
- end
+describe "The -W command line option with :experimental" do
+ it "enables experimental warnings" do
+ ruby_exe('p Warning[:experimental]', options: '-W:experimental').should == "true\n"
end
+end
- describe "The -W command line option with :no-experimental" do
- it "suppresses experimental warnings" do
- ruby_exe('p Warning[:experimental]', options: '-w -W:no-experimental').should == "false\n"
- end
+describe "The -W command line option with :no-experimental" do
+ it "suppresses experimental warnings" do
+ ruby_exe('p Warning[:experimental]', options: '-w -W:no-experimental').should == "false\n"
end
end
diff --git a/spec/ruby/command_line/dash_v_spec.rb b/spec/ruby/command_line/dash_v_spec.rb
index a4f4dcd051..747db7f755 100644
--- a/spec/ruby/command_line/dash_v_spec.rb
+++ b/spec/ruby/command_line/dash_v_spec.rb
@@ -6,8 +6,9 @@ describe "The -v command line option" do
describe "when used alone" do
it "prints version and ends" do
- ruby_exe(nil, args: '-v').should include(RUBY_DESCRIPTION)
+ ruby_exe(nil, args: '-v').sub("+PRISM ", "").should include(RUBY_DESCRIPTION.sub("+PRISM ", ""))
end unless (defined?(RubyVM::YJIT) && RubyVM::YJIT.enabled?) ||
- (defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled?)
+ (defined?(RubyVM::RJIT) && RubyVM::RJIT.enabled?) ||
+ (ENV['RUBY_MN_THREADS'] == '1')
end
end
diff --git a/spec/ruby/command_line/dash_w_spec.rb b/spec/ruby/command_line/dash_w_spec.rb
index c262df12cc..f310dca3ed 100644
--- a/spec/ruby/command_line/dash_w_spec.rb
+++ b/spec/ruby/command_line/dash_w_spec.rb
@@ -4,9 +4,7 @@ require_relative 'shared/verbose'
describe "The -w command line option" do
it_behaves_like :command_line_verbose, "-w"
- ruby_version_is "2.7" do
- it "enables both deprecated and experimental warnings" do
- ruby_exe('p Warning[:deprecated]; p Warning[:experimental]', options: '-w').should == "true\ntrue\n"
- end
+ it "enables both deprecated and experimental warnings" do
+ ruby_exe('p Warning[:deprecated]; p Warning[:experimental]', options: '-w').should == "true\ntrue\n"
end
end
diff --git a/spec/ruby/command_line/fixtures/bin/embedded_ruby.txt b/spec/ruby/command_line/fixtures/bin/embedded_ruby.txt
index c556bf0b71..1da779b1b9 100644
--- a/spec/ruby/command_line/fixtures/bin/embedded_ruby.txt
+++ b/spec/ruby/command_line/fixtures/bin/embedded_ruby.txt
@@ -1,3 +1,3 @@
@@@This line is not value Ruby
#!ruby
-puts 'success' \ No newline at end of file
+puts 'success'
diff --git a/spec/ruby/command_line/fixtures/freeze_flag_required_diff_enc.rb b/spec/ruby/command_line/fixtures/freeze_flag_required_diff_enc.rb
index fa348d59e7..df4b952c46 100644
--- a/spec/ruby/command_line/fixtures/freeze_flag_required_diff_enc.rb
+++ b/spec/ruby/command_line/fixtures/freeze_flag_required_diff_enc.rb
Binary files differ
diff --git a/spec/ruby/command_line/fixtures/freeze_flag_two_literals.rb b/spec/ruby/command_line/fixtures/freeze_flag_two_literals.rb
index 074092c9d9..f5547a5bae 100644
--- a/spec/ruby/command_line/fixtures/freeze_flag_two_literals.rb
+++ b/spec/ruby/command_line/fixtures/freeze_flag_two_literals.rb
@@ -1 +1 @@
-p "abc".object_id == "abc".object_id
+p "abc".equal?("abc")
diff --git a/spec/ruby/command_line/fixtures/string_literal_frozen_comment.rb b/spec/ruby/command_line/fixtures/string_literal_frozen_comment.rb
new file mode 100644
index 0000000000..fb84b546c0
--- /dev/null
+++ b/spec/ruby/command_line/fixtures/string_literal_frozen_comment.rb
@@ -0,0 +1,4 @@
+# frozen_string_literal: true
+frozen = "test".frozen?
+interned = "test".equal?("test")
+puts "frozen:#{frozen} interned:#{interned}"
diff --git a/spec/ruby/command_line/fixtures/string_literal_mutable_comment.rb b/spec/ruby/command_line/fixtures/string_literal_mutable_comment.rb
new file mode 100644
index 0000000000..381a742001
--- /dev/null
+++ b/spec/ruby/command_line/fixtures/string_literal_mutable_comment.rb
@@ -0,0 +1,4 @@
+# frozen_string_literal: false
+frozen = "test".frozen?
+interned = "test".equal?("test")
+puts "frozen:#{frozen} interned:#{interned}"
diff --git a/spec/ruby/command_line/fixtures/string_literal_raw.rb b/spec/ruby/command_line/fixtures/string_literal_raw.rb
new file mode 100644
index 0000000000..56b1841296
--- /dev/null
+++ b/spec/ruby/command_line/fixtures/string_literal_raw.rb
@@ -0,0 +1,3 @@
+frozen = "test".frozen?
+interned = "test".equal?("test")
+puts "frozen:#{frozen} interned:#{interned}"
diff --git a/spec/ruby/command_line/frozen_strings_spec.rb b/spec/ruby/command_line/frozen_strings_spec.rb
index 647b69daed..334b98273b 100644
--- a/spec/ruby/command_line/frozen_strings_spec.rb
+++ b/spec/ruby/command_line/frozen_strings_spec.rb
@@ -19,6 +19,50 @@ describe "The --enable-frozen-string-literal flag causes string literals to" do
end
end
+describe "The --disable-frozen-string-literal flag causes string literals to" do
+
+ it "produce a different object each time" do
+ ruby_exe(fixture(__FILE__, "freeze_flag_one_literal.rb"), options: "--disable-frozen-string-literal").chomp.should == "false"
+ end
+
+end
+
+describe "With neither --enable-frozen-string-literal nor --disable-frozen-string-literal flag set" do
+ before do
+ # disable --enable-frozen-string-literal and --disable-frozen-string-literal passed in $RUBYOPT
+ @rubyopt = ENV["RUBYOPT"]
+ ENV["RUBYOPT"] = ""
+ end
+
+ after do
+ ENV["RUBYOPT"] = @rubyopt
+ end
+
+ it "produce a different object each time" do
+ ruby_exe(fixture(__FILE__, "freeze_flag_one_literal.rb")).chomp.should == "false"
+ end
+
+ ruby_version_is "3.4" do
+ it "if file has no frozen_string_literal comment produce different frozen strings each time" do
+ ruby_exe(fixture(__FILE__, "string_literal_raw.rb")).chomp.should == "frozen:true interned:false"
+ end
+ end
+
+ ruby_version_is ""..."3.4" do
+ it "if file has no frozen_string_literal comment produce different mutable strings each time" do
+ ruby_exe(fixture(__FILE__, "string_literal_raw.rb")).chomp.should == "frozen:false interned:false"
+ end
+ end
+
+ it "if file has frozen_string_literal:true comment produce same frozen strings each time" do
+ ruby_exe(fixture(__FILE__, "string_literal_frozen_comment.rb")).chomp.should == "frozen:true interned:true"
+ end
+
+ it "if file has frozen_string_literal:false comment produce different mutable strings each time" do
+ ruby_exe(fixture(__FILE__, "string_literal_mutable_comment.rb")).chomp.should == "frozen:false interned:false"
+ end
+end
+
describe "The --debug flag produces" do
it "debugging info on attempted frozen string modification" do
error_str = ruby_exe(fixture(__FILE__, 'debug_info.rb'), options: '--debug', args: "2>&1")
diff --git a/spec/ruby/command_line/rubyopt_spec.rb b/spec/ruby/command_line/rubyopt_spec.rb
index a2b817bad8..18a5959b18 100644
--- a/spec/ruby/command_line/rubyopt_spec.rb
+++ b/spec/ruby/command_line/rubyopt_spec.rb
@@ -11,72 +11,70 @@ describe "Processing RUBYOPT" do
it "adds the -I path to $LOAD_PATH" do
ENV["RUBYOPT"] = "-Ioptrubyspecincl"
- result = ruby_exe("puts $LOAD_PATH.grep(/byspecin/)", escape: true)
+ result = ruby_exe("puts $LOAD_PATH.grep(/byspecin/)")
result.chomp[-15..-1].should == "optrubyspecincl"
end
it "sets $DEBUG to true for '-d'" do
ENV["RUBYOPT"] = '-d'
command = %[puts "value of $DEBUG is \#{$DEBUG}"]
- result = ruby_exe(command, escape: true, args: "2>&1")
+ result = ruby_exe(command, args: "2>&1")
result.should =~ /value of \$DEBUG is true/
end
guard -> { not CROSS_COMPILING } do
it "prints the version number for '-v'" do
ENV["RUBYOPT"] = '-v'
- ruby_exe("")[/\A.*/].should == RUBY_DESCRIPTION
+ ruby_exe("")[/\A.*/].should == RUBY_DESCRIPTION.sub("+PRISM ", "")
end
it "ignores whitespace around the option" do
ENV["RUBYOPT"] = ' -v '
- ruby_exe("")[/\A.*/].should == RUBY_DESCRIPTION
+ ruby_exe("")[/\A.*/].should == RUBY_DESCRIPTION.sub("+PRISM ", "")
end
end
it "sets $VERBOSE to true for '-w'" do
ENV["RUBYOPT"] = '-w'
- ruby_exe("p $VERBOSE", escape: true).chomp.should == "true"
+ ruby_exe("p $VERBOSE").chomp.should == "true"
end
it "sets $VERBOSE to true for '-W'" do
ENV["RUBYOPT"] = '-W'
- ruby_exe("p $VERBOSE", escape: true).chomp.should == "true"
+ ruby_exe("p $VERBOSE").chomp.should == "true"
end
it "sets $VERBOSE to nil for '-W0'" do
ENV["RUBYOPT"] = '-W0'
- ruby_exe("p $VERBOSE", escape: true).chomp.should == "nil"
+ ruby_exe("p $VERBOSE").chomp.should == "nil"
end
it "sets $VERBOSE to false for '-W1'" do
ENV["RUBYOPT"] = '-W1'
- ruby_exe("p $VERBOSE", escape: true).chomp.should == "false"
+ ruby_exe("p $VERBOSE").chomp.should == "false"
end
it "sets $VERBOSE to true for '-W2'" do
ENV["RUBYOPT"] = '-W2'
- ruby_exe("p $VERBOSE", escape: true).chomp.should == "true"
+ ruby_exe("p $VERBOSE").chomp.should == "true"
end
- ruby_version_is "2.7" do
- it "suppresses deprecation warnings for '-W:no-deprecated'" do
- ENV["RUBYOPT"] = '-W:no-deprecated'
- result = ruby_exe('$; = ""', args: '2>&1')
- result.should == ""
- end
+ it "suppresses deprecation warnings for '-W:no-deprecated'" do
+ ENV["RUBYOPT"] = '-W:no-deprecated'
+ result = ruby_exe('$; = ""', args: '2>&1')
+ result.should == ""
+ end
- it "suppresses experimental warnings for '-W:no-experimental'" do
- ENV["RUBYOPT"] = '-W:no-experimental'
- result = ruby_exe('case 0; in a; end', args: '2>&1')
- result.should == ""
- end
+ it "suppresses experimental warnings for '-W:no-experimental'" do
+ ENV["RUBYOPT"] = '-W:no-experimental'
+ result = ruby_exe('case 0; in a; end', args: '2>&1')
+ result.should == ""
+ end
- it "suppresses deprecation and experimental warnings for '-W:no-deprecated -W:no-experimental'" do
- ENV["RUBYOPT"] = '-W:no-deprecated -W:no-experimental'
- result = ruby_exe('case ($; = ""); in a; end', args: '2>&1')
- result.should == ""
- end
+ it "suppresses deprecation and experimental warnings for '-W:no-deprecated -W:no-experimental'" do
+ ENV["RUBYOPT"] = '-W:no-deprecated -W:no-experimental'
+ result = ruby_exe('case ($; = ""); in a; end', args: '2>&1')
+ result.should == ""
end
it "requires the file for '-r'" do
diff --git a/spec/ruby/command_line/syntax_error_spec.rb b/spec/ruby/command_line/syntax_error_spec.rb
index 444ea9635c..9ba87b9e22 100644
--- a/spec/ruby/command_line/syntax_error_spec.rb
+++ b/spec/ruby/command_line/syntax_error_spec.rb
@@ -3,11 +3,17 @@ require_relative '../spec_helper'
describe "The interpreter" do
it "prints an error when given a file with invalid syntax" do
out = ruby_exe(fixture(__FILE__, "bad_syntax.rb"), args: "2>&1", exit_status: 1)
- out.should include "syntax error"
+
+ # it's tempting not to rely on error message and rely only on exception class name,
+ # but CRuby before 3.2 doesn't print class name for syntax error
+ out.should include_any_of("syntax error", "SyntaxError")
end
it "prints an error when given code via -e with invalid syntax" do
out = ruby_exe(nil, args: "-e 'a{' 2>&1", exit_status: 1)
- out.should include "syntax error"
+
+ # it's tempting not to rely on error message and rely only on exception class name,
+ # but CRuby before 3.2 doesn't print class name for syntax error
+ out.should include_any_of("syntax error", "SyntaxError")
end
end
diff --git a/spec/ruby/core/argf/bytes_spec.rb b/spec/ruby/core/argf/bytes_spec.rb
deleted file mode 100644
index bf35ded1db..0000000000
--- a/spec/ruby/core/argf/bytes_spec.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'shared/each_byte'
-
-ruby_version_is ''...'3.0' do
- describe "ARGF.bytes" do
- before :each do
- @verbose, $VERBOSE = $VERBOSE, nil
- end
-
- after :each do
- $VERBOSE = @verbose
- end
-
- it_behaves_like :argf_each_byte, :bytes
- end
-end
diff --git a/spec/ruby/core/argf/chars_spec.rb b/spec/ruby/core/argf/chars_spec.rb
deleted file mode 100644
index 6af73cdabb..0000000000
--- a/spec/ruby/core/argf/chars_spec.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'shared/each_char'
-
-ruby_version_is ''...'3.0' do
- describe "ARGF.chars" do
- before :each do
- @verbose, $VERBOSE = $VERBOSE, nil
- end
-
- after :each do
- $VERBOSE = @verbose
- end
-
- it_behaves_like :argf_each_char, :chars
- end
-end
diff --git a/spec/ruby/core/argf/codepoints_spec.rb b/spec/ruby/core/argf/codepoints_spec.rb
deleted file mode 100644
index bb28c17fbb..0000000000
--- a/spec/ruby/core/argf/codepoints_spec.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'shared/each_codepoint'
-
-ruby_version_is ''...'3.0' do
- describe "ARGF.codepoints" do
- before :each do
- @verbose, $VERBOSE = $VERBOSE, nil
- end
-
- after :each do
- $VERBOSE = @verbose
- end
-
- it_behaves_like :argf_each_codepoint, :codepoints
- end
-end
diff --git a/spec/ruby/core/argf/lines_spec.rb b/spec/ruby/core/argf/lines_spec.rb
deleted file mode 100644
index e964dbd0d3..0000000000
--- a/spec/ruby/core/argf/lines_spec.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'shared/each_line'
-
-ruby_version_is ''...'3.0' do
- describe "ARGF.lines" do
- before :each do
- @verbose, $VERBOSE = $VERBOSE, nil
- end
-
- after :each do
- $VERBOSE = @verbose
- end
-
- it_behaves_like :argf_each_line, :lines
- end
-end
diff --git a/spec/ruby/core/argf/readpartial_spec.rb b/spec/ruby/core/argf/readpartial_spec.rb
index 5e284b3423..ea4301f25c 100644
--- a/spec/ruby/core/argf/readpartial_spec.rb
+++ b/spec/ruby/core/argf/readpartial_spec.rb
@@ -29,7 +29,7 @@ describe "ARGF.readpartial" do
it "clears output buffer even if EOFError is raised because @argf is at end" do
begin
- output = "to be cleared"
+ output = +"to be cleared"
argf [@file1_name] do
@argf.read
@@ -69,7 +69,7 @@ describe "ARGF.readpartial" do
print ARGF.readpartial(#{@stdin.size})
ARGF.readpartial(1) rescue print $!.class
STR
- stdin = ruby_exe(ruby_str, args: "< #{@stdin_name}", escape: true)
+ stdin = ruby_exe(ruby_str, args: "< #{@stdin_name}")
stdin.should == @stdin + "EOFError"
end
end
diff --git a/spec/ruby/core/argf/shared/getc.rb b/spec/ruby/core/argf/shared/getc.rb
index 8be39c60b6..d63372d9d7 100644
--- a/spec/ruby/core/argf/shared/getc.rb
+++ b/spec/ruby/core/argf/shared/getc.rb
@@ -9,7 +9,7 @@ describe :argf_getc, shared: true do
it "reads each char of files" do
argf [@file1, @file2] do
- chars = ""
+ chars = +""
@chars.size.times { chars << @argf.send(@method) }
chars.should == @chars
end
diff --git a/spec/ruby/core/argf/shared/read.rb b/spec/ruby/core/argf/shared/read.rb
index fe903983c0..e76d022139 100644
--- a/spec/ruby/core/argf/shared/read.rb
+++ b/spec/ruby/core/argf/shared/read.rb
@@ -15,7 +15,7 @@ describe :argf_read, shared: true do
it "treats second argument as an output buffer" do
argf [@file1_name] do
- buffer = ""
+ buffer = +""
@argf.send(@method, @file1.size, buffer)
buffer.should == @file1
end
@@ -23,7 +23,7 @@ describe :argf_read, shared: true do
it "clears output buffer before appending to it" do
argf [@file1_name] do
- buffer = "to be cleared"
+ buffer = +"to be cleared"
@argf.send(@method, @file1.size, buffer)
buffer.should == @file1
end
diff --git a/spec/ruby/core/array/all_spec.rb b/spec/ruby/core/array/all_spec.rb
new file mode 100644
index 0000000000..680e8c26fa
--- /dev/null
+++ b/spec/ruby/core/array/all_spec.rb
@@ -0,0 +1,13 @@
+require_relative '../../spec_helper'
+require_relative 'shared/iterable_and_tolerating_size_increasing'
+
+describe "Array#all?" do
+ @value_to_return = -> _ { true }
+ it_behaves_like :array_iterable_and_tolerating_size_increasing, :all?
+
+ it "ignores the block if there is an argument" do
+ -> {
+ ['bar', 'foobar'].all?(/bar/) { false }.should == true
+ }.should complain(/given block not used/)
+ end
+end
diff --git a/spec/ruby/core/array/any_spec.rb b/spec/ruby/core/array/any_spec.rb
index 09d949fe6e..b51ce62f0f 100644
--- a/spec/ruby/core/array/any_spec.rb
+++ b/spec/ruby/core/array/any_spec.rb
@@ -1,4 +1,5 @@
require_relative '../../spec_helper'
+require_relative 'shared/iterable_and_tolerating_size_increasing'
describe "Array#any?" do
describe 'with no block given (a default block of { |x| x } is implicit)' do
@@ -19,6 +20,9 @@ describe "Array#any?" do
end
describe 'with a block given' do
+ @value_to_return = -> _ { false }
+ it_behaves_like :array_iterable_and_tolerating_size_increasing, :any?
+
it 'is false if the array is empty' do
empty_array = []
empty_array.any? {|v| 1 == 1 }.should == false
@@ -34,4 +38,12 @@ describe "Array#any?" do
array_with_members.any? {|v| v == 42 }.should == false
end
end
+
+ describe 'when given a pattern argument' do
+ it "ignores the block if there is an argument" do
+ -> {
+ ['bar', 'foobar'].any?(/bar/) { false }.should == true
+ }.should complain(/given block not used/)
+ end
+ end
end
diff --git a/spec/ruby/core/array/assoc_spec.rb b/spec/ruby/core/array/assoc_spec.rb
index f8479d763c..f0be3de795 100644
--- a/spec/ruby/core/array/assoc_spec.rb
+++ b/spec/ruby/core/array/assoc_spec.rb
@@ -6,7 +6,7 @@ describe "Array#assoc" do
s1 = ["colors", "red", "blue", "green"]
s2 = [:letters, "a", "b", "c"]
s3 = [4]
- s4 = ["colors", "cyan", "yellow", "magenda"]
+ s4 = ["colors", "cyan", "yellow", "magenta"]
s5 = [:letters, "a", "i", "u"]
s_nil = [nil, nil]
a = [s1, s2, s3, s4, s5, s_nil]
@@ -37,4 +37,16 @@ describe "Array#assoc" do
a.assoc(s1.first).should equal(s1)
a.assoc(s2.first).should equal(s2)
end
+
+ it "calls to_ary on non-array elements" do
+ s1 = [1, 2]
+ s2 = ArraySpecs::ArrayConvertible.new(2, 3)
+ a = [s1, s2]
+
+ s1.should_not_receive(:to_ary)
+ a.assoc(s1.first).should equal(s1)
+
+ a.assoc(2).should == [2, 3]
+ s2.called.should equal(:to_ary)
+ end
end
diff --git a/spec/ruby/core/array/bsearch_index_spec.rb b/spec/ruby/core/array/bsearch_index_spec.rb
index df2c7c098e..94d85b37f3 100644
--- a/spec/ruby/core/array/bsearch_index_spec.rb
+++ b/spec/ruby/core/array/bsearch_index_spec.rb
@@ -63,10 +63,6 @@ describe "Array#bsearch_index" do
@array.bsearch_index { |x| -1 }.should be_nil
end
- it "returns the middle element when block always returns zero" do
- @array.bsearch_index { |x| 0 }.should == 2
- end
-
context "magnitude does not effect the result" do
it "returns the index of any matched elements where element is between 4n <= xn < 8n" do
[1, 2].should include(@array.bsearch_index { |x| (1 - x / 4) * (2**100) })
diff --git a/spec/ruby/core/array/clear_spec.rb b/spec/ruby/core/array/clear_spec.rb
index bddc672d3b..81ba56e01e 100644
--- a/spec/ruby/core/array/clear_spec.rb
+++ b/spec/ruby/core/array/clear_spec.rb
@@ -20,30 +20,10 @@ describe "Array#clear" do
a.size.should == 0
end
- ruby_version_is ''...'2.7' do
- it "keeps tainted status" do
- a = [1]
- a.taint
- a.tainted?.should be_true
- a.clear
- a.tainted?.should be_true
- end
- end
-
it "does not accept any arguments" do
-> { [1].clear(true) }.should raise_error(ArgumentError)
end
- ruby_version_is ''...'2.7' do
- it "keeps untrusted status" do
- a = [1]
- a.untrust
- a.untrusted?.should be_true
- a.clear
- a.untrusted?.should be_true
- end
- end
-
it "raises a FrozenError on a frozen array" do
a = [1]
a.freeze
diff --git a/spec/ruby/core/array/compact_spec.rb b/spec/ruby/core/array/compact_spec.rb
index aa3c1c0446..83b3fa2a89 100644
--- a/spec/ruby/core/array/compact_spec.rb
+++ b/spec/ruby/core/array/compact_spec.rb
@@ -21,20 +21,6 @@ describe "Array#compact" do
it "does not return subclass instance for Array subclasses" do
ArraySpecs::MyArray[1, 2, 3, nil].compact.should be_an_instance_of(Array)
end
-
- ruby_version_is ''...'2.7' do
- it "does not keep tainted status even if all elements are removed" do
- a = [nil, nil]
- a.taint
- a.compact.tainted?.should be_false
- end
-
- it "does not keep untrusted status even if all elements are removed" do
- a = [nil, nil]
- a.untrust
- a.compact.untrusted?.should be_false
- end
- end
end
describe "Array#compact!" do
@@ -59,22 +45,6 @@ describe "Array#compact!" do
[1, 2, false, 3].compact!.should == nil
end
- ruby_version_is ''...'2.7' do
- it "keeps tainted status even if all elements are removed" do
- a = [nil, nil]
- a.taint
- a.compact!
- a.tainted?.should be_true
- end
-
- it "keeps untrusted status even if all elements are removed" do
- a = [nil, nil]
- a.untrust
- a.compact!
- a.untrusted?.should be_true
- end
- end
-
it "raises a FrozenError on a frozen array" do
-> { ArraySpecs.frozen_array.compact! }.should raise_error(FrozenError)
end
diff --git a/spec/ruby/core/array/concat_spec.rb b/spec/ruby/core/array/concat_spec.rb
index da6763bfd6..f3cab9c17c 100644
--- a/spec/ruby/core/array/concat_spec.rb
+++ b/spec/ruby/core/array/concat_spec.rb
@@ -41,64 +41,6 @@ describe "Array#concat" do
-> { ArraySpecs.frozen_array.concat([]) }.should raise_error(FrozenError)
end
- ruby_version_is ''...'2.7' do
- it "keeps tainted status" do
- ary = [1, 2]
- ary.taint
- ary.concat([3])
- ary.tainted?.should be_true
- ary.concat([])
- ary.tainted?.should be_true
- end
-
- it "is not infected by the other" do
- ary = [1,2]
- other = [3]; other.taint
- ary.tainted?.should be_false
- ary.concat(other)
- ary.tainted?.should be_false
- end
-
- it "keeps the tainted status of elements" do
- ary = [ Object.new, Object.new, Object.new ]
- ary.each {|x| x.taint }
-
- ary.concat([ Object.new ])
- ary[0].tainted?.should be_true
- ary[1].tainted?.should be_true
- ary[2].tainted?.should be_true
- ary[3].tainted?.should be_false
- end
-
- it "keeps untrusted status" do
- ary = [1, 2]
- ary.untrust
- ary.concat([3])
- ary.untrusted?.should be_true
- ary.concat([])
- ary.untrusted?.should be_true
- end
-
- it "is not infected untrustedness by the other" do
- ary = [1,2]
- other = [3]; other.untrust
- ary.untrusted?.should be_false
- ary.concat(other)
- ary.untrusted?.should be_false
- end
-
- it "keeps the untrusted status of elements" do
- ary = [ Object.new, Object.new, Object.new ]
- ary.each {|x| x.untrust }
-
- ary.concat([ Object.new ])
- ary[0].untrusted?.should be_true
- ary[1].untrusted?.should be_true
- ary[2].untrusted?.should be_true
- ary[3].untrusted?.should be_false
- end
- end
-
it "appends elements to an Array with enough capacity that has been shifted" do
ary = [1, 2, 3, 4, 5]
2.times { ary.shift }
diff --git a/spec/ruby/core/array/count_spec.rb b/spec/ruby/core/array/count_spec.rb
index eaf275aeb7..e778233c16 100644
--- a/spec/ruby/core/array/count_spec.rb
+++ b/spec/ruby/core/array/count_spec.rb
@@ -1,4 +1,5 @@
require_relative '../../spec_helper'
+require_relative 'shared/iterable_and_tolerating_size_increasing'
describe "Array#count" do
it "returns the number of elements" do
@@ -12,4 +13,14 @@ describe "Array#count" do
it "returns the number of element for which the block evaluates to true" do
[:a, :b, :c].count { |s| s != :b }.should == 2
end
+
+ it "ignores the block if there is an argument" do
+ -> {
+ [:a, :b, :b, :c].count(:b) { |e| e.size > 10 }.should == 2
+ }.should complain(/given block not used/)
+ end
+
+ context "when a block argument given" do
+ it_behaves_like :array_iterable_and_tolerating_size_increasing, :count
+ end
end
diff --git a/spec/ruby/core/array/deconstruct_spec.rb b/spec/ruby/core/array/deconstruct_spec.rb
index 2b07152dfc..ad67abe47b 100644
--- a/spec/ruby/core/array/deconstruct_spec.rb
+++ b/spec/ruby/core/array/deconstruct_spec.rb
@@ -1,11 +1,9 @@
require_relative '../../spec_helper'
-ruby_version_is "2.7" do
- describe "Array#deconstruct" do
- it "returns self" do
- array = [1]
+describe "Array#deconstruct" do
+ it "returns self" do
+ array = [1]
- array.deconstruct.should equal array
- end
+ array.deconstruct.should equal array
end
end
diff --git a/spec/ruby/core/array/delete_at_spec.rb b/spec/ruby/core/array/delete_at_spec.rb
index fc225a03f1..80ec643702 100644
--- a/spec/ruby/core/array/delete_at_spec.rb
+++ b/spec/ruby/core/array/delete_at_spec.rb
@@ -38,26 +38,4 @@ describe "Array#delete_at" do
it "raises a FrozenError on a frozen array" do
-> { [1,2,3].freeze.delete_at(0) }.should raise_error(FrozenError)
end
-
- ruby_version_is ''...'2.7' do
- it "keeps tainted status" do
- ary = [1, 2]
- ary.taint
- ary.tainted?.should be_true
- ary.delete_at(0)
- ary.tainted?.should be_true
- ary.delete_at(0) # now empty
- ary.tainted?.should be_true
- end
-
- it "keeps untrusted status" do
- ary = [1, 2]
- ary.untrust
- ary.untrusted?.should be_true
- ary.delete_at(0)
- ary.untrusted?.should be_true
- ary.delete_at(0) # now empty
- ary.untrusted?.should be_true
- end
- end
end
diff --git a/spec/ruby/core/array/delete_if_spec.rb b/spec/ruby/core/array/delete_if_spec.rb
index e1931220f5..10972eee0e 100644
--- a/spec/ruby/core/array/delete_if_spec.rb
+++ b/spec/ruby/core/array/delete_if_spec.rb
@@ -2,6 +2,7 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
require_relative 'shared/enumeratorize'
require_relative 'shared/delete_if'
+require_relative 'shared/iterable_and_tolerating_size_increasing'
require_relative '../enumerable/shared/enumeratorized'
describe "Array#delete_if" do
@@ -47,22 +48,35 @@ describe "Array#delete_if" do
-> { ArraySpecs.empty_frozen_array.delete_if {} }.should raise_error(FrozenError)
end
- ruby_version_is ''...'2.7' do
- it "keeps tainted status" do
- @a.taint
- @a.tainted?.should be_true
- @a.delete_if{ true }
- @a.tainted?.should be_true
+ it "does not truncate the array is the block raises an exception" do
+ a = [1, 2, 3]
+ begin
+ a.delete_if { raise StandardError, 'Oops' }
+ rescue
end
- it "keeps untrusted status" do
- @a.untrust
- @a.untrusted?.should be_true
- @a.delete_if{ true }
- @a.untrusted?.should be_true
+ a.should == [1, 2, 3]
+ end
+
+ it "only removes elements for which the block returns true, keeping the element which raised an error." do
+ a = [1, 2, 3, 4]
+ begin
+ a.delete_if do |e|
+ case e
+ when 2 then true
+ when 3 then raise StandardError, 'Oops'
+ else false
+ end
+ end
+ rescue StandardError
end
+
+ a.should == [1, 3, 4]
end
it_behaves_like :enumeratorized_with_origin_size, :delete_if, [1,2,3]
it_behaves_like :delete_if, :delete_if
+
+ @value_to_return = -> _ { false }
+ it_behaves_like :array_iterable_and_tolerating_size_increasing, :delete_if
end
diff --git a/spec/ruby/core/array/delete_spec.rb b/spec/ruby/core/array/delete_spec.rb
index 5d53c74e47..dddbbe6bd3 100644
--- a/spec/ruby/core/array/delete_spec.rb
+++ b/spec/ruby/core/array/delete_spec.rb
@@ -43,26 +43,4 @@ describe "Array#delete" do
it "raises a FrozenError on a frozen array" do
-> { [1, 2, 3].freeze.delete(1) }.should raise_error(FrozenError)
end
-
- ruby_version_is ''...'2.7' do
- it "keeps tainted status" do
- a = [1, 2]
- a.taint
- a.tainted?.should be_true
- a.delete(2)
- a.tainted?.should be_true
- a.delete(1) # now empty
- a.tainted?.should be_true
- end
-
- it "keeps untrusted status" do
- a = [1, 2]
- a.untrust
- a.untrusted?.should be_true
- a.delete(2)
- a.untrusted?.should be_true
- a.delete(1) # now empty
- a.untrusted?.should be_true
- end
- end
end
diff --git a/spec/ruby/core/array/drop_spec.rb b/spec/ruby/core/array/drop_spec.rb
index f911fd9018..0ea748e47d 100644
--- a/spec/ruby/core/array/drop_spec.rb
+++ b/spec/ruby/core/array/drop_spec.rb
@@ -50,15 +50,7 @@ describe "Array#drop" do
-> { [1, 2].drop(obj) }.should raise_error(TypeError)
end
- ruby_version_is ''...'3.0' do
- it 'returns a subclass instance for Array subclasses' do
- ArraySpecs::MyArray[1, 2, 3, 4, 5].drop(1).should be_an_instance_of(ArraySpecs::MyArray)
- end
- end
-
- ruby_version_is '3.0' do
- it 'returns a Array instance for Array subclasses' do
- ArraySpecs::MyArray[1, 2, 3, 4, 5].drop(1).should be_an_instance_of(Array)
- end
+ it 'returns a Array instance for Array subclasses' do
+ ArraySpecs::MyArray[1, 2, 3, 4, 5].drop(1).should be_an_instance_of(Array)
end
end
diff --git a/spec/ruby/core/array/drop_while_spec.rb b/spec/ruby/core/array/drop_while_spec.rb
index bb783d22a5..bd46e8b882 100644
--- a/spec/ruby/core/array/drop_while_spec.rb
+++ b/spec/ruby/core/array/drop_while_spec.rb
@@ -1,7 +1,11 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
+require_relative 'shared/iterable_and_tolerating_size_increasing'
describe "Array#drop_while" do
+ @value_to_return = -> _ { true }
+ it_behaves_like :array_iterable_and_tolerating_size_increasing, :drop_while
+
it "removes elements from the start of the array while the block evaluates to true" do
[1, 2, 3, 4].drop_while { |n| n < 4 }.should == [4]
end
@@ -14,15 +18,7 @@ describe "Array#drop_while" do
[1, 2, 3, false, 5].drop_while { |n| n }.should == [false, 5]
end
- ruby_version_is ''...'3.0' do
- it 'returns a subclass instance for Array subclasses' do
- ArraySpecs::MyArray[1, 2, 3, 4, 5].drop_while { |n| n < 4 }.should be_an_instance_of(ArraySpecs::MyArray)
- end
- end
-
- ruby_version_is '3.0' do
- it 'returns a Array instance for Array subclasses' do
- ArraySpecs::MyArray[1, 2, 3, 4, 5].drop_while { |n| n < 4 }.should be_an_instance_of(Array)
- end
+ it 'returns a Array instance for Array subclasses' do
+ ArraySpecs::MyArray[1, 2, 3, 4, 5].drop_while { |n| n < 4 }.should be_an_instance_of(Array)
end
end
diff --git a/spec/ruby/core/array/each_index_spec.rb b/spec/ruby/core/array/each_index_spec.rb
index 51af5842c4..3a4bca9251 100644
--- a/spec/ruby/core/array/each_index_spec.rb
+++ b/spec/ruby/core/array/each_index_spec.rb
@@ -5,7 +5,7 @@ require_relative '../enumerable/shared/enumeratorized'
# Modifying a collection while the contents are being iterated
# gives undefined behavior. See
-# http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/23633
+# https://blade.ruby-lang.org/ruby-core/23633
describe "Array#each_index" do
before :each do
@@ -40,3 +40,19 @@ describe "Array#each_index" do
it_behaves_like :enumeratorize, :each_index
it_behaves_like :enumeratorized_with_origin_size, :each_index, [1,2,3]
end
+
+describe "Array#each_index" do
+ it "tolerates increasing an array size during iteration" do
+ array = [:a, :b, :c]
+ ScratchPad.record []
+ i = 0
+
+ array.each_index do |index|
+ ScratchPad << index
+ array << i if i < 100
+ i += 1
+ end
+
+ ScratchPad.recorded.should == (0..102).to_a # element indices
+ end
+end
diff --git a/spec/ruby/core/array/each_spec.rb b/spec/ruby/core/array/each_spec.rb
index 256647d61e..57d6082f01 100644
--- a/spec/ruby/core/array/each_spec.rb
+++ b/spec/ruby/core/array/each_spec.rb
@@ -1,11 +1,13 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
require_relative 'shared/enumeratorize'
+require_relative 'shared/iterable_and_tolerating_size_increasing'
require_relative '../enumerable/shared/enumeratorized'
-# Modifying a collection while the contents are being iterated
-# gives undefined behavior. See
-# http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/23633
+# Mutating the array while it is being iterated is discouraged as it can result in confusing behavior.
+# Yet a Ruby implementation must not crash in such a case, and following the simple CRuby behavior makes sense.
+# CRuby simply reads the array storage and checks the size for every iteration;
+# like `i = 0; while i < size; yield self[i]; end`
describe "Array#each" do
it "yields each element to the block" do
@@ -15,6 +17,34 @@ describe "Array#each" do
a.should == [1, 2, 3]
end
+ it "yields each element to the block even if the array is changed during iteration" do
+ a = [1, 2, 3, 4, 5]
+ iterated = []
+ a.each { |x| iterated << x; a << x+5 if x.even? }
+ iterated.should == [1, 2, 3, 4, 5, 7, 9]
+ end
+
+ it "yields only elements that are still in the array" do
+ a = [0, 1, 2, 3, 4]
+ iterated = []
+ a.each { |x| iterated << x; a.pop if x.even? }
+ iterated.should == [0, 1, 2]
+ end
+
+ it "yields elements based on an internal index" do
+ a = [0, 1, 2, 3, 4]
+ iterated = []
+ a.each { |x| iterated << x; a.shift if x.even? }
+ iterated.should == [0, 2, 4]
+ end
+
+ it "yields the same element multiple times if inserting while iterating" do
+ a = [1, 2]
+ iterated = []
+ a.each { |x| iterated << x; a.unshift(0) if a.size == 2 }
+ iterated.should == [1, 1, 2]
+ end
+
it "yields each element to a block that takes multiple arguments" do
a = [[1, 2], :a, [3, 4]]
b = []
@@ -46,3 +76,7 @@ describe "Array#each" do
it_behaves_like :enumeratorize, :each
it_behaves_like :enumeratorized_with_origin_size, :each, [1,2,3]
end
+
+describe "Array#each" do
+ it_behaves_like :array_iterable_and_tolerating_size_increasing, :each
+end
diff --git a/spec/ruby/core/array/element_set_spec.rb b/spec/ruby/core/array/element_set_spec.rb
index 1e192c100f..df5ca9582e 100644
--- a/spec/ruby/core/array/element_set_spec.rb
+++ b/spec/ruby/core/array/element_set_spec.rb
@@ -481,50 +481,48 @@ describe "Array#[]= with [m..]" do
end
end
-ruby_version_is "2.7" do
- describe "Array#[]= with [..n] and [...n]" do
- it "just sets the section defined by range to nil even if the rhs is nil" do
- a = [1, 2, 3, 4, 5]
- a[eval("(..2)")] = nil
- a.should == [nil, 4, 5]
- a[eval("(...2)")] = nil
- a.should == [nil, 5]
- end
+describe "Array#[]= with [..n] and [...n]" do
+ it "just sets the section defined by range to nil even if the rhs is nil" do
+ a = [1, 2, 3, 4, 5]
+ a[(..2)] = nil
+ a.should == [nil, 4, 5]
+ a[(...2)] = nil
+ a.should == [nil, 5]
+ end
- it "just sets the section defined by range to nil if n < 0 and the rhs is nil" do
- a = [1, 2, 3, 4, 5]
- a[eval("(..-3)")] = nil
- a.should == [nil, 4, 5]
- a[eval("(...-1)")] = [nil, 5]
- end
+ it "just sets the section defined by range to nil if n < 0 and the rhs is nil" do
+ a = [1, 2, 3, 4, 5]
+ a[(..-3)] = nil
+ a.should == [nil, 4, 5]
+ a[(...-1)] = [nil, 5]
+ end
- it "replaces the section defined by range" do
- a = [6, 5, 4, 3, 2, 1]
- a[eval("(...3)")] = 9
- a.should == [9, 3, 2, 1]
- a[eval("(..2)")] = [7, 7, 7, 7, 7]
- a.should == [7, 7, 7, 7, 7, 1]
- end
+ it "replaces the section defined by range" do
+ a = [6, 5, 4, 3, 2, 1]
+ a[(...3)] = 9
+ a.should == [9, 3, 2, 1]
+ a[(..2)] = [7, 7, 7, 7, 7]
+ a.should == [7, 7, 7, 7, 7, 1]
+ end
- it "replaces the section if n < 0" do
- a = [1, 2, 3, 4, 5]
- a[eval("(..-2)")] = [7, 8, 9]
- a.should == [7, 8, 9, 5]
- end
+ it "replaces the section if n < 0" do
+ a = [1, 2, 3, 4, 5]
+ a[(..-2)] = [7, 8, 9]
+ a.should == [7, 8, 9, 5]
+ end
- it "replaces everything if n > the array size" do
- a = [1, 2, 3]
- a[eval("(...7)")] = [4]
- a.should == [4]
- end
+ it "replaces everything if n > the array size" do
+ a = [1, 2, 3]
+ a[(...7)] = [4]
+ a.should == [4]
+ end
- it "inserts at the beginning if n < negative the array size" do
- a = [1, 2, 3]
- a[eval("(..-7)")] = [4]
- a.should == [4, 1, 2, 3]
- a[eval("(...-10)")] = [6]
- a.should == [6, 4, 1, 2, 3]
- end
+ it "inserts at the beginning if n < negative the array size" do
+ a = [1, 2, 3]
+ a[(..-7)] = [4]
+ a.should == [4, 1, 2, 3]
+ a[(...-10)] = [6]
+ a.should == [6, 4, 1, 2, 3]
end
end
diff --git a/spec/ruby/core/array/fill_spec.rb b/spec/ruby/core/array/fill_spec.rb
index bfa8db551b..2c3b5d9e84 100644
--- a/spec/ruby/core/array/fill_spec.rb
+++ b/spec/ruby/core/array/fill_spec.rb
@@ -21,7 +21,7 @@ describe "Array#fill" do
it "does not replicate the filler" do
ary = [1, 2, 3, 4]
- str = "x"
+ str = +"x"
ary.fill(str).should == [str, str, str, str]
str << "y"
ary.should == [str, str, str, str]
@@ -52,11 +52,9 @@ describe "Array#fill" do
end
it "raises an ArgumentError if 4 or more arguments are passed when no block given" do
- -> { [].fill('a') }.should_not raise_error(ArgumentError)
-
- -> { [].fill('a', 1) }.should_not raise_error(ArgumentError)
-
- -> { [].fill('a', 1, 2) }.should_not raise_error(ArgumentError)
+ [].fill('a').should == []
+ [].fill('a', 1).should == []
+ [].fill('a', 1, 2).should == [nil, 'a', 'a']
-> { [].fill('a', 1, 2, true) }.should raise_error(ArgumentError)
end
@@ -65,12 +63,52 @@ describe "Array#fill" do
end
it "raises an ArgumentError if 3 or more arguments are passed when a block given" do
- -> { [].fill() {|i|} }.should_not raise_error(ArgumentError)
+ [].fill() {|i|}.should == []
+ [].fill(1) {|i|}.should == []
+ [].fill(1, 2) {|i|}.should == [nil, nil, nil]
+ -> { [].fill(1, 2, true) {|i|} }.should raise_error(ArgumentError)
+ end
- -> { [].fill(1) {|i|} }.should_not raise_error(ArgumentError)
+ it "does not truncate the array is the block raises an exception" do
+ a = [1, 2, 3]
+ begin
+ a.fill { raise StandardError, 'Oops' }
+ rescue
+ end
- -> { [].fill(1, 2) {|i|} }.should_not raise_error(ArgumentError)
- -> { [].fill(1, 2, true) {|i|} }.should raise_error(ArgumentError)
+ a.should == [1, 2, 3]
+ end
+
+ it "only changes elements before error is raised, keeping the element which raised an error." do
+ a = [1, 2, 3, 4]
+ begin
+ a.fill do |i|
+ case i
+ when 0 then -1
+ when 1 then -2
+ when 2 then raise StandardError, 'Oops'
+ else 0
+ end
+ end
+ rescue StandardError
+ end
+
+ a.should == [-1, -2, 3, 4]
+ end
+
+ it "tolerates increasing an array size during iteration" do
+ array = [:a, :b, :c]
+ ScratchPad.record []
+ i = 0
+
+ array.fill do |index|
+ ScratchPad << index
+ array << i if i < 100
+ i++
+ index
+ end
+
+ ScratchPad.recorded.should == [0, 1, 2]
end
end
@@ -169,25 +207,25 @@ describe "Array#fill with (filler, index, length)" do
[1, 2, 3, 4, 5].fill(-2, -2, &@never_passed).should == [1, 2, 3, 4, 5]
end
- # See: http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/17481
+ # See: https://blade.ruby-lang.org/ruby-core/17481
it "does not raise an exception if the given length is negative and its absolute value does not exceed the index" do
- -> { [1, 2, 3, 4].fill('a', 3, -1)}.should_not raise_error(ArgumentError)
- -> { [1, 2, 3, 4].fill('a', 3, -2)}.should_not raise_error(ArgumentError)
- -> { [1, 2, 3, 4].fill('a', 3, -3)}.should_not raise_error(ArgumentError)
+ [1, 2, 3, 4].fill('a', 3, -1).should == [1, 2, 3, 4]
+ [1, 2, 3, 4].fill('a', 3, -2).should == [1, 2, 3, 4]
+ [1, 2, 3, 4].fill('a', 3, -3).should == [1, 2, 3, 4]
- -> { [1, 2, 3, 4].fill(3, -1, &@never_passed)}.should_not raise_error(ArgumentError)
- -> { [1, 2, 3, 4].fill(3, -2, &@never_passed)}.should_not raise_error(ArgumentError)
- -> { [1, 2, 3, 4].fill(3, -3, &@never_passed)}.should_not raise_error(ArgumentError)
+ [1, 2, 3, 4].fill(3, -1, &@never_passed).should == [1, 2, 3, 4]
+ [1, 2, 3, 4].fill(3, -2, &@never_passed).should == [1, 2, 3, 4]
+ [1, 2, 3, 4].fill(3, -3, &@never_passed).should == [1, 2, 3, 4]
end
it "does not raise an exception even if the given length is negative and its absolute value exceeds the index" do
- -> { [1, 2, 3, 4].fill('a', 3, -4)}.should_not raise_error(ArgumentError)
- -> { [1, 2, 3, 4].fill('a', 3, -5)}.should_not raise_error(ArgumentError)
- -> { [1, 2, 3, 4].fill('a', 3, -10000)}.should_not raise_error(ArgumentError)
+ [1, 2, 3, 4].fill('a', 3, -4).should == [1, 2, 3, 4]
+ [1, 2, 3, 4].fill('a', 3, -5).should == [1, 2, 3, 4]
+ [1, 2, 3, 4].fill('a', 3, -10000).should == [1, 2, 3, 4]
- -> { [1, 2, 3, 4].fill(3, -4, &@never_passed)}.should_not raise_error(ArgumentError)
- -> { [1, 2, 3, 4].fill(3, -5, &@never_passed)}.should_not raise_error(ArgumentError)
- -> { [1, 2, 3, 4].fill(3, -10000, &@never_passed)}.should_not raise_error(ArgumentError)
+ [1, 2, 3, 4].fill(3, -4, &@never_passed).should == [1, 2, 3, 4]
+ [1, 2, 3, 4].fill(3, -5, &@never_passed).should == [1, 2, 3, 4]
+ [1, 2, 3, 4].fill(3, -10000, &@never_passed).should == [1, 2, 3, 4]
end
it "tries to convert the second and third arguments to Integers using #to_int" do
@@ -205,6 +243,12 @@ describe "Array#fill with (filler, index, length)" do
-> { [].fill('a', obj) }.should raise_error(TypeError)
end
+ it "raises a TypeError when the length is not numeric" do
+ -> { [1, 2, 3].fill("x", 1, "foo") }.should raise_error(TypeError, /no implicit conversion of String into Integer/)
+ -> { [1, 2, 3].fill("x", 1, :"foo") }.should raise_error(TypeError, /no implicit conversion of Symbol into Integer/)
+ -> { [1, 2, 3].fill("x", 1, Object.new) }.should raise_error(TypeError, /no implicit conversion of Object into Integer/)
+ end
+
not_supported_on :opal do
it "raises an ArgumentError or RangeError for too-large sizes" do
error_types = [RangeError, ArgumentError]
@@ -323,10 +367,8 @@ describe "Array#fill with (filler, range)" do
[1, 2, 3, 4].fill(eval("(3...)")) { |x| x + 2 }.should == [1, 2, 3, 5]
end
- ruby_version_is "2.7" do
- it "works with beginless ranges" do
- [1, 2, 3, 4].fill('x', eval("(..2)")).should == ["x", "x", "x", 4]
- [1, 2, 3, 4].fill(eval("(...2)")) { |x| x + 2 }.should == [2, 3, 3, 4]
- end
+ it "works with beginless ranges" do
+ [1, 2, 3, 4].fill('x', (..2)).should == ["x", "x", "x", 4]
+ [1, 2, 3, 4].fill((...2)) { |x| x + 2 }.should == [2, 3, 3, 4]
end
end
diff --git a/spec/ruby/core/array/fixtures/classes.rb b/spec/ruby/core/array/fixtures/classes.rb
index affb3b49e6..8596245fb8 100644
--- a/spec/ruby/core/array/fixtures/classes.rb
+++ b/spec/ruby/core/array/fixtures/classes.rb
@@ -40,6 +40,68 @@ module ArraySpecs
a
end
+ # Chi squared critical values for tests with n degrees of freedom at 99% confidence.
+ # Values obtained from NIST Engineering Statistic Handbook at
+ # https://www.itl.nist.gov/div898/handbook/eda/section3/eda3674.htm
+
+ CHI_SQUARED_CRITICAL_VALUES = [
+ 0,
+ 6.635, 9.210, 11.345, 13.277, 15.086, 16.812, 18.475, 20.090, 21.666, 23.209,
+ 24.725, 26.217, 27.688, 29.141, 30.578, 32.000, 33.409, 34.805, 36.191, 37.566,
+ 38.932, 40.289, 41.638, 42.980, 44.314, 45.642, 46.963, 48.278, 49.588, 50.892,
+ 52.191, 53.486, 54.776, 56.061, 57.342, 58.619, 59.893, 61.162, 62.428, 63.691,
+ 64.950, 66.206, 67.459, 68.710, 69.957, 71.201, 72.443, 73.683, 74.919, 76.154,
+ 77.386, 78.616, 79.843, 81.069, 82.292, 83.513, 84.733, 85.950, 87.166, 88.379,
+ 89.591, 90.802, 92.010, 93.217, 94.422, 95.626, 96.828, 98.028, 99.228, 100.425,
+ 101.621, 102.816, 104.010, 105.202, 106.393, 107.583, 108.771, 109.958, 111.144, 112.329,
+ 113.512, 114.695, 115.876, 117.057, 118.236, 119.414, 120.591, 121.767, 122.942, 124.116,
+ 125.289, 126.462, 127.633, 128.803, 129.973, 131.141, 132.309, 133.476, 134.642, 135.807,
+ ]
+
+ def self.measure_sample_fairness(size, samples, iters)
+ ary = Array.new(size) { |x| x }
+ (samples).times do |i|
+ chi_results = []
+ 3.times do
+ counts = Array.new(size) { 0 }
+ expected = iters / size
+ iters.times do
+ x = ary.sample(samples)[i]
+ counts[x] += 1
+ end
+ chi_squared = 0.0
+ counts.each do |count|
+ chi_squared += (((count - expected) ** 2) * 1.0 / expected)
+ end
+ chi_results << chi_squared
+ break if chi_squared <= CHI_SQUARED_CRITICAL_VALUES[size]
+ end
+
+ chi_results.min.should <= CHI_SQUARED_CRITICAL_VALUES[size]
+ end
+ end
+
+ def self.measure_sample_fairness_large_sample_size(size, samples, iters)
+ ary = Array.new(size) { |x| x }
+ counts = Array.new(size) { 0 }
+ expected = iters * samples / size
+ iters.times do
+ ary.sample(samples).each do |sample|
+ counts[sample] += 1
+ end
+ end
+ chi_squared = 0.0
+ counts.each do |count|
+ chi_squared += (((count - expected) ** 2) * 1.0 / expected)
+ end
+
+ # Chi squared critical values for tests with 4 degrees of freedom
+ # Values obtained from NIST Engineering Statistic Handbook at
+ # https://www.itl.nist.gov/div898/handbook/eda/section3/eda3674.htm
+
+ chi_squared.should <= CHI_SQUARED_CRITICAL_VALUES[size]
+ end
+
class MyArray < Array
# The #initialize method has a different signature than Array to help
# catch places in the specs that do not assert the #initialize is not
@@ -98,6 +160,16 @@ module ArraySpecs
end
end
+ class ArrayMethodMissing
+ def initialize(*values, &block)
+ @values = values;
+ end
+
+ def method_missing(name, *args)
+ @values
+ end
+ end
+
class SortSame
def <=>(other); 0; end
def ==(other); true; end
diff --git a/spec/ruby/core/array/fixtures/encoded_strings.rb b/spec/ruby/core/array/fixtures/encoded_strings.rb
index 5b85bd0e06..b5888d86ae 100644
--- a/spec/ruby/core/array/fixtures/encoded_strings.rb
+++ b/spec/ruby/core/array/fixtures/encoded_strings.rb
@@ -2,14 +2,14 @@
module ArraySpecs
def self.array_with_usascii_and_7bit_utf8_strings
[
- 'foo'.force_encoding('US-ASCII'),
+ 'foo'.dup.force_encoding('US-ASCII'),
'bar'
]
end
def self.array_with_usascii_and_utf8_strings
[
- 'foo'.force_encoding('US-ASCII'),
+ 'foo'.dup.force_encoding('US-ASCII'),
'báz'
]
end
@@ -17,7 +17,7 @@ module ArraySpecs
def self.array_with_7bit_utf8_and_usascii_strings
[
'bar',
- 'foo'.force_encoding('US-ASCII')
+ 'foo'.dup.force_encoding('US-ASCII')
]
end
@@ -25,13 +25,13 @@ module ArraySpecs
[
'báz',
'bar',
- 'foo'.force_encoding('US-ASCII')
+ 'foo'.dup.force_encoding('US-ASCII')
]
end
def self.array_with_usascii_and_utf8_strings
[
- 'foo'.force_encoding('US-ASCII'),
+ 'foo'.dup.force_encoding('US-ASCII'),
'bar',
'báz'
]
@@ -41,7 +41,7 @@ module ArraySpecs
[
'bar',
'báz',
- 'foo'.force_encoding('BINARY')
+ 'foo'.dup.force_encoding('BINARY')
]
end
@@ -55,14 +55,14 @@ module ArraySpecs
def self.array_with_usascii_and_7bit_binary_strings
[
- 'bar'.force_encoding('US-ASCII'),
- 'foo'.force_encoding('BINARY')
+ 'bar'.dup.force_encoding('US-ASCII'),
+ 'foo'.dup.force_encoding('BINARY')
]
end
def self.array_with_usascii_and_binary_strings
[
- 'bar'.force_encoding('US-ASCII'),
+ 'bar'.dup.force_encoding('US-ASCII'),
[255].pack('C').force_encoding('BINARY')
]
end
diff --git a/spec/ruby/core/array/flatten_spec.rb b/spec/ruby/core/array/flatten_spec.rb
index 2f9fb8a3ec..8c97000c79 100644
--- a/spec/ruby/core/array/flatten_spec.rb
+++ b/spec/ruby/core/array/flatten_spec.rb
@@ -75,24 +75,12 @@ describe "Array#flatten" do
[[obj]].flatten(1)
end
- ruby_version_is ''...'3.0' do
- it "returns subclass instance for Array subclasses" do
- ArraySpecs::MyArray[].flatten.should be_an_instance_of(ArraySpecs::MyArray)
- ArraySpecs::MyArray[1, 2, 3].flatten.should be_an_instance_of(ArraySpecs::MyArray)
- ArraySpecs::MyArray[1, [2], 3].flatten.should be_an_instance_of(ArraySpecs::MyArray)
- ArraySpecs::MyArray[1, [2, 3], 4].flatten.should == ArraySpecs::MyArray[1, 2, 3, 4]
- [ArraySpecs::MyArray[1, 2, 3]].flatten.should be_an_instance_of(Array)
- end
- end
-
- ruby_version_is '3.0' do
- it "returns Array instance for Array subclasses" do
- ArraySpecs::MyArray[].flatten.should be_an_instance_of(Array)
- ArraySpecs::MyArray[1, 2, 3].flatten.should be_an_instance_of(Array)
- ArraySpecs::MyArray[1, [2], 3].flatten.should be_an_instance_of(Array)
- ArraySpecs::MyArray[1, [2, 3], 4].flatten.should == [1, 2, 3, 4]
- [ArraySpecs::MyArray[1, 2, 3]].flatten.should be_an_instance_of(Array)
- end
+ it "returns Array instance for Array subclasses" do
+ ArraySpecs::MyArray[].flatten.should be_an_instance_of(Array)
+ ArraySpecs::MyArray[1, 2, 3].flatten.should be_an_instance_of(Array)
+ ArraySpecs::MyArray[1, [2], 3].flatten.should be_an_instance_of(Array)
+ ArraySpecs::MyArray[1, [2, 3], 4].flatten.should == [1, 2, 3, 4]
+ [ArraySpecs::MyArray[1, 2, 3]].flatten.should be_an_instance_of(Array)
end
it "is not destructive" do
@@ -147,16 +135,6 @@ describe "Array#flatten" do
end
end
- ruby_version_is ''...'2.7' do
- it "returns a tainted array if self is tainted" do
- [].taint.flatten.tainted?.should be_true
- end
-
- it "returns an untrusted array if self is untrusted" do
- [].untrust.flatten.untrusted?.should be_true
- end
- end
-
it "performs respond_to? and method_missing-aware checks when coercing elements to array" do
bo = BasicObject.new
[bo].flatten.should == [bo]
diff --git a/spec/ruby/core/array/initialize_spec.rb b/spec/ruby/core/array/initialize_spec.rb
index a8deed2b84..b9fa77b16e 100644
--- a/spec/ruby/core/array/initialize_spec.rb
+++ b/spec/ruby/core/array/initialize_spec.rb
@@ -53,7 +53,9 @@ describe "Array#initialize with no arguments" do
end
it "does not use the given block" do
- ->{ [1, 2, 3].send(:initialize) { raise } }.should_not raise_error
+ -> {
+ -> { [1, 2, 3].send(:initialize) { raise } }.should_not raise_error
+ }.should complain(/#{__FILE__}:#{__LINE__-1}: warning: given block not used/, verbose: true)
end
end
diff --git a/spec/ruby/core/array/intersect_spec.rb b/spec/ruby/core/array/intersect_spec.rb
index b8c5b1e69a..62ac157278 100644
--- a/spec/ruby/core/array/intersect_spec.rb
+++ b/spec/ruby/core/array/intersect_spec.rb
@@ -1,17 +1,66 @@
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]).should == true
+ [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
- [1, 2].intersect?([3, 4]).should == false
+ [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])
+
+ [1, 2].intersect?(obj).should == true
+ end
+
+ it "determines equivalence between elements in the sense of eql?" do
+ obj1 = mock('1')
+ obj2 = mock('2')
+ obj1.stub!(:hash).and_return(0)
+ obj2.stub!(:hash).and_return(0)
+ obj1.stub!(:eql?).and_return(true)
+ obj2.stub!(:eql?).and_return(true)
+
+ [obj1].intersect?([obj2]).should == true
+
+ obj1 = mock('3')
+ obj2 = mock('4')
+ obj1.stub!(:hash).and_return(0)
+ obj2.stub!(:hash).and_return(0)
+ obj1.stub!(:eql?).and_return(false)
+ obj2.stub!(:eql?).and_return(false)
+
+ [obj1].intersect?([obj2]).should == false
+ end
+
+ it "does not call to_ary on array subclasses" do
+ [5, 6].intersect?(ArraySpecs::ToAryArray[1, 2, 5, 6]).should == true
+ end
+
+ it "properly handles an identical item even when its #eql? isn't reflexive" do
+ x = mock('x')
+ x.stub!(:hash).and_return(42)
+ x.stub!(:eql?).and_return(false) # Stubbed for clarity and latitude in implementation; not actually sent by MRI.
+
+ [x].intersect?([x]).should == true
+ end
+
+ it "has semantic of !(a & b).empty?" do
+ [].intersect?([]).should == false
+ [nil].intersect?([nil]).should == true
+ end
end
end
diff --git a/spec/ruby/core/array/intersection_spec.rb b/spec/ruby/core/array/intersection_spec.rb
index 27d90f1e44..e01a68d389 100644
--- a/spec/ruby/core/array/intersection_spec.rb
+++ b/spec/ruby/core/array/intersection_spec.rb
@@ -6,16 +6,14 @@ describe "Array#&" do
it_behaves_like :array_intersection, :&
end
-ruby_version_is "2.7" do
- describe "Array#intersection" do
- it_behaves_like :array_intersection, :intersection
+describe "Array#intersection" do
+ it_behaves_like :array_intersection, :intersection
- it "accepts multiple arguments" do
- [1, 2, 3, 4].intersection([1, 2, 3], [2, 3, 4]).should == [2, 3]
- end
+ it "accepts multiple arguments" do
+ [1, 2, 3, 4].intersection([1, 2, 3], [2, 3, 4]).should == [2, 3]
+ end
- it "preserves elements order from original array" do
- [1, 2, 3, 4].intersection([3, 2, 1]).should == [1, 2, 3]
- end
+ it "preserves elements order from original array" do
+ [1, 2, 3, 4].intersection([3, 2, 1]).should == [1, 2, 3]
end
end
diff --git a/spec/ruby/core/array/keep_if_spec.rb b/spec/ruby/core/array/keep_if_spec.rb
index bf2bdeaf91..40f7329b7c 100644
--- a/spec/ruby/core/array/keep_if_spec.rb
+++ b/spec/ruby/core/array/keep_if_spec.rb
@@ -1,3 +1,4 @@
+require_relative '../../spec_helper'
require_relative 'shared/keep_if'
describe "Array#keep_if" do
diff --git a/spec/ruby/core/array/multiply_spec.rb b/spec/ruby/core/array/multiply_spec.rb
index 16e407348b..eca51142fb 100644
--- a/spec/ruby/core/array/multiply_spec.rb
+++ b/spec/ruby/core/array/multiply_spec.rb
@@ -76,20 +76,10 @@ describe "Array#* with an integer" do
@array = ArraySpecs::MyArray[1, 2, 3, 4, 5]
end
- ruby_version_is ''...'3.0' do
- it "returns a subclass instance" do
- (@array * 0).should be_an_instance_of(ArraySpecs::MyArray)
- (@array * 1).should be_an_instance_of(ArraySpecs::MyArray)
- (@array * 2).should be_an_instance_of(ArraySpecs::MyArray)
- end
- end
-
- ruby_version_is '3.0' do
- it "returns an Array instance" do
- (@array * 0).should be_an_instance_of(Array)
- (@array * 1).should be_an_instance_of(Array)
- (@array * 2).should be_an_instance_of(Array)
- end
+ it "returns an Array instance" do
+ (@array * 0).should be_an_instance_of(Array)
+ (@array * 1).should be_an_instance_of(Array)
+ (@array * 2).should be_an_instance_of(Array)
end
it "does not call #initialize on the subclass instance" do
@@ -97,46 +87,6 @@ describe "Array#* with an integer" do
ScratchPad.recorded.should be_nil
end
end
-
- ruby_version_is ''...'2.7' do
- it "copies the taint status of the original array even if the passed count is 0" do
- ary = [1, 2, 3]
- ary.taint
- (ary * 0).should.tainted?
- end
-
- it "copies the taint status of the original array even if the array is empty" do
- ary = []
- ary.taint
- (ary * 3).should.tainted?
- end
-
- it "copies the taint status of the original array if the passed count is not 0" do
- ary = [1, 2, 3]
- ary.taint
- (ary * 1).should.tainted?
- (ary * 2).should.tainted?
- end
-
- it "copies the untrusted status of the original array even if the passed count is 0" do
- ary = [1, 2, 3]
- ary.untrust
- (ary * 0).should.untrusted?
- end
-
- it "copies the untrusted status of the original array even if the array is empty" do
- ary = []
- ary.untrust
- (ary * 3).should.untrusted?
- end
-
- it "copies the untrusted status of the original array if the passed count is not 0" do
- ary = [1, 2, 3]
- ary.untrust
- (ary * 1).should.untrusted?
- (ary * 2).should.untrusted?
- end
- end
end
describe "Array#* with a string" do
diff --git a/spec/ruby/core/array/new_spec.rb b/spec/ruby/core/array/new_spec.rb
index 96ec6b8198..b50a4857b0 100644
--- a/spec/ruby/core/array/new_spec.rb
+++ b/spec/ruby/core/array/new_spec.rb
@@ -26,7 +26,9 @@ describe "Array.new with no arguments" do
end
it "does not use the given block" do
- ->{ Array.new { raise } }.should_not raise_error
+ -> {
+ -> { Array.new { raise } }.should_not raise_error
+ }.should complain(/warning: given block not used/, verbose: true)
end
end
diff --git a/spec/ruby/core/array/none_spec.rb b/spec/ruby/core/array/none_spec.rb
new file mode 100644
index 0000000000..31cd8c46d6
--- /dev/null
+++ b/spec/ruby/core/array/none_spec.rb
@@ -0,0 +1,13 @@
+require_relative '../../spec_helper'
+require_relative 'shared/iterable_and_tolerating_size_increasing'
+
+describe "Array#none?" do
+ @value_to_return = -> _ { false }
+ it_behaves_like :array_iterable_and_tolerating_size_increasing, :none?
+
+ it "ignores the block if there is an argument" do
+ -> {
+ ['bar', 'foobar'].none?(/baz/) { true }.should == true
+ }.should complain(/given block not used/)
+ end
+end
diff --git a/spec/ruby/core/array/one_spec.rb b/spec/ruby/core/array/one_spec.rb
new file mode 100644
index 0000000000..0c61907881
--- /dev/null
+++ b/spec/ruby/core/array/one_spec.rb
@@ -0,0 +1,13 @@
+require_relative '../../spec_helper'
+require_relative 'shared/iterable_and_tolerating_size_increasing'
+
+describe "Array#one?" do
+ @value_to_return = -> _ { false }
+ it_behaves_like :array_iterable_and_tolerating_size_increasing, :one?
+
+ it "ignores the block if there is an argument" do
+ -> {
+ ['bar', 'foobar'].one?(/foo/) { false }.should == true
+ }.should complain(/given block not used/)
+ end
+end
diff --git a/spec/ruby/core/array/pack/buffer_spec.rb b/spec/ruby/core/array/pack/buffer_spec.rb
index ecb40bfd06..f1206efb3e 100644
--- a/spec/ruby/core/array/pack/buffer_spec.rb
+++ b/spec/ruby/core/array/pack/buffer_spec.rb
@@ -13,13 +13,13 @@ describe "Array#pack with :buffer option" do
it "adds result at the end of buffer content" do
n = [ 65, 66, 67 ] # result without buffer is "ABC"
- buffer = ""
+ buffer = +""
n.pack("ccc", buffer: buffer).should == "ABC"
- buffer = "123"
+ buffer = +"123"
n.pack("ccc", buffer: buffer).should == "123ABC"
- buffer = "12345"
+ buffer = +"12345"
n.pack("ccc", buffer: buffer).should == "12345ABC"
end
@@ -31,19 +31,19 @@ describe "Array#pack with :buffer option" do
context "offset (@) is specified" do
it 'keeps buffer content if it is longer than offset' do
n = [ 65, 66, 67 ]
- buffer = "123456"
+ buffer = +"123456"
n.pack("@3ccc", buffer: buffer).should == "123ABC"
end
it "fills the gap with \\0 if buffer content is shorter than offset" do
n = [ 65, 66, 67 ]
- buffer = "123"
+ buffer = +"123"
n.pack("@6ccc", buffer: buffer).should == "123\0\0\0ABC"
end
it 'does not keep buffer content if it is longer than offset + result' do
n = [ 65, 66, 67 ]
- buffer = "1234567890"
+ buffer = +"1234567890"
n.pack("@3ccc", buffer: buffer).should == "123ABC"
end
end
diff --git a/spec/ruby/core/array/pack/c_spec.rb b/spec/ruby/core/array/pack/c_spec.rb
index 7200830331..ac133ff9b6 100644
--- a/spec/ruby/core/array/pack/c_spec.rb
+++ b/spec/ruby/core/array/pack/c_spec.rb
@@ -45,8 +45,20 @@ describe :array_pack_8bit, shared: true do
[1, 2, 3, 4, 5].pack(pack_format('*')).should == "\x01\x02\x03\x04\x05"
end
- it "ignores NULL bytes between directives" do
- [1, 2, 3].pack(pack_format("\000", 2)).should == "\x01\x02"
+ ruby_version_is ""..."3.3" do
+ it "ignores NULL bytes between directives" do
+ suppress_warning do
+ [1, 2, 3].pack(pack_format("\000", 2)).should == "\x01\x02"
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ [1, 2, 3].pack(pack_format("\000", 2))
+ }.should raise_error(ArgumentError, /unknown pack directive/)
+ end
end
it "ignores spaces between directives" do
diff --git a/spec/ruby/core/array/pack/m_spec.rb b/spec/ruby/core/array/pack/m_spec.rb
index 2b1a84abca..c6364af12d 100644
--- a/spec/ruby/core/array/pack/m_spec.rb
+++ b/spec/ruby/core/array/pack/m_spec.rb
@@ -80,8 +80,16 @@ describe "Array#pack with format 'M'" do
].should be_computed_by(:pack, "M")
end
- it "encodes a tab followed by a newline with an encoded newline" do
+ it "encodes a tab at the end of a line with an encoded newline" do
+ ["\t"].pack("M").should == "\t=\n"
["\t\n"].pack("M").should == "\t=\n\n"
+ ["abc\t\nxyz"].pack("M").should == "abc\t=\n\nxyz=\n"
+ end
+
+ it "encodes a space at the end of a line with an encoded newline" do
+ [" "].pack("M").should == " =\n"
+ [" \n"].pack("M").should == " =\n\n"
+ ["abc \nxyz"].pack("M").should == "abc =\n\nxyz=\n"
end
it "encodes 127..255 in hex format" do
diff --git a/spec/ruby/core/array/pack/p_spec.rb b/spec/ruby/core/array/pack/p_spec.rb
index d7dff8a4da..b023bf9110 100644
--- a/spec/ruby/core/array/pack/p_spec.rb
+++ b/spec/ruby/core/array/pack/p_spec.rb
@@ -15,18 +15,6 @@ describe "Array#pack with format 'P'" do
["hello"].pack("P").unpack("P5").should == ["hello"]
end
- ruby_version_is ''...'2.7' do
- it "taints the input string" do
- input_string = "hello"
- [input_string].pack("P")
- input_string.tainted?.should be_true
- end
-
- it "does not taint the output string in normal cases" do
- ["hello"].pack("P").tainted?.should be_false
- end
- end
-
it "with nil gives a null pointer" do
[nil].pack("P").unpack("J").should == [0]
end
@@ -44,18 +32,6 @@ describe "Array#pack with format 'p'" do
["hello"].pack("p").unpack("p").should == ["hello"]
end
- ruby_version_is ''...'2.7' do
- it "taints the input string" do
- input_string = "hello"
- [input_string].pack("p")
- input_string.tainted?.should be_true
- end
-
- it "does not taint the output string in normal cases" do
- ["hello"].pack("p").tainted?.should be_false
- end
- end
-
it "with nil gives a null pointer" do
[nil].pack("p").unpack("J").should == [0]
end
diff --git a/spec/ruby/core/array/pack/shared/basic.rb b/spec/ruby/core/array/pack/shared/basic.rb
index 9061273ad6..5e3eea55f9 100644
--- a/spec/ruby/core/array/pack/shared/basic.rb
+++ b/spec/ruby/core/array/pack/shared/basic.rb
@@ -27,17 +27,47 @@ describe :array_pack_basic_non_float, shared: true do
[@obj, @obj].pack("a \t\n\v\f\r"+pack_format).should be_an_instance_of(String)
end
+ it "ignores comments in the format string" do
+ # 2 additional directives ('a') are required for the X directive
+ [@obj, @obj, @obj, @obj].pack("aa #{pack_format} # some comment \n#{pack_format}").should be_an_instance_of(String)
+ end
+
+ ruby_version_is ""..."3.2" do
+ it "warns in verbose mode that a directive is unknown" do
+ # additional directive ('a') is required for the X directive
+ -> { [@obj, @obj].pack("a R" + pack_format) }.should complain(/unknown pack directive 'R'/, verbose: true)
+ -> { [@obj, @obj].pack("a 0" + pack_format) }.should complain(/unknown pack directive '0'/, verbose: true)
+ -> { [@obj, @obj].pack("a :" + pack_format) }.should complain(/unknown pack directive ':'/, verbose: true)
+ end
+ end
+
+ ruby_version_is "3.2"..."3.3" do
+ # https://bugs.ruby-lang.org/issues/19150
+ # NOTE: it's just a plan of the Ruby core team
+ it "warns that a directive is unknown" do
+ # additional directive ('a') is required for the X directive
+ -> { [@obj, @obj].pack("a R" + pack_format) }.should complain(/unknown pack directive 'R'/)
+ -> { [@obj, @obj].pack("a 0" + pack_format) }.should complain(/unknown pack directive '0'/)
+ -> { [@obj, @obj].pack("a :" + pack_format) }.should complain(/unknown pack directive ':'/)
+ end
+ end
+
+ ruby_version_is "3.3" do
+ # https://bugs.ruby-lang.org/issues/19150
+ # NOTE: Added this case just to not forget about the decision in the ticket
+ it "raise ArgumentError when a directive is unknown" do
+ # additional directive ('a') is required for the X directive
+ -> { [@obj, @obj].pack("a R" + pack_format) }.should raise_error(ArgumentError)
+ -> { [@obj, @obj].pack("a 0" + pack_format) }.should raise_error(ArgumentError)
+ -> { [@obj, @obj].pack("a :" + pack_format) }.should raise_error(ArgumentError)
+ end
+ end
+
it "calls #to_str to coerce the directives string" do
d = mock("pack directive")
d.should_receive(:to_str).and_return("x"+pack_format)
[@obj, @obj].pack(d).should be_an_instance_of(String)
end
-
- ruby_version_is ''...'2.7' do
- it "taints the output string if the format string is tainted" do
- [@obj, @obj].pack("x"+pack_format.taint).tainted?.should be_true
- end
- end
end
describe :array_pack_basic_float, shared: true do
@@ -45,17 +75,15 @@ describe :array_pack_basic_float, shared: true do
[9.3, 4.7].pack(" \t\n\v\f\r"+pack_format).should be_an_instance_of(String)
end
+ it "ignores comments in the format string" do
+ [9.3, 4.7].pack(pack_format + "# some comment \n" + pack_format).should be_an_instance_of(String)
+ end
+
it "calls #to_str to coerce the directives string" do
d = mock("pack directive")
d.should_receive(:to_str).and_return("x"+pack_format)
[1.2, 4.7].pack(d).should be_an_instance_of(String)
end
-
- ruby_version_is ''...'2.7' do
- it "taints the output string if the format string is tainted" do
- [3.2, 2.8].pack("x"+pack_format.taint).tainted?.should be_true
- end
- end
end
describe :array_pack_no_platform, shared: true do
diff --git a/spec/ruby/core/array/pack/shared/float.rb b/spec/ruby/core/array/pack/shared/float.rb
index ba174a071a..1780d7635e 100644
--- a/spec/ruby/core/array/pack/shared/float.rb
+++ b/spec/ruby/core/array/pack/shared/float.rb
@@ -25,8 +25,20 @@ describe :array_pack_float_le, shared: true do
[2.9, 1.4, 8.2].pack(pack_format("*")).should == "\x9a\x999@33\xb3?33\x03A"
end
- it "ignores NULL bytes between directives" do
- [5.3, 9.2].pack(pack_format("\000", 2)).should == "\x9a\x99\xa9@33\x13A"
+ ruby_version_is ""..."3.3" do
+ it "ignores NULL bytes between directives" do
+ suppress_warning do
+ [5.3, 9.2].pack(pack_format("\000", 2)).should == "\x9a\x99\xa9@33\x13A"
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ [5.3, 9.2].pack(pack_format("\000", 2))
+ }.should raise_error(ArgumentError, /unknown pack directive/)
+ end
end
it "ignores spaces between directives" do
@@ -74,6 +86,11 @@ describe :array_pack_float_be, shared: true do
it "converts an Integer to a Float" do
[8].pack(pack_format).should == "A\x00\x00\x00"
+ [bignum_value].pack(pack_format).should == "_\x80\x00\x00"
+ end
+
+ it "converts a Rational to a Float" do
+ [Rational(8)].pack(pack_format).should == "A\x00\x00\x00"
end
it "raises a TypeError if passed a String representation of a floating point number" do
@@ -88,8 +105,20 @@ describe :array_pack_float_be, shared: true do
[2.9, 1.4, 8.2].pack(pack_format("*")).should == "@9\x99\x9a?\xb333A\x0333"
end
- it "ignores NULL bytes between directives" do
- [5.3, 9.2].pack(pack_format("\000", 2)).should == "@\xa9\x99\x9aA\x1333"
+ ruby_version_is ""..."3.3" do
+ it "ignores NULL bytes between directives" do
+ suppress_warning do
+ [5.3, 9.2].pack(pack_format("\000", 2)).should == "@\xa9\x99\x9aA\x1333"
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ [5.3, 9.2].pack(pack_format("\000", 2))
+ }.should raise_error(ArgumentError, /unknown pack directive/)
+ end
end
it "ignores spaces between directives" do
@@ -129,6 +158,11 @@ describe :array_pack_double_le, shared: true do
it "converts an Integer to a Float" do
[8].pack(pack_format).should == "\x00\x00\x00\x00\x00\x00\x20@"
+ [bignum_value].pack(pack_format).should == "\x00\x00\x00\x00\x00\x00\xF0C"
+ end
+
+ it "converts a Rational to a Float" do
+ [Rational(8)].pack(pack_format).should == "\x00\x00\x00\x00\x00\x00 @"
end
it "raises a TypeError if passed a String representation of a floating point number" do
@@ -143,8 +177,20 @@ describe :array_pack_double_le, shared: true do
[2.9, 1.4, 8.2].pack(pack_format("*")).should == "333333\x07@ffffff\xf6?ffffff\x20@"
end
- it "ignores NULL bytes between directives" do
- [5.3, 9.2].pack(pack_format("\000", 2)).should == "333333\x15@ffffff\x22@"
+ ruby_version_is ""..."3.3" do
+ it "ignores NULL bytes between directives" do
+ suppress_warning do
+ [5.3, 9.2].pack(pack_format("\000", 2)).should == "333333\x15@ffffff\x22@"
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ [5.3, 9.2].pack(pack_format("\000", 2))
+ }.should raise_error(ArgumentError, /unknown pack directive/)
+ end
end
it "ignores spaces between directives" do
@@ -202,8 +248,20 @@ describe :array_pack_double_be, shared: true do
[2.9, 1.4, 8.2].pack(pack_format("*")).should == "@\x07333333?\xf6ffffff@\x20ffffff"
end
- it "ignores NULL bytes between directives" do
- [5.3, 9.2].pack(pack_format("\000", 2)).should == "@\x15333333@\x22ffffff"
+ ruby_version_is ""..."3.3" do
+ it "ignores NULL bytes between directives" do
+ suppress_warning do
+ [5.3, 9.2].pack(pack_format("\000", 2)).should == "@\x15333333@\x22ffffff"
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ [5.3, 9.2].pack(pack_format("\000", 2))
+ }.should raise_error(ArgumentError, /unknown pack directive/)
+ end
end
it "ignores spaces between directives" do
diff --git a/spec/ruby/core/array/pack/shared/integer.rb b/spec/ruby/core/array/pack/shared/integer.rb
index 6592f85022..fd21b25b19 100644
--- a/spec/ruby/core/array/pack/shared/integer.rb
+++ b/spec/ruby/core/array/pack/shared/integer.rb
@@ -41,9 +41,21 @@ describe :array_pack_16bit_le, shared: true do
str.should == "\x78\x65\xcd\xab\x21\x43"
end
- it "ignores NULL bytes between directives" do
- str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
- str.should == "\x78\x65\xcd\xab"
+ ruby_version_is ""..."3.3" do
+ it "ignores NULL bytes between directives" do
+ suppress_warning do
+ str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
+ str.should == "\x78\x65\xcd\xab"
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
+ }.should raise_error(ArgumentError, /unknown pack directive/)
+ end
end
it "ignores spaces between directives" do
@@ -93,9 +105,21 @@ describe :array_pack_16bit_be, shared: true do
str.should == "\x65\x78\xab\xcd\x43\x21"
end
- it "ignores NULL bytes between directives" do
- str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
- str.should == "\x65\x78\xab\xcd"
+ ruby_version_is ""..."3.3" do
+ it "ignores NULL bytes between directives" do
+ suppress_warning do
+ str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
+ str.should == "\x65\x78\xab\xcd"
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
+ }.should raise_error(ArgumentError, /unknown pack directive/)
+ end
end
it "ignores spaces between directives" do
@@ -145,9 +169,21 @@ describe :array_pack_32bit_le, shared: true do
str.should == "\x78\x65\x43\x12\xcd\xab\xf0\xde\x21\x43\x65\x78"
end
- it "ignores NULL bytes between directives" do
- str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
- str.should == "\x78\x65\x43\x12\xcd\xab\xf0\xde"
+ ruby_version_is ""..."3.3" do
+ it "ignores NULL bytes between directives" do
+ suppress_warning do
+ str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
+ str.should == "\x78\x65\x43\x12\xcd\xab\xf0\xde"
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
+ }.should raise_error(ArgumentError, /unknown pack directive/)
+ end
end
it "ignores spaces between directives" do
@@ -197,9 +233,21 @@ describe :array_pack_32bit_be, shared: true do
str.should == "\x12\x43\x65\x78\xde\xf0\xab\xcd\x78\x65\x43\x21"
end
- it "ignores NULL bytes between directives" do
- str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
- str.should == "\x12\x43\x65\x78\xde\xf0\xab\xcd"
+ ruby_version_is ""..."3.3" do
+ it "ignores NULL bytes between directives" do
+ suppress_warning do
+ str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
+ str.should == "\x12\x43\x65\x78\xde\xf0\xab\xcd"
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
+ }.should raise_error(ArgumentError, /unknown pack directive/)
+ end
end
it "ignores spaces between directives" do
@@ -309,9 +357,21 @@ describe :array_pack_64bit_le, shared: true do
str.should == "\x56\x78\x12\x34\xcd\xab\xf0\xde\xf0\xde\xba\xdc\x21\x43\x65\x78"
end
- it "ignores NULL bytes between directives" do
- str = [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2))
- str.should == "\x56\x78\x12\x34\xcd\xab\xf0\xde\xf0\xde\xba\xdc\x21\x43\x65\x78"
+ ruby_version_is ""..."3.3" do
+ it "ignores NULL bytes between directives" do
+ suppress_warning do
+ str = [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2))
+ str.should == "\x56\x78\x12\x34\xcd\xab\xf0\xde\xf0\xde\xba\xdc\x21\x43\x65\x78"
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2))
+ }.should raise_error(ArgumentError, /unknown pack directive/)
+ end
end
it "ignores spaces between directives" do
@@ -369,9 +429,21 @@ describe :array_pack_64bit_be, shared: true do
str.should == "\xde\xf0\xab\xcd\x34\x12\x78\x56\x78\x65\x43\x21\xdc\xba\xde\xf0"
end
- it "ignores NULL bytes between directives" do
- str = [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2))
- str.should == "\xde\xf0\xab\xcd\x34\x12\x78\x56\x78\x65\x43\x21\xdc\xba\xde\xf0"
+ ruby_version_is ""..."3.3" do
+ it "ignores NULL bytes between directives" do
+ suppress_warning do
+ str = [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2))
+ str.should == "\xde\xf0\xab\xcd\x34\x12\x78\x56\x78\x65\x43\x21\xdc\xba\xde\xf0"
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2))
+ }.should raise_error(ArgumentError, /unknown pack directive/)
+ end
end
it "ignores spaces between directives" do
diff --git a/spec/ruby/core/array/pack/shared/numeric_basic.rb b/spec/ruby/core/array/pack/shared/numeric_basic.rb
index 7c36ba4a32..545e215e64 100644
--- a/spec/ruby/core/array/pack/shared/numeric_basic.rb
+++ b/spec/ruby/core/array/pack/shared/numeric_basic.rb
@@ -37,8 +37,14 @@ describe :array_pack_float, shared: true do
-> { ["a"].pack(pack_format) }.should raise_error(TypeError)
end
- it "raises a TypeError when the object does not respond to #to_f" do
- obj = mock('not an float')
+ it "raises a TypeError when the object is not Numeric" do
+ obj = Object.new
+ -> { [obj].pack(pack_format) }.should raise_error(TypeError, /can't convert Object into Float/)
+ end
+
+ it "raises a TypeError when the Numeric object does not respond to #to_f" do
+ klass = Class.new(Numeric)
+ obj = klass.new
-> { [obj].pack(pack_format) }.should raise_error(TypeError)
end
end
diff --git a/spec/ruby/core/array/pack/shared/string.rb b/spec/ruby/core/array/pack/shared/string.rb
index 8c82e8c617..2f70dc3951 100644
--- a/spec/ruby/core/array/pack/shared/string.rb
+++ b/spec/ruby/core/array/pack/shared/string.rb
@@ -40,7 +40,7 @@ describe :array_pack_string, shared: true do
f = pack_format("*")
[ [["\u{3042 3044 3046 3048}", 0x2000B].pack(f+"U"), Encoding::BINARY],
[["abcde\xd1", "\xFF\xFe\x81\x82"].pack(f+"u"), Encoding::BINARY],
- [["a".force_encoding("ascii"), "\xFF\xFe\x81\x82"].pack(f+"u"), Encoding::BINARY],
+ [["a".dup.force_encoding("ascii"), "\xFF\xFe\x81\x82"].pack(f+"u"), Encoding::BINARY],
# under discussion [ruby-dev:37294]
[["\u{3042 3044 3046 3048}", 1].pack(f+"N"), Encoding::BINARY]
].should be_computed_by(:encoding)
diff --git a/spec/ruby/core/array/pack/shared/taint.rb b/spec/ruby/core/array/pack/shared/taint.rb
index 565f04b8b9..2c2b011c34 100644
--- a/spec/ruby/core/array/pack/shared/taint.rb
+++ b/spec/ruby/core/array/pack/shared/taint.rb
@@ -1,35 +1,2 @@
describe :array_pack_taint, shared: true do
- ruby_version_is ''...'2.7' do
- it "returns a tainted string when a pack argument is tainted" do
- ["abcd".taint, 0x20].pack(pack_format("3C")).tainted?.should be_true
- end
-
- it "does not return a tainted string when the array is tainted" do
- ["abcd", 0x20].taint.pack(pack_format("3C")).tainted?.should be_false
- end
-
- it "returns a tainted string when the format is tainted" do
- ["abcd", 0x20].pack(pack_format("3C").taint).tainted?.should be_true
- end
-
- it "returns a tainted string when an empty format is tainted" do
- ["abcd", 0x20].pack("".taint).tainted?.should be_true
- end
-
- it "returns a untrusted string when the format is untrusted" do
- ["abcd", 0x20].pack(pack_format("3C").untrust).untrusted?.should be_true
- end
-
- it "returns a untrusted string when the empty format is untrusted" do
- ["abcd", 0x20].pack("".untrust).untrusted?.should be_true
- end
-
- it "returns a untrusted string when a pack argument is untrusted" do
- ["abcd".untrust, 0x20].pack(pack_format("3C")).untrusted?.should be_true
- end
-
- it "returns a trusted string when the array is untrusted" do
- ["abcd", 0x20].untrust.pack(pack_format("3C")).untrusted?.should be_false
- end
- end
end
diff --git a/spec/ruby/core/array/pack/shared/unicode.rb b/spec/ruby/core/array/pack/shared/unicode.rb
index dd0f8b38aa..4d8eaef323 100644
--- a/spec/ruby/core/array/pack/shared/unicode.rb
+++ b/spec/ruby/core/array/pack/shared/unicode.rb
@@ -67,8 +67,20 @@ describe :array_pack_unicode, shared: true do
-> { [obj].pack("U") }.should raise_error(TypeError)
end
- it "ignores NULL bytes between directives" do
- [1, 2, 3].pack("U\x00U").should == "\x01\x02"
+ ruby_version_is ""..."3.3" do
+ it "ignores NULL bytes between directives" do
+ suppress_warning do
+ [1, 2, 3].pack("U\x00U").should == "\x01\x02"
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ [1, 2, 3].pack("U\x00U")
+ }.should raise_error(ArgumentError, /unknown pack directive/)
+ end
end
it "ignores spaces between directives" do
diff --git a/spec/ruby/core/array/pack/w_spec.rb b/spec/ruby/core/array/pack/w_spec.rb
index 439fa02198..48ed4496a5 100644
--- a/spec/ruby/core/array/pack/w_spec.rb
+++ b/spec/ruby/core/array/pack/w_spec.rb
@@ -24,8 +24,20 @@ describe "Array#pack with format 'w'" do
[obj].pack("w").should == "\x05"
end
- it "ignores NULL bytes between directives" do
- [1, 2, 3].pack("w\x00w").should == "\x01\x02"
+ ruby_version_is ""..."3.3" do
+ it "ignores NULL bytes between directives" do
+ suppress_warning do
+ [1, 2, 3].pack("w\x00w").should == "\x01\x02"
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ [1, 2, 3].pack("w\x00w")
+ }.should raise_error(ArgumentError, /unknown pack directive/)
+ end
end
it "ignores spaces between directives" do
diff --git a/spec/ruby/core/array/pack/x_spec.rb b/spec/ruby/core/array/pack/x_spec.rb
index a28dd0bf21..86c3ad1aa4 100644
--- a/spec/ruby/core/array/pack/x_spec.rb
+++ b/spec/ruby/core/array/pack/x_spec.rb
@@ -30,6 +30,7 @@ describe "Array#pack with format 'x'" do
it "does not add a NULL byte when passed the '*' modifier" do
[].pack("x*").should == ""
+ [1, 2].pack("Cx*C").should == "\x01\x02"
end
end
diff --git a/spec/ruby/core/array/plus_spec.rb b/spec/ruby/core/array/plus_spec.rb
index 45f8438208..635bd131c9 100644
--- a/spec/ruby/core/array/plus_spec.rb
+++ b/spec/ruby/core/array/plus_spec.rb
@@ -14,10 +14,23 @@ describe "Array#+" do
(ary + ary).should == [1, 2, 3, 1, 2, 3]
end
- it "tries to convert the passed argument to an Array using #to_ary" do
- obj = mock('["x", "y"]')
- obj.should_receive(:to_ary).and_return(["x", "y"])
- ([1, 2, 3] + obj).should == [1, 2, 3, "x", "y"]
+ describe "converts the passed argument to an Array using #to_ary" do
+ it "successfully concatenates the resulting array from the #to_ary call" do
+ obj = mock('["x", "y"]')
+ obj.should_receive(:to_ary).and_return(["x", "y"])
+ ([1, 2, 3] + obj).should == [1, 2, 3, "x", "y"]
+ end
+
+ it "raises a Typeerror if the given argument can't be converted to an array" do
+ -> { [1, 2, 3] + nil }.should raise_error(TypeError)
+ -> { [1, 2, 3] + "abc" }.should raise_error(TypeError)
+ end
+
+ it "raises a NoMethodError if the given argument raises a NoMethodError during type coercion to an Array" do
+ obj = mock("hello")
+ obj.should_receive(:to_ary).and_raise(NoMethodError)
+ -> { [1, 2, 3] + obj }.should raise_error(NoMethodError)
+ end
end
it "properly handles recursive arrays" do
@@ -40,20 +53,4 @@ describe "Array#+" do
it "does not call to_ary on array subclasses" do
([5, 6] + ArraySpecs::ToAryArray[1, 2]).should == [5, 6, 1, 2]
end
-
- ruby_version_is ''...'2.7' do
- it "does not get infected even if an original array is tainted" do
- ([1, 2] + [3, 4]).tainted?.should be_false
- ([1, 2].taint + [3, 4]).tainted?.should be_false
- ([1, 2] + [3, 4].taint).tainted?.should be_false
- ([1, 2].taint + [3, 4].taint).tainted?.should be_false
- end
-
- it "does not infected even if an original array is untrusted" do
- ([1, 2] + [3, 4]).untrusted?.should be_false
- ([1, 2].untrust + [3, 4]).untrusted?.should be_false
- ([1, 2] + [3, 4].untrust).untrusted?.should be_false
- ([1, 2].untrust + [3, 4].untrust).untrusted?.should be_false
- end
- end
end
diff --git a/spec/ruby/core/array/pop_spec.rb b/spec/ruby/core/array/pop_spec.rb
index 96ef78da32..2a19408660 100644
--- a/spec/ruby/core/array/pop_spec.rb
+++ b/spec/ruby/core/array/pop_spec.rb
@@ -30,16 +30,6 @@ describe "Array#pop" do
array.pop.should == [1, 'two', 3.0, array, array, array, array]
end
- ruby_version_is ''...'2.7' do
- it "keeps taint status" do
- a = [1, 2].taint
- a.pop
- a.tainted?.should be_true
- a.pop
- a.tainted?.should be_true
- end
- end
-
it "raises a FrozenError on a frozen array" do
-> { ArraySpecs.frozen_array.pop }.should raise_error(FrozenError)
end
@@ -48,16 +38,6 @@ describe "Array#pop" do
-> { ArraySpecs.empty_frozen_array.pop }.should raise_error(FrozenError)
end
- ruby_version_is ''...'2.7' do
- it "keeps untrusted status" do
- a = [1, 2].untrust
- a.pop
- a.untrusted?.should be_true
- a.pop
- a.untrusted?.should be_true
- end
- end
-
describe "passed a number n as an argument" do
it "removes and returns an array with the last n elements of the array" do
a = [1, 2, 3, 4, 5, 6]
@@ -136,41 +116,9 @@ describe "Array#pop" do
ArraySpecs::MyArray[1, 2, 3].pop(2).should be_an_instance_of(Array)
end
- ruby_version_is ''...'2.7' do
- it "returns an untainted array even if the array is tainted" do
- ary = [1, 2].taint
- ary.pop(2).tainted?.should be_false
- ary.pop(0).tainted?.should be_false
- end
-
- it "keeps taint status" do
- a = [1, 2].taint
- a.pop(2)
- a.tainted?.should be_true
- a.pop(2)
- a.tainted?.should be_true
- end
-
- it "returns a trusted array even if the array is untrusted" do
- ary = [1, 2].untrust
- ary.pop(2).untrusted?.should be_false
- ary.pop(0).untrusted?.should be_false
- end
- end
-
it "raises a FrozenError on a frozen array" do
-> { ArraySpecs.frozen_array.pop(2) }.should raise_error(FrozenError)
-> { ArraySpecs.frozen_array.pop(0) }.should raise_error(FrozenError)
end
-
- ruby_version_is ''...'2.7' do
- it "keeps untrusted status" do
- a = [1, 2].untrust
- a.pop(2)
- a.untrusted?.should be_true
- a.pop(2)
- a.untrusted?.should be_true
- end
- end
end
end
diff --git a/spec/ruby/core/array/product_spec.rb b/spec/ruby/core/array/product_spec.rb
index 07d2880a96..6fb3818508 100644
--- a/spec/ruby/core/array/product_spec.rb
+++ b/spec/ruby/core/array/product_spec.rb
@@ -9,6 +9,11 @@ describe "Array#product" do
ar.called.should == :to_ary
end
+ it "returns converted arguments using :method_missing" do
+ ar = ArraySpecs::ArrayMethodMissing.new(2,3)
+ [1].product(ar).should == [[1,2],[1,3]]
+ end
+
it "returns the expected result" do
[1,2].product([3,4,5],[6,8]).should == [[1, 3, 6], [1, 3, 8], [1, 4, 6], [1, 4, 8], [1, 5, 6], [1, 5, 8],
[2, 3, 6], [2, 3, 8], [2, 4, 6], [2, 4, 8], [2, 5, 6], [2, 5, 8]]
diff --git a/spec/ruby/core/array/rassoc_spec.rb b/spec/ruby/core/array/rassoc_spec.rb
index 62fbd40611..632a05e8b3 100644
--- a/spec/ruby/core/array/rassoc_spec.rb
+++ b/spec/ruby/core/array/rassoc_spec.rb
@@ -35,4 +35,18 @@ describe "Array#rassoc" do
[[1, :foobar, o], [2, o, 1], [3, mock('foo')]].rassoc(key).should == [2, o, 1]
end
+
+ ruby_version_is "3.3" do
+ it "calls to_ary on non-array elements" do
+ s1 = [1, 2]
+ s2 = ArraySpecs::ArrayConvertible.new(2, 3)
+ a = [s1, s2]
+
+ s1.should_not_receive(:to_ary)
+ a.rassoc(2).should equal(s1)
+
+ a.rassoc(3).should == [2, 3]
+ s2.called.should equal(:to_ary)
+ end
+ end
end
diff --git a/spec/ruby/core/array/reject_spec.rb b/spec/ruby/core/array/reject_spec.rb
index fcf43fabde..81a467e364 100644
--- a/spec/ruby/core/array/reject_spec.rb
+++ b/spec/ruby/core/array/reject_spec.rb
@@ -2,6 +2,7 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
require_relative 'shared/enumeratorize'
require_relative 'shared/delete_if'
+require_relative 'shared/iterable_and_tolerating_size_increasing'
require_relative '../enumerable/shared/enumeratorized'
describe "Array#reject" do
@@ -47,6 +48,10 @@ describe "Array#reject" do
it_behaves_like :enumeratorized_with_origin_size, :reject, [1,2,3]
end
+describe "Array#reject" do
+ it_behaves_like :array_iterable_and_tolerating_size_increasing, :reject
+end
+
describe "Array#reject!" do
it "removes elements for which block is true" do
a = [3, 4, 5, 6, 7, 8, 9, 10, 11]
@@ -111,6 +116,11 @@ describe "Array#reject!" do
-> { ArraySpecs.empty_frozen_array.reject! {} }.should raise_error(FrozenError)
end
+ it "raises a FrozenError on a frozen array only during iteration if called without a block" do
+ enum = ArraySpecs.frozen_array.reject!
+ -> { enum.each {} }.should raise_error(FrozenError)
+ end
+
it "does not truncate the array is the block raises an exception" do
a = [1, 2, 3]
begin
@@ -141,3 +151,8 @@ describe "Array#reject!" do
it_behaves_like :enumeratorized_with_origin_size, :reject!, [1,2,3]
it_behaves_like :delete_if, :reject!
end
+
+describe "Array#reject!" do
+ @value_to_return = -> _ { false }
+ it_behaves_like :array_iterable_and_tolerating_size_increasing, :reject!
+end
diff --git a/spec/ruby/core/array/reverse_each_spec.rb b/spec/ruby/core/array/reverse_each_spec.rb
index 28b8bfcb34..59dabcd33d 100644
--- a/spec/ruby/core/array/reverse_each_spec.rb
+++ b/spec/ruby/core/array/reverse_each_spec.rb
@@ -5,7 +5,7 @@ require_relative '../enumerable/shared/enumeratorized'
# Modifying a collection while the contents are being iterated
# gives undefined behavior. See
-# http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/23633
+# https://blade.ruby-lang.org/ruby-core/23633
describe "Array#reverse_each" do
before :each do
@@ -38,6 +38,20 @@ describe "Array#reverse_each" do
[1, 2, 3].reverse_each.size.should == 3
end
+ it "tolerates increasing an array size during iteration" do
+ array = [:a, :b, :c]
+ ScratchPad.record []
+ i = 0
+
+ array.reverse_each do |e|
+ ScratchPad << e
+ array.prepend i if i < 100
+ i += 1
+ end
+
+ ScratchPad.recorded.should == [:c, :a, 1]
+ end
+
it_behaves_like :enumeratorize, :reverse_each
it_behaves_like :enumeratorized_with_origin_size, :reverse_each, [1,2,3]
end
diff --git a/spec/ruby/core/array/rindex_spec.rb b/spec/ruby/core/array/rindex_spec.rb
index 175c7bcfe2..13de88818c 100644
--- a/spec/ruby/core/array/rindex_spec.rb
+++ b/spec/ruby/core/array/rindex_spec.rb
@@ -4,7 +4,7 @@ require_relative '../enumerable/shared/enumeratorized'
# Modifying a collection while the contents are being iterated
# gives undefined behavior. See
-# http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/23633
+# https://blade.ruby-lang.org/ruby-core/23633
describe "Array#rindex" do
it "returns the first index backwards from the end where element == to object" do
@@ -68,6 +68,21 @@ describe "Array#rindex" do
seen.should == [3]
end
+ it "tolerates increasing an array size during iteration" do
+ array = [:a, :b, :c]
+ ScratchPad.record []
+ i = 0
+
+ array.rindex do |e|
+ ScratchPad << e
+ array.prepend i if i < 100
+ i += 1
+ false
+ end
+
+ ScratchPad.recorded.should == [:c, :a, 1]
+ end
+
describe "given no argument and no block" do
it "produces an Enumerator" do
enum = [4, 2, 1, 5, 1, 3].rindex
diff --git a/spec/ruby/core/array/sample_spec.rb b/spec/ruby/core/array/sample_spec.rb
index 565d7ff7f9..6ef78594f0 100644
--- a/spec/ruby/core/array/sample_spec.rb
+++ b/spec/ruby/core/array/sample_spec.rb
@@ -3,26 +3,36 @@ require_relative 'fixtures/classes'
describe "Array#sample" do
it "samples evenly" do
- ary = [0, 1, 2, 3]
- 3.times do |i|
- counts = [0, 0, 0, 0]
- 4000.times do
- counts[ary.sample(3)[i]] += 1
- end
- counts.each do |count|
- (800..1200).should include(count)
- end
- end
+ ArraySpecs.measure_sample_fairness(4, 1, 400)
+ ArraySpecs.measure_sample_fairness(4, 2, 400)
+ ArraySpecs.measure_sample_fairness(4, 3, 400)
+ ArraySpecs.measure_sample_fairness(40, 3, 400)
+ ArraySpecs.measure_sample_fairness(40, 4, 400)
+ ArraySpecs.measure_sample_fairness(40, 8, 400)
+ ArraySpecs.measure_sample_fairness(40, 16, 400)
+ ArraySpecs.measure_sample_fairness_large_sample_size(100, 80, 4000)
end
it "returns nil for an empty Array" do
[].sample.should be_nil
end
+ it "returns nil for an empty array when called without n and a Random is given" do
+ [].sample(random: Random.new(42)).should be_nil
+ end
+
it "returns a single value when not passed a count" do
[4].sample.should equal(4)
end
+ it "returns a single value when not passed a count and a Random is given" do
+ [4].sample(random: Random.new(42)).should equal(4)
+ end
+
+ it "returns a single value when not passed a count and a Random class is given" do
+ [4].sample(random: Random).should equal(4)
+ end
+
it "returns an empty Array when passed zero" do
[4].sample(0).should == []
end
diff --git a/spec/ruby/core/array/shared/clone.rb b/spec/ruby/core/array/shared/clone.rb
index 3c17b1f10f..035b45ec99 100644
--- a/spec/ruby/core/array/shared/clone.rb
+++ b/spec/ruby/core/array/shared/clone.rb
@@ -17,28 +17,4 @@ describe :array_clone, shared: true do
b.should == a
b.__id__.should_not == a.__id__
end
-
- ruby_version_is ''...'2.7' do
- it "copies taint status from the original" do
- a = [1, 2, 3, 4]
- b = [1, 2, 3, 4]
- a.taint
- aa = a.send @method
- bb = b.send @method
-
- aa.should.tainted?
- bb.should_not.tainted?
- end
-
- it "copies untrusted status from the original" do
- a = [1, 2, 3, 4]
- b = [1, 2, 3, 4]
- a.untrust
- aa = a.send @method
- bb = b.send @method
-
- aa.should.untrusted?
- bb.should_not.untrusted?
- end
- end
end
diff --git a/spec/ruby/core/array/shared/collect.rb b/spec/ruby/core/array/shared/collect.rb
index d84432734a..030302ced6 100644
--- a/spec/ruby/core/array/shared/collect.rb
+++ b/spec/ruby/core/array/shared/collect.rb
@@ -1,4 +1,5 @@
require_relative '../../enumerable/shared/enumeratorized'
+require_relative '../shared/iterable_and_tolerating_size_increasing'
describe :array_collect, shared: true do
it "returns a copy of array with each element replaced by the value returned by block" do
@@ -42,24 +43,12 @@ describe :array_collect, shared: true do
}.should raise_error(ArgumentError)
end
- ruby_version_is ''...'2.7' do
- it "does not copy tainted status" do
- a = [1, 2, 3]
- a.taint
- a.send(@method){|x| x}.tainted?.should be_false
- end
-
- it "does not copy untrusted status" do
- a = [1, 2, 3]
- a.untrust
- a.send(@method){|x| x}.untrusted?.should be_false
- end
- end
-
before :all do
@object = [1, 2, 3, 4]
end
it_should_behave_like :enumeratorized_with_origin_size
+
+ it_should_behave_like :array_iterable_and_tolerating_size_increasing
end
describe :array_collect_b, shared: true do
@@ -96,23 +85,6 @@ describe :array_collect_b, shared: true do
a.should == ["1!", "2!", "3!"]
end
- ruby_version_is ''...'2.7' do
- it "keeps tainted status" do
- a = [1, 2, 3]
- a.taint
- a.tainted?.should be_true
- a.send(@method){|x| x}
- a.tainted?.should be_true
- end
-
- it "keeps untrusted status" do
- a = [1, 2, 3]
- a.untrust
- a.send(@method){|x| x}
- a.untrusted?.should be_true
- end
- end
-
describe "when frozen" do
it "raises a FrozenError" do
-> { ArraySpecs.frozen_array.send(@method) {} }.should raise_error(FrozenError)
@@ -133,8 +105,37 @@ describe :array_collect_b, shared: true do
end
end
+ it "does not truncate the array is the block raises an exception" do
+ a = [1, 2, 3]
+ begin
+ a.send(@method) { raise StandardError, 'Oops' }
+ rescue
+ end
+
+ a.should == [1, 2, 3]
+ end
+
+ it "only changes elements before error is raised, keeping the element which raised an error." do
+ a = [1, 2, 3, 4]
+ begin
+ a.send(@method) do |e|
+ case e
+ when 1 then -1
+ when 2 then -2
+ when 3 then raise StandardError, 'Oops'
+ else 0
+ end
+ end
+ rescue StandardError
+ end
+
+ a.should == [-1, -2, 3, 4]
+ end
+
before :all do
@object = [1, 2, 3, 4]
end
it_should_behave_like :enumeratorized_with_origin_size
+
+ it_should_behave_like :array_iterable_and_tolerating_size_increasing
end
diff --git a/spec/ruby/core/array/shared/index.rb b/spec/ruby/core/array/shared/index.rb
index a9896554f2..a4a0adbab6 100644
--- a/spec/ruby/core/array/shared/index.rb
+++ b/spec/ruby/core/array/shared/index.rb
@@ -1,3 +1,5 @@
+require_relative '../shared/iterable_and_tolerating_size_increasing'
+
describe :array_index, shared: true do
it "returns the index of the first element == to object" do
x = mock('3')
@@ -34,4 +36,6 @@ describe :array_index, shared: true do
[].send(@method).should be_an_instance_of(Enumerator)
end
end
+
+ it_should_behave_like :array_iterable_and_tolerating_size_increasing
end
diff --git a/spec/ruby/core/array/shared/inspect.rb b/spec/ruby/core/array/shared/inspect.rb
index 736f8d946b..af5128c645 100644
--- a/spec/ruby/core/array/shared/inspect.rb
+++ b/spec/ruby/core/array/shared/inspect.rb
@@ -19,7 +19,7 @@ describe :array_inspect, shared: true do
end
it "does not call #to_s on a String returned from #inspect" do
- str = "abc"
+ str = +"abc"
str.should_not_receive(:to_s)
[str].send(@method).should == '["abc"]'
@@ -64,32 +64,6 @@ describe :array_inspect, shared: true do
ArraySpecs.empty_recursive_array.send(@method).should == "[[...]]"
end
- ruby_version_is ''...'2.7' do
- it "taints the result if the Array is non-empty and tainted" do
- [1, 2].taint.send(@method).tainted?.should be_true
- end
-
- it "does not taint the result if the Array is tainted but empty" do
- [].taint.send(@method).tainted?.should be_false
- end
-
- it "taints the result if an element is tainted" do
- ["str".taint].send(@method).tainted?.should be_true
- end
-
- it "untrusts the result if the Array is untrusted" do
- [1, 2].untrust.send(@method).untrusted?.should be_true
- end
-
- it "does not untrust the result if the Array is untrusted but empty" do
- [].untrust.send(@method).untrusted?.should be_false
- end
-
- it "untrusts the result if an element is untrusted" do
- ["str".untrust].send(@method).untrusted?.should be_true
- end
- end
-
describe "with encoding" do
before :each do
@default_external_encoding = Encoding.default_external
@@ -124,8 +98,8 @@ describe :array_inspect, shared: true do
end
it "does not raise if inspected result is not default external encoding" do
- utf_16be = mock("utf_16be")
- utf_16be.should_receive(:inspect).and_return(%<"utf_16be \u3042">.encode!(Encoding::UTF_16BE))
+ utf_16be = mock(+"utf_16be")
+ utf_16be.should_receive(:inspect).and_return(%<"utf_16be \u3042">.encode(Encoding::UTF_16BE))
[utf_16be].send(@method).should == '["utf_16be \u3042"]'
end
diff --git a/spec/ruby/core/array/shared/intersection.rb b/spec/ruby/core/array/shared/intersection.rb
index 49849b08c2..0b4166ab63 100644
--- a/spec/ruby/core/array/shared/intersection.rb
+++ b/spec/ruby/core/array/shared/intersection.rb
@@ -11,7 +11,8 @@ describe :array_intersection, shared: true do
end
it "creates an array with elements in order they are first encountered" do
- [ 1, 2, 3, 2, 5 ].send(@method, [ 5, 2, 3, 4 ]).should == [2, 3, 5]
+ [ 1, 2, 3, 2, 5, 6, 7, 8 ].send(@method, [ 5, 2, 3, 4 ]).should == [2, 3, 5] # array > other
+ [ 5, 2, 3, 4 ].send(@method, [ 1, 2, 3, 2, 5, 6, 7, 8 ]).should == [5, 2, 3] # array < other
end
it "does not modify the original Array" do
diff --git a/spec/ruby/core/array/shared/iterable_and_tolerating_size_increasing.rb b/spec/ruby/core/array/shared/iterable_and_tolerating_size_increasing.rb
new file mode 100644
index 0000000000..3e73bad44b
--- /dev/null
+++ b/spec/ruby/core/array/shared/iterable_and_tolerating_size_increasing.rb
@@ -0,0 +1,25 @@
+describe :array_iterable_and_tolerating_size_increasing, shared: true do
+ before do
+ @value_to_return ||= -> _ { nil }
+ end
+
+ it "tolerates increasing an array size during iteration" do
+ # The goal is to trigger potential reallocation of internal array storage, so we:
+ # - use elements of different types, starting with the less generic (Integer)
+ # - add reasonably big number of new elements (~ 100)
+ array = [1, 2, 3] # to test some methods we need several uniq elements
+ array_to_join = [:a, :b, :c] + (4..100).to_a
+
+ ScratchPad.record []
+ i = 0
+
+ array.send(@method) do |e|
+ ScratchPad << e
+ array << array_to_join[i] if i < array_to_join.size
+ i += 1
+ @value_to_return.call(e)
+ end
+
+ ScratchPad.recorded.should == [1, 2, 3] + array_to_join
+ end
+end
diff --git a/spec/ruby/core/array/shared/join.rb b/spec/ruby/core/array/shared/join.rb
index dfdb4ae1e4..507b13e3c8 100644
--- a/spec/ruby/core/array/shared/join.rb
+++ b/spec/ruby/core/array/shared/join.rb
@@ -58,36 +58,6 @@ describe :array_join_with_default_separator, shared: true do
-> { ArraySpecs.empty_recursive_array.send(@method) }.should raise_error(ArgumentError)
end
- ruby_version_is ''...'2.7' do
- it "taints the result if the Array is tainted and non-empty" do
- [1, 2].taint.send(@method).tainted?.should be_true
- end
-
- it "does not taint the result if the Array is tainted but empty" do
- [].taint.send(@method).tainted?.should be_false
- end
-
- it "taints the result if the result of coercing an element is tainted" do
- s = mock("taint")
- s.should_receive(:to_s).and_return("str".taint)
- [s].send(@method).tainted?.should be_true
- end
-
- it "untrusts the result if the Array is untrusted and non-empty" do
- [1, 2].untrust.send(@method).untrusted?.should be_true
- end
-
- it "does not untrust the result if the Array is untrusted but empty" do
- [].untrust.send(@method).untrusted?.should be_false
- end
-
- it "untrusts the result if the result of coercing an element is untrusted" do
- s = mock("untrust")
- s.should_receive(:to_s).and_return("str".untrust)
- [s].send(@method).untrusted?.should be_true
- end
- end
-
it "uses the first encoding when other strings are compatible" do
ary1 = ArraySpecs.array_with_7bit_utf8_and_usascii_strings
ary2 = ArraySpecs.array_with_usascii_and_7bit_utf8_strings
@@ -114,18 +84,16 @@ describe :array_join_with_default_separator, shared: true do
-> { ary_utf8_bad_binary.send(@method) }.should raise_error(EncodingError)
end
- ruby_version_is "2.7" do
- context "when $, is not nil" do
- before do
- suppress_warning do
- $, = '*'
- end
+ context "when $, is not nil" do
+ before do
+ suppress_warning do
+ $, = '*'
end
+ end
- it "warns" do
- -> { [].join }.should complain(/warning: \$, is set to non-nil value/)
- -> { [].join(nil) }.should complain(/warning: \$, is set to non-nil value/)
- end
+ it "warns" do
+ -> { [].join }.should complain(/warning: \$, is set to non-nil value/)
+ -> { [].join(nil) }.should complain(/warning: \$, is set to non-nil value/)
end
end
end
@@ -141,42 +109,4 @@ describe :array_join_with_string_separator, shared: true do
[1, [2, [3, 4], 5], 6].send(@method, ":").should == "1:2:3:4:5:6"
[1, [2, ArraySpecs::MyArray[3, 4], 5], 6].send(@method, ":").should == "1:2:3:4:5:6"
end
-
- ruby_version_is ''...'2.7' do
- describe "with a tainted separator" do
- before :each do
- @sep = ":".taint
- end
-
- it "does not taint the result if the array is empty" do
- [].send(@method, @sep).tainted?.should be_false
- end
-
- it "does not taint the result if the array has only one element" do
- [1].send(@method, @sep).tainted?.should be_false
- end
-
- it "taints the result if the array has two or more elements" do
- [1, 2].send(@method, @sep).tainted?.should be_true
- end
- end
-
- describe "with an untrusted separator" do
- before :each do
- @sep = ":".untrust
- end
-
- it "does not untrust the result if the array is empty" do
- [].send(@method, @sep).untrusted?.should be_false
- end
-
- it "does not untrust the result if the array has only one element" do
- [1].send(@method, @sep).untrusted?.should be_false
- end
-
- it "untrusts the result if the array has two or more elements" do
- [1, 2].send(@method, @sep).untrusted?.should be_true
- end
- end
- end
end
diff --git a/spec/ruby/core/array/shared/keep_if.rb b/spec/ruby/core/array/shared/keep_if.rb
index f26aff028c..43a047c0a7 100644
--- a/spec/ruby/core/array/shared/keep_if.rb
+++ b/spec/ruby/core/array/shared/keep_if.rb
@@ -1,4 +1,5 @@
require_relative '../../enumerable/shared/enumeratorized'
+require_relative '../shared/iterable_and_tolerating_size_increasing'
describe :keep_if, shared: true do
it "deletes elements for which the block returns a false value" do
@@ -56,5 +57,39 @@ describe :keep_if, shared: true do
-> { @frozen.send(@method) { false } }.should raise_error(FrozenError)
end
end
+
+ it "raises a FrozenError on a frozen array only during iteration if called without a block" do
+ enum = @frozen.send(@method)
+ -> { enum.each {} }.should raise_error(FrozenError)
+ end
+ end
+
+ it "does not truncate the array is the block raises an exception" do
+ a = [1, 2, 3]
+ begin
+ a.send(@method) { raise StandardError, 'Oops' }
+ rescue
+ end
+
+ a.should == [1, 2, 3]
end
+
+ it "only changes elements before error is raised, keeping the element which raised an error." do
+ a = [1, 2, 3, 4]
+ begin
+ a.send(@method) do |e|
+ case e
+ when 2 then false
+ when 3 then raise StandardError, 'Oops'
+ else true
+ end
+ end
+ rescue StandardError
+ end
+
+ a.should == [1, 3, 4]
+ end
+
+ @value_to_return = -> _ { true }
+ it_should_behave_like :array_iterable_and_tolerating_size_increasing
end
diff --git a/spec/ruby/core/array/shared/select.rb b/spec/ruby/core/array/shared/select.rb
index 09101e8ab5..9c2cbf76c4 100644
--- a/spec/ruby/core/array/shared/select.rb
+++ b/spec/ruby/core/array/shared/select.rb
@@ -2,11 +2,14 @@ require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
require_relative '../shared/enumeratorize'
require_relative '../shared/keep_if'
+require_relative '../shared/iterable_and_tolerating_size_increasing'
require_relative '../../enumerable/shared/enumeratorized'
describe :array_select, shared: true do
it_should_behave_like :enumeratorize
+ it_should_behave_like :array_iterable_and_tolerating_size_increasing
+
before :each do
@object = [1,2,3]
end
diff --git a/spec/ruby/core/array/shared/slice.rb b/spec/ruby/core/array/shared/slice.rb
index 540a050130..d2866970a5 100644
--- a/spec/ruby/core/array/shared/slice.rb
+++ b/spec/ruby/core/array/shared/slice.rb
@@ -397,56 +397,28 @@ describe :array_slice, shared: true do
@array = ArraySpecs::MyArray[1, 2, 3, 4, 5]
end
- ruby_version_is ''...'3.0' do
- it "returns a subclass instance with [n, m]" do
- @array.send(@method, 0, 2).should be_an_instance_of(ArraySpecs::MyArray)
- end
-
- it "returns a subclass instance with [-n, m]" do
- @array.send(@method, -3, 2).should be_an_instance_of(ArraySpecs::MyArray)
- end
-
- it "returns a subclass instance with [n..m]" do
- @array.send(@method, 1..3).should be_an_instance_of(ArraySpecs::MyArray)
- end
-
- it "returns a subclass instance with [n...m]" do
- @array.send(@method, 1...3).should be_an_instance_of(ArraySpecs::MyArray)
- end
-
- it "returns a subclass instance with [-n..-m]" do
- @array.send(@method, -3..-1).should be_an_instance_of(ArraySpecs::MyArray)
- end
-
- it "returns a subclass instance with [-n...-m]" do
- @array.send(@method, -3...-1).should be_an_instance_of(ArraySpecs::MyArray)
- end
+ it "returns a Array instance with [n, m]" do
+ @array.send(@method, 0, 2).should be_an_instance_of(Array)
end
- ruby_version_is '3.0' do
- it "returns a Array instance with [n, m]" do
- @array.send(@method, 0, 2).should be_an_instance_of(Array)
- end
-
- it "returns a Array instance with [-n, m]" do
- @array.send(@method, -3, 2).should be_an_instance_of(Array)
- end
+ it "returns a Array instance with [-n, m]" do
+ @array.send(@method, -3, 2).should be_an_instance_of(Array)
+ end
- it "returns a Array instance with [n..m]" do
- @array.send(@method, 1..3).should be_an_instance_of(Array)
- end
+ it "returns a Array instance with [n..m]" do
+ @array.send(@method, 1..3).should be_an_instance_of(Array)
+ end
- it "returns a Array instance with [n...m]" do
- @array.send(@method, 1...3).should be_an_instance_of(Array)
- end
+ it "returns a Array instance with [n...m]" do
+ @array.send(@method, 1...3).should be_an_instance_of(Array)
+ end
- it "returns a Array instance with [-n..-m]" do
- @array.send(@method, -3..-1).should be_an_instance_of(Array)
- end
+ it "returns a Array instance with [-n..-m]" do
+ @array.send(@method, -3..-1).should be_an_instance_of(Array)
+ end
- it "returns a Array instance with [-n...-m]" do
- @array.send(@method, -3...-1).should be_an_instance_of(Array)
- end
+ it "returns a Array instance with [-n...-m]" do
+ @array.send(@method, -3...-1).should be_an_instance_of(Array)
end
it "returns an empty array when m == n with [m...n]" do
@@ -534,262 +506,354 @@ describe :array_slice, shared: true do
a.send(@method, eval("(-9...)")).should == nil
end
- ruby_version_is "3.0" do
- describe "can be sliced with Enumerator::ArithmeticSequence" do
- before :each do
- @array = [0, 1, 2, 3, 4, 5]
- end
+ describe "can be sliced with Enumerator::ArithmeticSequence" do
+ before :each do
+ @array = [0, 1, 2, 3, 4, 5]
+ end
- it "has endless range and positive steps" do
- @array.send(@method, eval("(0..).step(1)")).should == [0, 1, 2, 3, 4, 5]
- @array.send(@method, eval("(0..).step(2)")).should == [0, 2, 4]
- @array.send(@method, eval("(0..).step(10)")).should == [0]
+ it "has endless range and positive steps" do
+ @array.send(@method, eval("(0..).step(1)")).should == [0, 1, 2, 3, 4, 5]
+ @array.send(@method, eval("(0..).step(2)")).should == [0, 2, 4]
+ @array.send(@method, eval("(0..).step(10)")).should == [0]
- @array.send(@method, eval("(2..).step(1)")).should == [2, 3, 4, 5]
- @array.send(@method, eval("(2..).step(2)")).should == [2, 4]
- @array.send(@method, eval("(2..).step(10)")).should == [2]
+ @array.send(@method, eval("(2..).step(1)")).should == [2, 3, 4, 5]
+ @array.send(@method, eval("(2..).step(2)")).should == [2, 4]
+ @array.send(@method, eval("(2..).step(10)")).should == [2]
- @array.send(@method, eval("(-3..).step(1)")).should == [3, 4, 5]
- @array.send(@method, eval("(-3..).step(2)")).should == [3, 5]
- @array.send(@method, eval("(-3..).step(10)")).should == [3]
- end
+ @array.send(@method, eval("(-3..).step(1)")).should == [3, 4, 5]
+ @array.send(@method, eval("(-3..).step(2)")).should == [3, 5]
+ @array.send(@method, eval("(-3..).step(10)")).should == [3]
+ end
- it "has beginless range and positive steps" do
- # end with zero index
- @array.send(@method, eval("(..0).step(1)")).should == [0]
- @array.send(@method, eval("(...0).step(1)")).should == []
+ it "has beginless range and positive steps" do
+ # end with zero index
+ @array.send(@method, (..0).step(1)).should == [0]
+ @array.send(@method, (...0).step(1)).should == []
- @array.send(@method, eval("(..0).step(2)")).should == [0]
- @array.send(@method, eval("(...0).step(2)")).should == []
+ @array.send(@method, (..0).step(2)).should == [0]
+ @array.send(@method, (...0).step(2)).should == []
- @array.send(@method, eval("(..0).step(10)")).should == [0]
- @array.send(@method, eval("(...0).step(10)")).should == []
+ @array.send(@method, (..0).step(10)).should == [0]
+ @array.send(@method, (...0).step(10)).should == []
- # end with positive index
- @array.send(@method, eval("(..3).step(1)")).should == [0, 1, 2, 3]
- @array.send(@method, eval("(...3).step(1)")).should == [0, 1, 2]
+ # end with positive index
+ @array.send(@method, (..3).step(1)).should == [0, 1, 2, 3]
+ @array.send(@method, (...3).step(1)).should == [0, 1, 2]
- @array.send(@method, eval("(..3).step(2)")).should == [0, 2]
- @array.send(@method, eval("(...3).step(2)")).should == [0, 2]
+ @array.send(@method, (..3).step(2)).should == [0, 2]
+ @array.send(@method, (...3).step(2)).should == [0, 2]
- @array.send(@method, eval("(..3).step(10)")).should == [0]
- @array.send(@method, eval("(...3).step(10)")).should == [0]
+ @array.send(@method, (..3).step(10)).should == [0]
+ @array.send(@method, (...3).step(10)).should == [0]
- # end with negative index
- @array.send(@method, eval("(..-2).step(1)")).should == [0, 1, 2, 3, 4,]
- @array.send(@method, eval("(...-2).step(1)")).should == [0, 1, 2, 3]
+ # end with negative index
+ @array.send(@method, (..-2).step(1)).should == [0, 1, 2, 3, 4,]
+ @array.send(@method, (...-2).step(1)).should == [0, 1, 2, 3]
- @array.send(@method, eval("(..-2).step(2)")).should == [0, 2, 4]
- @array.send(@method, eval("(...-2).step(2)")).should == [0, 2]
+ @array.send(@method, (..-2).step(2)).should == [0, 2, 4]
+ @array.send(@method, (...-2).step(2)).should == [0, 2]
- @array.send(@method, eval("(..-2).step(10)")).should == [0]
- @array.send(@method, eval("(...-2).step(10)")).should == [0]
- end
+ @array.send(@method, (..-2).step(10)).should == [0]
+ @array.send(@method, (...-2).step(10)).should == [0]
+ end
- it "has endless range and negative steps" do
- @array.send(@method, eval("(0..).step(-1)")).should == [0]
- @array.send(@method, eval("(0..).step(-2)")).should == [0]
- @array.send(@method, eval("(0..).step(-10)")).should == [0]
+ it "has endless range and negative steps" do
+ @array.send(@method, eval("(0..).step(-1)")).should == [0]
+ @array.send(@method, eval("(0..).step(-2)")).should == [0]
+ @array.send(@method, eval("(0..).step(-10)")).should == [0]
- @array.send(@method, eval("(2..).step(-1)")).should == [2, 1, 0]
- @array.send(@method, eval("(2..).step(-2)")).should == [2, 0]
+ @array.send(@method, eval("(2..).step(-1)")).should == [2, 1, 0]
+ @array.send(@method, eval("(2..).step(-2)")).should == [2, 0]
- @array.send(@method, eval("(-3..).step(-1)")).should == [3, 2, 1, 0]
- @array.send(@method, eval("(-3..).step(-2)")).should == [3, 1]
- end
+ @array.send(@method, eval("(-3..).step(-1)")).should == [3, 2, 1, 0]
+ @array.send(@method, eval("(-3..).step(-2)")).should == [3, 1]
+ end
- it "has closed range and positive steps" do
- # start and end with 0
- @array.send(@method, eval("(0..0).step(1)")).should == [0]
- @array.send(@method, eval("(0...0).step(1)")).should == []
+ it "has closed range and positive steps" do
+ # start and end with 0
+ @array.send(@method, eval("(0..0).step(1)")).should == [0]
+ @array.send(@method, eval("(0...0).step(1)")).should == []
- @array.send(@method, eval("(0..0).step(2)")).should == [0]
- @array.send(@method, eval("(0...0).step(2)")).should == []
+ @array.send(@method, eval("(0..0).step(2)")).should == [0]
+ @array.send(@method, eval("(0...0).step(2)")).should == []
- @array.send(@method, eval("(0..0).step(10)")).should == [0]
- @array.send(@method, eval("(0...0).step(10)")).should == []
+ @array.send(@method, eval("(0..0).step(10)")).should == [0]
+ @array.send(@method, eval("(0...0).step(10)")).should == []
- # start and end with positive index
- @array.send(@method, eval("(1..3).step(1)")).should == [1, 2, 3]
- @array.send(@method, eval("(1...3).step(1)")).should == [1, 2]
+ # start and end with positive index
+ @array.send(@method, eval("(1..3).step(1)")).should == [1, 2, 3]
+ @array.send(@method, eval("(1...3).step(1)")).should == [1, 2]
- @array.send(@method, eval("(1..3).step(2)")).should == [1, 3]
- @array.send(@method, eval("(1...3).step(2)")).should == [1]
+ @array.send(@method, eval("(1..3).step(2)")).should == [1, 3]
+ @array.send(@method, eval("(1...3).step(2)")).should == [1]
- @array.send(@method, eval("(1..3).step(10)")).should == [1]
- @array.send(@method, eval("(1...3).step(10)")).should == [1]
+ @array.send(@method, eval("(1..3).step(10)")).should == [1]
+ @array.send(@method, eval("(1...3).step(10)")).should == [1]
- # start with positive index, end with negative index
- @array.send(@method, eval("(1..-2).step(1)")).should == [1, 2, 3, 4]
- @array.send(@method, eval("(1...-2).step(1)")).should == [1, 2, 3]
+ # start with positive index, end with negative index
+ @array.send(@method, eval("(1..-2).step(1)")).should == [1, 2, 3, 4]
+ @array.send(@method, eval("(1...-2).step(1)")).should == [1, 2, 3]
- @array.send(@method, eval("(1..-2).step(2)")).should == [1, 3]
- @array.send(@method, eval("(1...-2).step(2)")).should == [1, 3]
+ @array.send(@method, eval("(1..-2).step(2)")).should == [1, 3]
+ @array.send(@method, eval("(1...-2).step(2)")).should == [1, 3]
- @array.send(@method, eval("(1..-2).step(10)")).should == [1]
- @array.send(@method, eval("(1...-2).step(10)")).should == [1]
+ @array.send(@method, eval("(1..-2).step(10)")).should == [1]
+ @array.send(@method, eval("(1...-2).step(10)")).should == [1]
- # start with negative index, end with positive index
- @array.send(@method, eval("(-4..4).step(1)")).should == [2, 3, 4]
- @array.send(@method, eval("(-4...4).step(1)")).should == [2, 3]
+ # start with negative index, end with positive index
+ @array.send(@method, eval("(-4..4).step(1)")).should == [2, 3, 4]
+ @array.send(@method, eval("(-4...4).step(1)")).should == [2, 3]
- @array.send(@method, eval("(-4..4).step(2)")).should == [2, 4]
- @array.send(@method, eval("(-4...4).step(2)")).should == [2]
+ @array.send(@method, eval("(-4..4).step(2)")).should == [2, 4]
+ @array.send(@method, eval("(-4...4).step(2)")).should == [2]
- @array.send(@method, eval("(-4..4).step(10)")).should == [2]
- @array.send(@method, eval("(-4...4).step(10)")).should == [2]
+ @array.send(@method, eval("(-4..4).step(10)")).should == [2]
+ @array.send(@method, eval("(-4...4).step(10)")).should == [2]
- # start with negative index, end with negative index
- @array.send(@method, eval("(-4..-2).step(1)")).should == [2, 3, 4]
- @array.send(@method, eval("(-4...-2).step(1)")).should == [2, 3]
+ # start with negative index, end with negative index
+ @array.send(@method, eval("(-4..-2).step(1)")).should == [2, 3, 4]
+ @array.send(@method, eval("(-4...-2).step(1)")).should == [2, 3]
- @array.send(@method, eval("(-4..-2).step(2)")).should == [2, 4]
- @array.send(@method, eval("(-4...-2).step(2)")).should == [2]
+ @array.send(@method, eval("(-4..-2).step(2)")).should == [2, 4]
+ @array.send(@method, eval("(-4...-2).step(2)")).should == [2]
- @array.send(@method, eval("(-4..-2).step(10)")).should == [2]
- @array.send(@method, eval("(-4...-2).step(10)")).should == [2]
- end
+ @array.send(@method, eval("(-4..-2).step(10)")).should == [2]
+ @array.send(@method, eval("(-4...-2).step(10)")).should == [2]
+ end
- it "has closed range and negative steps" do
- # start and end with 0
- @array.send(@method, eval("(0..0).step(-1)")).should == [0]
- @array.send(@method, eval("(0...0).step(-1)")).should == []
+ it "has closed range and negative steps" do
+ # start and end with 0
+ @array.send(@method, eval("(0..0).step(-1)")).should == [0]
+ @array.send(@method, eval("(0...0).step(-1)")).should == []
- @array.send(@method, eval("(0..0).step(-2)")).should == [0]
- @array.send(@method, eval("(0...0).step(-2)")).should == []
+ @array.send(@method, eval("(0..0).step(-2)")).should == [0]
+ @array.send(@method, eval("(0...0).step(-2)")).should == []
- @array.send(@method, eval("(0..0).step(-10)")).should == [0]
- @array.send(@method, eval("(0...0).step(-10)")).should == []
+ @array.send(@method, eval("(0..0).step(-10)")).should == [0]
+ @array.send(@method, eval("(0...0).step(-10)")).should == []
- # start and end with positive index
- @array.send(@method, eval("(1..3).step(-1)")).should == []
- @array.send(@method, eval("(1...3).step(-1)")).should == []
+ # start and end with positive index
+ @array.send(@method, eval("(1..3).step(-1)")).should == []
+ @array.send(@method, eval("(1...3).step(-1)")).should == []
- @array.send(@method, eval("(1..3).step(-2)")).should == []
- @array.send(@method, eval("(1...3).step(-2)")).should == []
+ @array.send(@method, eval("(1..3).step(-2)")).should == []
+ @array.send(@method, eval("(1...3).step(-2)")).should == []
- @array.send(@method, eval("(1..3).step(-10)")).should == []
- @array.send(@method, eval("(1...3).step(-10)")).should == []
+ @array.send(@method, eval("(1..3).step(-10)")).should == []
+ @array.send(@method, eval("(1...3).step(-10)")).should == []
- # start with positive index, end with negative index
- @array.send(@method, eval("(1..-2).step(-1)")).should == []
- @array.send(@method, eval("(1...-2).step(-1)")).should == []
+ # start with positive index, end with negative index
+ @array.send(@method, eval("(1..-2).step(-1)")).should == []
+ @array.send(@method, eval("(1...-2).step(-1)")).should == []
- @array.send(@method, eval("(1..-2).step(-2)")).should == []
- @array.send(@method, eval("(1...-2).step(-2)")).should == []
+ @array.send(@method, eval("(1..-2).step(-2)")).should == []
+ @array.send(@method, eval("(1...-2).step(-2)")).should == []
- @array.send(@method, eval("(1..-2).step(-10)")).should == []
- @array.send(@method, eval("(1...-2).step(-10)")).should == []
+ @array.send(@method, eval("(1..-2).step(-10)")).should == []
+ @array.send(@method, eval("(1...-2).step(-10)")).should == []
- # start with negative index, end with positive index
- @array.send(@method, eval("(-4..4).step(-1)")).should == []
- @array.send(@method, eval("(-4...4).step(-1)")).should == []
+ # start with negative index, end with positive index
+ @array.send(@method, eval("(-4..4).step(-1)")).should == []
+ @array.send(@method, eval("(-4...4).step(-1)")).should == []
- @array.send(@method, eval("(-4..4).step(-2)")).should == []
- @array.send(@method, eval("(-4...4).step(-2)")).should == []
+ @array.send(@method, eval("(-4..4).step(-2)")).should == []
+ @array.send(@method, eval("(-4...4).step(-2)")).should == []
- @array.send(@method, eval("(-4..4).step(-10)")).should == []
- @array.send(@method, eval("(-4...4).step(-10)")).should == []
+ @array.send(@method, eval("(-4..4).step(-10)")).should == []
+ @array.send(@method, eval("(-4...4).step(-10)")).should == []
- # start with negative index, end with negative index
- @array.send(@method, eval("(-4..-2).step(-1)")).should == []
- @array.send(@method, eval("(-4...-2).step(-1)")).should == []
+ # start with negative index, end with negative index
+ @array.send(@method, eval("(-4..-2).step(-1)")).should == []
+ @array.send(@method, eval("(-4...-2).step(-1)")).should == []
- @array.send(@method, eval("(-4..-2).step(-2)")).should == []
- @array.send(@method, eval("(-4...-2).step(-2)")).should == []
+ @array.send(@method, eval("(-4..-2).step(-2)")).should == []
+ @array.send(@method, eval("(-4...-2).step(-2)")).should == []
- @array.send(@method, eval("(-4..-2).step(-10)")).should == []
- @array.send(@method, eval("(-4...-2).step(-10)")).should == []
- end
+ @array.send(@method, eval("(-4..-2).step(-10)")).should == []
+ @array.send(@method, eval("(-4...-2).step(-10)")).should == []
+ end
- it "has inverted closed range and positive steps" do
- # start and end with positive index
- @array.send(@method, eval("(3..1).step(1)")).should == []
- @array.send(@method, eval("(3...1).step(1)")).should == []
+ it "has inverted closed range and positive steps" do
+ # start and end with positive index
+ @array.send(@method, eval("(3..1).step(1)")).should == []
+ @array.send(@method, eval("(3...1).step(1)")).should == []
- @array.send(@method, eval("(3..1).step(2)")).should == []
- @array.send(@method, eval("(3...1).step(2)")).should == []
+ @array.send(@method, eval("(3..1).step(2)")).should == []
+ @array.send(@method, eval("(3...1).step(2)")).should == []
- @array.send(@method, eval("(3..1).step(10)")).should == []
- @array.send(@method, eval("(3...1).step(10)")).should == []
+ @array.send(@method, eval("(3..1).step(10)")).should == []
+ @array.send(@method, eval("(3...1).step(10)")).should == []
- # start with negative index, end with positive index
- @array.send(@method, eval("(-2..1).step(1)")).should == []
- @array.send(@method, eval("(-2...1).step(1)")).should == []
+ # start with negative index, end with positive index
+ @array.send(@method, eval("(-2..1).step(1)")).should == []
+ @array.send(@method, eval("(-2...1).step(1)")).should == []
- @array.send(@method, eval("(-2..1).step(2)")).should == []
- @array.send(@method, eval("(-2...1).step(2)")).should == []
+ @array.send(@method, eval("(-2..1).step(2)")).should == []
+ @array.send(@method, eval("(-2...1).step(2)")).should == []
- @array.send(@method, eval("(-2..1).step(10)")).should == []
- @array.send(@method, eval("(-2...1).step(10)")).should == []
+ @array.send(@method, eval("(-2..1).step(10)")).should == []
+ @array.send(@method, eval("(-2...1).step(10)")).should == []
- # start with positive index, end with negative index
- @array.send(@method, eval("(4..-4).step(1)")).should == []
- @array.send(@method, eval("(4...-4).step(1)")).should == []
+ # start with positive index, end with negative index
+ @array.send(@method, eval("(4..-4).step(1)")).should == []
+ @array.send(@method, eval("(4...-4).step(1)")).should == []
- @array.send(@method, eval("(4..-4).step(2)")).should == []
- @array.send(@method, eval("(4...-4).step(2)")).should == []
+ @array.send(@method, eval("(4..-4).step(2)")).should == []
+ @array.send(@method, eval("(4...-4).step(2)")).should == []
- @array.send(@method, eval("(4..-4).step(10)")).should == []
- @array.send(@method, eval("(4...-4).step(10)")).should == []
+ @array.send(@method, eval("(4..-4).step(10)")).should == []
+ @array.send(@method, eval("(4...-4).step(10)")).should == []
- # start with negative index, end with negative index
- @array.send(@method, eval("(-2..-4).step(1)")).should == []
- @array.send(@method, eval("(-2...-4).step(1)")).should == []
+ # start with negative index, end with negative index
+ @array.send(@method, eval("(-2..-4).step(1)")).should == []
+ @array.send(@method, eval("(-2...-4).step(1)")).should == []
- @array.send(@method, eval("(-2..-4).step(2)")).should == []
- @array.send(@method, eval("(-2...-4).step(2)")).should == []
+ @array.send(@method, eval("(-2..-4).step(2)")).should == []
+ @array.send(@method, eval("(-2...-4).step(2)")).should == []
- @array.send(@method, eval("(-2..-4).step(10)")).should == []
- @array.send(@method, eval("(-2...-4).step(10)")).should == []
- end
+ @array.send(@method, eval("(-2..-4).step(10)")).should == []
+ @array.send(@method, eval("(-2...-4).step(10)")).should == []
+ end
- it "has range with bounds outside of array" do
- # end is equal to array's length
- @array.send(@method, (0..6).step(1)).should == [0, 1, 2, 3, 4, 5]
- -> { @array.send(@method, (0..6).step(2)) }.should raise_error(RangeError)
+ it "has range with bounds outside of array" do
+ # end is equal to array's length
+ @array.send(@method, (0..6).step(1)).should == [0, 1, 2, 3, 4, 5]
+ -> { @array.send(@method, (0..6).step(2)) }.should raise_error(RangeError)
- # end is greater than length with positive steps
- @array.send(@method, (1..6).step(2)).should == [1, 3, 5]
- @array.send(@method, (2..7).step(2)).should == [2, 4]
- -> { @array.send(@method, (2..8).step(2)) }.should raise_error(RangeError)
+ # end is greater than length with positive steps
+ @array.send(@method, (1..6).step(2)).should == [1, 3, 5]
+ @array.send(@method, (2..7).step(2)).should == [2, 4]
+ -> { @array.send(@method, (2..8).step(2)) }.should raise_error(RangeError)
- # begin is greater than length with negative steps
- @array.send(@method, (6..1).step(-2)).should == [5, 3, 1]
- @array.send(@method, (7..2).step(-2)).should == [5, 3]
- -> { @array.send(@method, (8..2).step(-2)) }.should raise_error(RangeError)
- end
+ # begin is greater than length with negative steps
+ @array.send(@method, (6..1).step(-2)).should == [5, 3, 1]
+ @array.send(@method, (7..2).step(-2)).should == [5, 3]
+ -> { @array.send(@method, (8..2).step(-2)) }.should raise_error(RangeError)
+ end
- it "has endless range with start outside of array's bounds" do
- @array.send(@method, eval("(6..).step(1)")).should == []
- @array.send(@method, eval("(7..).step(1)")).should == nil
+ it "has endless range with start outside of array's bounds" do
+ @array.send(@method, eval("(6..).step(1)")).should == []
+ @array.send(@method, eval("(7..).step(1)")).should == nil
- @array.send(@method, eval("(6..).step(2)")).should == []
- -> { @array.send(@method, eval("(7..).step(2)")) }.should raise_error(RangeError)
- end
+ @array.send(@method, eval("(6..).step(2)")).should == []
+ -> { @array.send(@method, eval("(7..).step(2)")) }.should raise_error(RangeError)
end
end
- ruby_version_is "2.7" do
- it "can accept beginless ranges" do
- a = [0, 1, 2, 3, 4, 5]
- a.send(@method, eval("(..3)")).should == [0, 1, 2, 3]
- a.send(@method, eval("(...3)")).should == [0, 1, 2]
- a.send(@method, eval("(..-3)")).should == [0, 1, 2, 3]
- a.send(@method, eval("(...-3)")).should == [0, 1, 2]
- a.send(@method, eval("(..0)")).should == [0]
- a.send(@method, eval("(...0)")).should == []
- a.send(@method, eval("(..9)")).should == [0, 1, 2, 3, 4, 5]
- a.send(@method, eval("(...9)")).should == [0, 1, 2, 3, 4, 5]
- a.send(@method, eval("(..-9)")).should == []
- a.send(@method, eval("(...-9)")).should == []
+ it "can accept beginless ranges" do
+ a = [0, 1, 2, 3, 4, 5]
+ a.send(@method, (..3)).should == [0, 1, 2, 3]
+ a.send(@method, (...3)).should == [0, 1, 2]
+ a.send(@method, (..-3)).should == [0, 1, 2, 3]
+ a.send(@method, (...-3)).should == [0, 1, 2]
+ a.send(@method, (..0)).should == [0]
+ a.send(@method, (...0)).should == []
+ a.send(@method, (..9)).should == [0, 1, 2, 3, 4, 5]
+ a.send(@method, (...9)).should == [0, 1, 2, 3, 4, 5]
+ a.send(@method, (..-9)).should == []
+ a.send(@method, (...-9)).should == []
+ end
+
+ ruby_version_is "3.2" do
+ describe "can be sliced with Enumerator::ArithmeticSequence" do
+ it "with infinite/inverted ranges and negative steps" do
+ @array = [0, 1, 2, 3, 4, 5]
+ @array.send(@method, (2..).step(-1)).should == [2, 1, 0]
+ @array.send(@method, (2..).step(-2)).should == [2, 0]
+ @array.send(@method, (2..).step(-3)).should == [2]
+ @array.send(@method, (2..).step(-4)).should == [2]
+
+ @array.send(@method, (-3..).step(-1)).should == [3, 2, 1, 0]
+ @array.send(@method, (-3..).step(-2)).should == [3, 1]
+ @array.send(@method, (-3..).step(-3)).should == [3, 0]
+ @array.send(@method, (-3..).step(-4)).should == [3]
+ @array.send(@method, (-3..).step(-5)).should == [3]
+
+ @array.send(@method, (..0).step(-1)).should == [5, 4, 3, 2, 1, 0]
+ @array.send(@method, (..0).step(-2)).should == [5, 3, 1]
+ @array.send(@method, (..0).step(-3)).should == [5, 2]
+ @array.send(@method, (..0).step(-4)).should == [5, 1]
+ @array.send(@method, (..0).step(-5)).should == [5, 0]
+ @array.send(@method, (..0).step(-6)).should == [5]
+ @array.send(@method, (..0).step(-7)).should == [5]
+
+ @array.send(@method, (...0).step(-1)).should == [5, 4, 3, 2, 1]
+ @array.send(@method, (...0).step(-2)).should == [5, 3, 1]
+ @array.send(@method, (...0).step(-3)).should == [5, 2]
+ @array.send(@method, (...0).step(-4)).should == [5, 1]
+ @array.send(@method, (...0).step(-5)).should == [5]
+ @array.send(@method, (...0).step(-6)).should == [5]
+
+ @array.send(@method, (...1).step(-1)).should == [5, 4, 3, 2]
+ @array.send(@method, (...1).step(-2)).should == [5, 3]
+ @array.send(@method, (...1).step(-3)).should == [5, 2]
+ @array.send(@method, (...1).step(-4)).should == [5]
+ @array.send(@method, (...1).step(-5)).should == [5]
+
+ @array.send(@method, (..-5).step(-1)).should == [5, 4, 3, 2, 1]
+ @array.send(@method, (..-5).step(-2)).should == [5, 3, 1]
+ @array.send(@method, (..-5).step(-3)).should == [5, 2]
+ @array.send(@method, (..-5).step(-4)).should == [5, 1]
+ @array.send(@method, (..-5).step(-5)).should == [5]
+ @array.send(@method, (..-5).step(-6)).should == [5]
+
+ @array.send(@method, (...-5).step(-1)).should == [5, 4, 3, 2]
+ @array.send(@method, (...-5).step(-2)).should == [5, 3]
+ @array.send(@method, (...-5).step(-3)).should == [5, 2]
+ @array.send(@method, (...-5).step(-4)).should == [5]
+ @array.send(@method, (...-5).step(-5)).should == [5]
+
+ @array.send(@method, (4..1).step(-1)).should == [4, 3, 2, 1]
+ @array.send(@method, (4..1).step(-2)).should == [4, 2]
+ @array.send(@method, (4..1).step(-3)).should == [4, 1]
+ @array.send(@method, (4..1).step(-4)).should == [4]
+ @array.send(@method, (4..1).step(-5)).should == [4]
+
+ @array.send(@method, (4...1).step(-1)).should == [4, 3, 2]
+ @array.send(@method, (4...1).step(-2)).should == [4, 2]
+ @array.send(@method, (4...1).step(-3)).should == [4]
+ @array.send(@method, (4...1).step(-4)).should == [4]
+
+ @array.send(@method, (-2..1).step(-1)).should == [4, 3, 2, 1]
+ @array.send(@method, (-2..1).step(-2)).should == [4, 2]
+ @array.send(@method, (-2..1).step(-3)).should == [4, 1]
+ @array.send(@method, (-2..1).step(-4)).should == [4]
+ @array.send(@method, (-2..1).step(-5)).should == [4]
+
+ @array.send(@method, (-2...1).step(-1)).should == [4, 3, 2]
+ @array.send(@method, (-2...1).step(-2)).should == [4, 2]
+ @array.send(@method, (-2...1).step(-3)).should == [4]
+ @array.send(@method, (-2...1).step(-4)).should == [4]
+
+ @array.send(@method, (4..-5).step(-1)).should == [4, 3, 2, 1]
+ @array.send(@method, (4..-5).step(-2)).should == [4, 2]
+ @array.send(@method, (4..-5).step(-3)).should == [4, 1]
+ @array.send(@method, (4..-5).step(-4)).should == [4]
+ @array.send(@method, (4..-5).step(-5)).should == [4]
+
+ @array.send(@method, (4...-5).step(-1)).should == [4, 3, 2]
+ @array.send(@method, (4...-5).step(-2)).should == [4, 2]
+ @array.send(@method, (4...-5).step(-3)).should == [4]
+ @array.send(@method, (4...-5).step(-4)).should == [4]
+
+ @array.send(@method, (-2..-5).step(-1)).should == [4, 3, 2, 1]
+ @array.send(@method, (-2..-5).step(-2)).should == [4, 2]
+ @array.send(@method, (-2..-5).step(-3)).should == [4, 1]
+ @array.send(@method, (-2..-5).step(-4)).should == [4]
+ @array.send(@method, (-2..-5).step(-5)).should == [4]
+
+ @array.send(@method, (-2...-5).step(-1)).should == [4, 3, 2]
+ @array.send(@method, (-2...-5).step(-2)).should == [4, 2]
+ @array.send(@method, (-2...-5).step(-3)).should == [4]
+ @array.send(@method, (-2...-5).step(-4)).should == [4]
+ end
end
+ end
- it "can accept nil...nil ranges" do
- a = [0, 1, 2, 3, 4, 5]
- a.send(@method, eval("(nil...nil)")).should == a
- a.send(@method, eval("(...nil)")).should == a
- a.send(@method, eval("(nil..)")).should == a
- end
+ it "can accept nil...nil ranges" do
+ a = [0, 1, 2, 3, 4, 5]
+ a.send(@method, eval("(nil...nil)")).should == a
+ a.send(@method, (...nil)).should == a
+ a.send(@method, eval("(nil..)")).should == a
end
end
diff --git a/spec/ruby/core/array/shared/unshift.rb b/spec/ruby/core/array/shared/unshift.rb
index fc82e19e2a..4941e098f6 100644
--- a/spec/ruby/core/array/shared/unshift.rb
+++ b/spec/ruby/core/array/shared/unshift.rb
@@ -22,6 +22,11 @@ describe :array_unshift, shared: true do
a.should == [3, 4]
end
+ it "returns self" do
+ a = [1, 2, 3]
+ a.send(@method, "a").should.equal?(a)
+ end
+
it "quietly ignores unshifting nothing" do
[].send(@method).should == []
end
@@ -43,4 +48,17 @@ describe :array_unshift, shared: true do
it "raises a FrozenError on a frozen array when the array would not be modified" do
-> { ArraySpecs.frozen_array.send(@method) }.should raise_error(FrozenError)
end
+
+ # https://github.com/oracle/truffleruby/issues/2772
+ it "doesn't rely on Array#[]= so it can be overridden" do
+ subclass = Class.new(Array) do
+ def []=(*)
+ raise "[]= is called"
+ end
+ end
+
+ array = subclass.new
+ array.send(@method, 1)
+ array.should == [1]
+ end
end
diff --git a/spec/ruby/core/array/shift_spec.rb b/spec/ruby/core/array/shift_spec.rb
index b998e45d28..6b4ef39f77 100644
--- a/spec/ruby/core/array/shift_spec.rb
+++ b/spec/ruby/core/array/shift_spec.rb
@@ -116,21 +116,5 @@ describe "Array#shift" do
it "does not return subclass instances with Array subclass" do
ArraySpecs::MyArray[1, 2, 3].shift(2).should be_an_instance_of(Array)
end
-
- ruby_version_is ''...'2.7' do
- it "returns an untainted array even if the array is tainted" do
- ary = [1, 2].taint
- ary.shift(2).tainted?.should be_false
- ary.shift(0).tainted?.should be_false
- end
-
- it "keeps taint status" do
- a = [1, 2].taint
- a.shift(2)
- a.tainted?.should be_true
- a.shift(2)
- a.tainted?.should be_true
- end
- end
end
end
diff --git a/spec/ruby/core/array/shuffle_spec.rb b/spec/ruby/core/array/shuffle_spec.rb
index b255147c75..1d528c124f 100644
--- a/spec/ruby/core/array/shuffle_spec.rb
+++ b/spec/ruby/core/array/shuffle_spec.rb
@@ -47,6 +47,10 @@ describe "Array#shuffle" do
[1, 2].shuffle(random: random).should be_an_instance_of(Array)
end
+ it "accepts a Random class for the value for random: argument" do
+ [1, 2].shuffle(random: Random).should be_an_instance_of(Array)
+ end
+
it "calls #to_int on the Object returned by #rand" do
value = mock("array_shuffle_random_value")
value.should_receive(:to_int).at_least(1).times.and_return(0)
@@ -93,4 +97,14 @@ describe "Array#shuffle!" do
-> { ArraySpecs.frozen_array.shuffle! }.should raise_error(FrozenError)
-> { ArraySpecs.empty_frozen_array.shuffle! }.should raise_error(FrozenError)
end
+
+ it "matches CRuby with random:" do
+ %w[a b c].shuffle(random: Random.new(1)).should == %w[a c b]
+ (0..10).to_a.shuffle(random: Random.new(10)).should == [2, 6, 8, 5, 7, 10, 3, 1, 0, 4, 9]
+ end
+
+ it "matches CRuby with srand" do
+ srand(123)
+ %w[a b c d e f g h i j k].shuffle.should == %w[a e f h i j d b g k c]
+ end
end
diff --git a/spec/ruby/core/array/slice_spec.rb b/spec/ruby/core/array/slice_spec.rb
index 8c276f9084..731c129251 100644
--- a/spec/ruby/core/array/slice_spec.rb
+++ b/spec/ruby/core/array/slice_spec.rb
@@ -172,16 +172,14 @@ describe "Array#slice!" do
a.should == [1, 2]
end
- ruby_version_is "2.7" do
- it "works with beginless ranges" do
- a = [0,1,2,3,4]
- a.slice!(eval("(..3)")).should == [0, 1, 2, 3]
- a.should == [4]
-
- a = [0,1,2,3,4]
- a.slice!(eval("(...-2)")).should == [0, 1, 2]
- a.should == [3, 4]
- end
+ it "works with beginless ranges" do
+ a = [0,1,2,3,4]
+ a.slice!((..3)).should == [0, 1, 2, 3]
+ a.should == [4]
+
+ a = [0,1,2,3,4]
+ a.slice!((...-2)).should == [0, 1, 2]
+ a.should == [3, 4]
end
describe "with a subclass of Array" do
@@ -189,56 +187,28 @@ describe "Array#slice!" do
@array = ArraySpecs::MyArray[1, 2, 3, 4, 5]
end
- ruby_version_is ''...'3.0' do
- it "returns a subclass instance with [n, m]" do
- @array.slice!(0, 2).should be_an_instance_of(ArraySpecs::MyArray)
- end
-
- it "returns a subclass instance with [-n, m]" do
- @array.slice!(-3, 2).should be_an_instance_of(ArraySpecs::MyArray)
- end
-
- it "returns a subclass instance with [n..m]" do
- @array.slice!(1..3).should be_an_instance_of(ArraySpecs::MyArray)
- end
-
- it "returns a subclass instance with [n...m]" do
- @array.slice!(1...3).should be_an_instance_of(ArraySpecs::MyArray)
- end
-
- it "returns a subclass instance with [-n..-m]" do
- @array.slice!(-3..-1).should be_an_instance_of(ArraySpecs::MyArray)
- end
-
- it "returns a subclass instance with [-n...-m]" do
- @array.slice!(-3...-1).should be_an_instance_of(ArraySpecs::MyArray)
- end
+ it "returns a Array instance with [n, m]" do
+ @array.slice!(0, 2).should be_an_instance_of(Array)
end
- ruby_version_is '3.0' do
- it "returns a Array instance with [n, m]" do
- @array.slice!(0, 2).should be_an_instance_of(Array)
- end
-
- it "returns a Array instance with [-n, m]" do
- @array.slice!(-3, 2).should be_an_instance_of(Array)
- end
+ it "returns a Array instance with [-n, m]" do
+ @array.slice!(-3, 2).should be_an_instance_of(Array)
+ end
- it "returns a Array instance with [n..m]" do
- @array.slice!(1..3).should be_an_instance_of(Array)
- end
+ it "returns a Array instance with [n..m]" do
+ @array.slice!(1..3).should be_an_instance_of(Array)
+ end
- it "returns a Array instance with [n...m]" do
- @array.slice!(1...3).should be_an_instance_of(Array)
- end
+ it "returns a Array instance with [n...m]" do
+ @array.slice!(1...3).should be_an_instance_of(Array)
+ end
- it "returns a Array instance with [-n..-m]" do
- @array.slice!(-3..-1).should be_an_instance_of(Array)
- end
+ it "returns a Array instance with [-n..-m]" do
+ @array.slice!(-3..-1).should be_an_instance_of(Array)
+ end
- it "returns a Array instance with [-n...-m]" do
- @array.slice!(-3...-1).should be_an_instance_of(Array)
- end
+ it "returns a Array instance with [-n...-m]" do
+ @array.slice!(-3...-1).should be_an_instance_of(Array)
end
end
end
diff --git a/spec/ruby/core/array/sort_by_spec.rb b/spec/ruby/core/array/sort_by_spec.rb
index 7cea6ec6d3..0334f953f6 100644
--- a/spec/ruby/core/array/sort_by_spec.rb
+++ b/spec/ruby/core/array/sort_by_spec.rb
@@ -1,5 +1,6 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
+require_relative 'shared/iterable_and_tolerating_size_increasing'
require_relative '../enumerable/shared/enumeratorized'
describe "Array#sort_by!" do
@@ -31,6 +32,11 @@ describe "Array#sort_by!" do
-> { ArraySpecs.empty_frozen_array.sort_by! {}}.should raise_error(FrozenError)
end
+ it "raises a FrozenError on a frozen array only during iteration if called without a block" do
+ enum = ArraySpecs.frozen_array.sort_by!
+ -> { enum.each {} }.should raise_error(FrozenError)
+ end
+
it "returns the specified value when it would break in the given block" do
[1, 2, 3].sort_by!{ break :a }.should == :a
end
@@ -48,5 +54,32 @@ describe "Array#sort_by!" do
[1].sort_by!(&:to_s).should == [1]
end
+ it "does not truncate the array is the block raises an exception" do
+ a = [1, 2, 3]
+ begin
+ a.sort_by! { raise StandardError, 'Oops' }
+ rescue
+ end
+
+ a.should == [1, 2, 3]
+ end
+
+ it "doesn't change array if error is raised" do
+ a = [4, 3, 2, 1]
+ begin
+ a.sort_by! do |e|
+ raise StandardError, 'Oops' if e == 1
+ e
+ end
+ rescue StandardError
+ end
+
+ a.should == [4, 3, 2, 1]
+ end
+
it_behaves_like :enumeratorized_with_origin_size, :sort_by!, [1,2,3]
end
+
+describe "Array#sort_by!" do
+ it_behaves_like :array_iterable_and_tolerating_size_increasing, :sort_by!
+end
diff --git a/spec/ruby/core/array/sum_spec.rb b/spec/ruby/core/array/sum_spec.rb
index 8ca8353a67..06abe06135 100644
--- a/spec/ruby/core/array/sum_spec.rb
+++ b/spec/ruby/core/array/sum_spec.rb
@@ -1,4 +1,5 @@
require_relative '../../spec_helper'
+require_relative 'shared/iterable_and_tolerating_size_increasing'
describe "Array#sum" do
it "returns the sum of elements" do
@@ -9,8 +10,12 @@ describe "Array#sum" do
[1, 2, 3].sum { |i| i * 10 }.should == 60
end
+ it "doesn't apply the block init" do
+ [1, 2, 3].sum(1) { |i| i * 10 }.should == 61
+ end
+
# https://bugs.ruby-lang.org/issues/12217
- # https://github.com/ruby/ruby/blob/master/doc/ChangeLog-2.4.0#L6208-L6214
+ # https://github.com/ruby/ruby/blob/master/doc/ChangeLog/ChangeLog-2.4.0#L6208-L6214
it "uses Kahan's compensated summation algorithm for precise sum of float numbers" do
floats = [2.7800000000000002, 5.0, 2.5, 4.44, 3.89, 3.89, 4.44, 7.78, 5.0, 2.7800000000000002, 5.0, 2.5]
naive_sum = floats.reduce { |sum, e| sum + e }
@@ -68,4 +73,18 @@ describe "Array#sum" do
a.should_receive(:+).with(b).and_return(42)
[b].sum(a).should == 42
end
+
+ ruby_bug '#19530', ''...'3.3' do
+ it "calls + on the init value" do
+ a = mock("a")
+ b = mock("b")
+ a.should_receive(:+).with(42).and_return(b)
+ [42].sum(a).should == b
+ end
+ end
+end
+
+describe "Array#sum" do
+ @value_to_return = -> _ { 1 }
+ it_behaves_like :array_iterable_and_tolerating_size_increasing, :sum
end
diff --git a/spec/ruby/core/array/take_spec.rb b/spec/ruby/core/array/take_spec.rb
index 4fb6f0ce75..c4f0ac9aa4 100644
--- a/spec/ruby/core/array/take_spec.rb
+++ b/spec/ruby/core/array/take_spec.rb
@@ -26,15 +26,7 @@ describe "Array#take" do
->{ [1].take(-3) }.should raise_error(ArgumentError)
end
- ruby_version_is ''...'3.0' do
- it 'returns a subclass instance for Array subclasses' do
- ArraySpecs::MyArray[1, 2, 3, 4, 5].take(1).should be_an_instance_of(ArraySpecs::MyArray)
- end
- end
-
- ruby_version_is '3.0' do
- it 'returns a Array instance for Array subclasses' do
- ArraySpecs::MyArray[1, 2, 3, 4, 5].take(1).should be_an_instance_of(Array)
- end
+ it 'returns a Array instance for Array subclasses' do
+ ArraySpecs::MyArray[1, 2, 3, 4, 5].take(1).should be_an_instance_of(Array)
end
end
diff --git a/spec/ruby/core/array/take_while_spec.rb b/spec/ruby/core/array/take_while_spec.rb
index 363419b265..8f50260b42 100644
--- a/spec/ruby/core/array/take_while_spec.rb
+++ b/spec/ruby/core/array/take_while_spec.rb
@@ -1,5 +1,6 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
+require_relative 'shared/iterable_and_tolerating_size_increasing'
describe "Array#take_while" do
it "returns all elements until the block returns false" do
@@ -14,15 +15,12 @@ describe "Array#take_while" do
[1, 2, false, 4].take_while{ |element| element }.should == [1, 2]
end
- ruby_version_is ''...'3.0' do
- it 'returns a subclass instance for Array subclasses' do
- ArraySpecs::MyArray[1, 2, 3, 4, 5].take_while { |n| n < 4 }.should be_an_instance_of(ArraySpecs::MyArray)
- end
+ it 'returns a Array instance for Array subclasses' do
+ ArraySpecs::MyArray[1, 2, 3, 4, 5].take_while { |n| n < 4 }.should be_an_instance_of(Array)
end
+end
- ruby_version_is '3.0' do
- it 'returns a Array instance for Array subclasses' do
- ArraySpecs::MyArray[1, 2, 3, 4, 5].take_while { |n| n < 4 }.should be_an_instance_of(Array)
- end
- end
+describe "Array#take_while" do
+ @value_to_return = -> _ { true }
+ it_behaves_like :array_iterable_and_tolerating_size_increasing, :take_while
end
diff --git a/spec/ruby/core/array/to_h_spec.rb b/spec/ruby/core/array/to_h_spec.rb
index f5a7e546e6..f4578211a1 100644
--- a/spec/ruby/core/array/to_h_spec.rb
+++ b/spec/ruby/core/array/to_h_spec.rb
@@ -1,5 +1,6 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
+require_relative 'shared/iterable_and_tolerating_size_increasing'
describe "Array#to_h" do
it "converts empty array to empty hash" do
@@ -77,3 +78,8 @@ describe "Array#to_h" do
end
end
end
+
+describe "Array#to_h" do
+ @value_to_return = -> e { [e, e.to_s] }
+ it_behaves_like :array_iterable_and_tolerating_size_increasing, :to_h
+end
diff --git a/spec/ruby/core/array/try_convert_spec.rb b/spec/ruby/core/array/try_convert_spec.rb
index 47b4722d80..bea8815006 100644
--- a/spec/ruby/core/array/try_convert_spec.rb
+++ b/spec/ruby/core/array/try_convert_spec.rb
@@ -39,7 +39,7 @@ describe "Array.try_convert" do
it "sends #to_ary to the argument and raises TypeError if it's not a kind of Array" do
obj = mock("to_ary")
obj.should_receive(:to_ary).and_return(Object.new)
- -> { Array.try_convert obj }.should raise_error(TypeError)
+ -> { Array.try_convert obj }.should raise_error(TypeError, "can't convert MockObject to Array (MockObject#to_ary gives Object)")
end
it "does not rescue exceptions raised by #to_ary" do
diff --git a/spec/ruby/core/array/uniq_spec.rb b/spec/ruby/core/array/uniq_spec.rb
index 5911c23e6a..d5d826db15 100644
--- a/spec/ruby/core/array/uniq_spec.rb
+++ b/spec/ruby/core/array/uniq_spec.rb
@@ -1,5 +1,6 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
+require_relative 'shared/iterable_and_tolerating_size_increasing'
describe "Array#uniq" do
it "returns an array with no duplicates" do
@@ -39,76 +40,32 @@ describe "Array#uniq" do
[x, y].uniq.should == [x, y]
end
- ruby_version_is '2.7' do
- it "compares elements with matching hash codes with #eql?" do
- a = Array.new(2) do
- obj = mock('0')
- obj.should_receive(:hash).at_least(1).and_return(0)
+ it "compares elements with matching hash codes with #eql?" do
+ a = Array.new(2) do
+ obj = mock('0')
+ obj.should_receive(:hash).at_least(1).and_return(0)
- def obj.eql?(o)
- false
- end
-
- obj
+ def obj.eql?(o)
+ false
end
- a.uniq.should == a
-
- a = Array.new(2) do
- obj = mock('0')
- obj.should_receive(:hash).at_least(1).and_return(0)
-
- def obj.eql?(o)
- true
- end
-
- obj
- end
-
- a.uniq.size.should == 1
+ obj
end
- end
- ruby_version_is ''...'2.7' do
- it "compares elements with matching hash codes with #eql?" do
- a = Array.new(2) do
- obj = mock('0')
- obj.should_receive(:hash).at_least(1).and_return(0)
-
- def obj.eql?(o)
- # It's undefined whether the impl does a[0].eql?(a[1]) or
- # a[1].eql?(a[0]) so we taint both.
- taint
- o.taint
- false
- end
-
- obj
- end
+ a.uniq.should == a
- a.uniq.should == a
- a[0].should.tainted?
- a[1].should.tainted?
+ a = Array.new(2) do
+ obj = mock('0')
+ obj.should_receive(:hash).at_least(1).and_return(0)
- a = Array.new(2) do
- obj = mock('0')
- obj.should_receive(:hash).at_least(1).and_return(0)
-
- def obj.eql?(o)
- # It's undefined whether the impl does a[0].eql?(a[1]) or
- # a[1].eql?(a[0]) so we taint both.
- taint
- o.taint
- true
- end
-
- obj
+ def obj.eql?(o)
+ true
end
- a.uniq.size.should == 1
- a[0].should.tainted?
- a[1].should.tainted?
+ obj
end
+
+ a.uniq.size.should == 1
end
it "compares elements based on the value returned from the block" do
@@ -128,16 +85,8 @@ describe "Array#uniq" do
[false, nil, 42].uniq { :bar }.should == [false]
end
- ruby_version_is ''...'3.0' do
- it "returns subclass instance on Array subclasses" do
- ArraySpecs::MyArray[1, 2, 3].uniq.should be_an_instance_of(ArraySpecs::MyArray)
- end
- end
-
- ruby_version_is '3.0' do
- it "returns Array instance on Array subclasses" do
- ArraySpecs::MyArray[1, 2, 3].uniq.should be_an_instance_of(Array)
- end
+ it "returns Array instance on Array subclasses" do
+ ArraySpecs::MyArray[1, 2, 3].uniq.should be_an_instance_of(Array)
end
it "properly handles an identical item even when its #eql? isn't reflexive" do
@@ -175,6 +124,11 @@ describe "Array#uniq" do
end
end
+describe "Array#uniq" do
+ @value_to_return = -> e { e }
+ it_behaves_like :array_iterable_and_tolerating_size_increasing, :uniq
+end
+
describe "Array#uniq!" do
it "modifies the array in place" do
a = [ "a", "a", "b", "b", "c" ]
@@ -258,4 +212,32 @@ describe "Array#uniq!" do
a.uniq!
a.should == [x]
end
+
+ it "does not truncate the array is the block raises an exception" do
+ a = [1, 2, 3]
+ begin
+ a.send(@method) { raise StandardError, 'Oops' }
+ rescue
+ end
+
+ a.should == [1, 2, 3]
+ end
+
+ it "doesn't change array if error is raised" do
+ a = [1, 1, 2, 2, 3, 3, 4, 4]
+ begin
+ a.send(@method) do |e|
+ raise StandardError, 'Oops' if e == 3
+ e
+ end
+ rescue StandardError
+ end
+
+ a.should == [1, 1, 2, 2, 3, 3, 4, 4]
+ end
+end
+
+describe "Array#uniq!" do
+ @value_to_return = -> e { e }
+ it_behaves_like :array_iterable_and_tolerating_size_increasing, :uniq!
end
diff --git a/spec/ruby/core/array/values_at_spec.rb b/spec/ruby/core/array/values_at_spec.rb
index f1522e0bfe..e85bbee400 100644
--- a/spec/ruby/core/array/values_at_spec.rb
+++ b/spec/ruby/core/array/values_at_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
+# Should be synchronized with core/struct/values_at_spec.rb
describe "Array#values_at" do
it "returns an array of elements at the indexes when passed indexes" do
[1, 2, 3, 4, 5].values_at().should == []
@@ -66,10 +67,8 @@ describe "Array#values_at" do
[1, 2, 3, 4].values_at(eval("(3...)")).should == [4]
end
- ruby_version_is "2.7" do
- it "works when given beginless ranges" do
- [1, 2, 3, 4].values_at(eval("(..2)")).should == [1, 2, 3]
- [1, 2, 3, 4].values_at(eval("(...2)")).should == [1, 2]
- end
+ it "works when given beginless ranges" do
+ [1, 2, 3, 4].values_at((..2)).should == [1, 2, 3]
+ [1, 2, 3, 4].values_at((...2)).should == [1, 2]
end
end
diff --git a/spec/ruby/core/array/zip_spec.rb b/spec/ruby/core/array/zip_spec.rb
index af4013debe..2a0f64cb49 100644
--- a/spec/ruby/core/array/zip_spec.rb
+++ b/spec/ruby/core/array/zip_spec.rb
@@ -62,4 +62,10 @@ describe "Array#zip" do
it "does not return subclass instance on Array subclasses" do
ArraySpecs::MyArray[1, 2, 3].zip(["a", "b"]).should be_an_instance_of(Array)
end
+
+ it "raises TypeError when some argument isn't Array and doesn't respond to #to_ary and #to_enum" do
+ -> { [1, 2, 3].zip(Object.new) }.should raise_error(TypeError, "wrong argument type Object (must respond to :each)")
+ -> { [1, 2, 3].zip(1) }.should raise_error(TypeError, "wrong argument type Integer (must respond to :each)")
+ -> { [1, 2, 3].zip(true) }.should raise_error(TypeError, "wrong argument type TrueClass (must respond to :each)")
+ end
end
diff --git a/spec/ruby/core/basicobject/fixtures/classes.rb b/spec/ruby/core/basicobject/fixtures/classes.rb
index d1785afe31..ed5a2dda17 100644
--- a/spec/ruby/core/basicobject/fixtures/classes.rb
+++ b/spec/ruby/core/basicobject/fixtures/classes.rb
@@ -15,8 +15,231 @@ module BasicObjectSpecs
include InstExec
end
- module InstEvalCVar
- instance_eval { @@count = 2 }
+ module InstEval
+ module CVar
+ module Get
+ class ReceiverScope
+ @@cvar = :value_defined_in_receiver_scope
+ end
+
+ class BlockDefinitionScope
+ @@cvar = :value_defined_in_block_definition_scope
+
+ def block
+ -> * { @@cvar }
+ end
+ end
+
+ class CallerScope
+ @@cvar = :value_defined_in_caller_scope
+
+ def get_class_variable_with_string(obj)
+ obj.instance_eval("@@cvar")
+ end
+
+ def get_class_variable_with_block(obj, block)
+ obj.instance_eval(&block)
+ end
+ end
+
+ class CallerWithoutCVarScope
+ def get_class_variable_with_string(obj)
+ obj.instance_eval("@@cvar")
+ end
+ end
+
+ ReceiverWithCVarDefinedInSingletonClass = Class.new.new.tap do |obj|
+ obj.singleton_class.class_variable_set(:@@cvar, :value_defined_in_receiver_singleton_class)
+ end
+ end
+
+ module Set
+ class ReceiverScope
+ end
+
+ class BlockDefinitionScope
+ def self.get_class_variable
+ @@cvar
+ end
+
+ def block_to_assign(value)
+ -> * { @@cvar = value }
+ end
+ end
+
+ class CallerScope
+ def self.get_class_variable
+ @@cvar
+ end
+
+ def set_class_variable_with_string(obj, value)
+ obj.instance_eval("@@cvar=#{value.inspect}")
+ end
+
+ def set_class_variable_with_block(obj, block)
+ obj.instance_eval(&block)
+ end
+ end
+ end
+ end
+ end
+
+ module InstEval
+ module Constants
+ module ConstantInReceiverSingletonClass
+ module ReceiverScope
+ FOO = :ReceiverScope
+
+ class ReceiverParent
+ FOO = :ReceiverParent
+ end
+
+ class Receiver < ReceiverParent
+ FOO = :Receiver
+
+ def initialize
+ self.singleton_class.const_set(:FOO, :singleton_class)
+ end
+ end
+ end
+
+ module CallerScope
+ FOO = :CallerScope
+
+ class CallerParent
+ FOO = :CallerParent
+ end
+
+ class Caller < CallerParent
+ FOO = :Caller
+
+ def get_constant_with_string(receiver)
+ receiver.instance_eval("FOO")
+ end
+ end
+ end
+ end
+
+ module ConstantInReceiverClass
+ module ReceiverScope
+ FOO = :ReceiverScope
+
+ class ReceiverParent
+ FOO = :ReceiverParent
+ end
+
+ class Receiver < ReceiverParent
+ FOO = :Receiver
+ end
+ end
+
+ module CallerScope
+ FOO = :CallerScope
+
+ class CallerParent
+ FOO = :CallerParent
+ end
+
+ class Caller < CallerParent
+ FOO = :Caller
+
+ def get_constant_with_string(receiver)
+ receiver.instance_eval("FOO")
+ end
+ end
+ end
+ end
+
+ module ConstantInCallerClass
+ module ReceiverScope
+ FOO = :ReceiverScope
+
+ class ReceiverParent
+ FOO = :ReceiverParent
+ end
+
+ class Receiver < ReceiverParent
+ # FOO is not declared in a receiver class
+ end
+ end
+
+ module CallerScope
+ FOO = :CallerScope
+
+ class CallerParent
+ FOO = :CallerParent
+ end
+
+ class Caller < CallerParent
+ FOO = :Caller
+
+ def get_constant_with_string(receiver)
+ receiver.instance_eval("FOO")
+ end
+ end
+ end
+ end
+
+ module ConstantInCallerOuterScopes
+ module ReceiverScope
+ FOO = :ReceiverScope
+
+ class ReceiverParent
+ FOO = :ReceiverParent
+ end
+
+ class Receiver < ReceiverParent
+ # FOO is not declared in a receiver class
+ end
+ end
+
+ module CallerScope
+ FOO = :CallerScope
+
+ class CallerParent
+ FOO = :CallerParent
+ end
+
+ class Caller < CallerParent
+ # FOO is not declared in a caller class
+
+ def get_constant_with_string(receiver)
+ receiver.instance_eval("FOO")
+ end
+ end
+ end
+ end
+
+ module ConstantInReceiverParentClass
+ module ReceiverScope
+ FOO = :ReceiverScope
+
+ class ReceiverParent
+ FOO = :ReceiverParent
+ end
+
+ class Receiver < ReceiverParent
+ # FOO is not declared in a receiver class
+ end
+ end
+
+ module CallerScope
+ # FOO is not declared in a caller outer scopes
+
+ class CallerParent
+ FOO = :CallerParent
+ end
+
+ class Caller < CallerParent
+ # FOO is not declared in a caller class
+
+ def get_constant_with_string(receiver)
+ receiver.instance_eval("FOO")
+ end
+ end
+ end
+ end
+ end
end
class InstEvalConst
@@ -26,7 +249,6 @@ module BasicObjectSpecs
module InstEvalOuter
module Inner
obj = InstEvalConst.new
- X_BY_STR = obj.instance_eval("INST_EVAL_CONST_X") rescue nil
X_BY_BLOCK = obj.instance_eval { INST_EVAL_CONST_X } rescue nil
end
end
diff --git a/spec/ruby/core/basicobject/instance_eval_spec.rb b/spec/ruby/core/basicobject/instance_eval_spec.rb
index b6a146095d..1f3a43f341 100644
--- a/spec/ruby/core/basicobject/instance_eval_spec.rb
+++ b/spec/ruby/core/basicobject/instance_eval_spec.rb
@@ -20,12 +20,18 @@ describe "BasicObject#instance_eval" do
a.instance_eval('self').equal?(a).should be_true
end
- it "expects a block with no arguments" do
- -> { "hola".instance_eval }.should raise_error(ArgumentError)
+ it "raises an ArgumentError when no arguments and no block are given" do
+ -> { "hola".instance_eval }.should raise_error(ArgumentError, "wrong number of arguments (given 0, expected 1..3)")
end
- it "takes no arguments with a block" do
- -> { "hola".instance_eval(4, 5) {|a,b| a + b } }.should raise_error(ArgumentError)
+ it "raises an ArgumentError when a block and normal arguments are given" do
+ -> { "hola".instance_eval(4, 5) {|a,b| a + b } }.should raise_error(ArgumentError, "wrong number of arguments (given 2, expected 0)")
+ end
+
+ it "raises an ArgumentError when more than 3 arguments are given" do
+ -> {
+ "hola".instance_eval("1 + 1", "some file", 0, "bogus")
+ }.should raise_error(ArgumentError, "wrong number of arguments (given 4, expected 1..3)")
end
it "yields the object to the block" do
@@ -78,11 +84,30 @@ describe "BasicObject#instance_eval" do
end
+ ruby_version_is "3.3" do
+ it "uses the caller location as default location" do
+ f = Object.new
+ f.instance_eval("[__FILE__, __LINE__]").should == ["(eval at #{__FILE__}:#{__LINE__})", 1]
+ end
+ end
+
it "has access to receiver's instance variables" do
BasicObjectSpecs::IVars.new.instance_eval { @secret }.should == 99
BasicObjectSpecs::IVars.new.instance_eval("@secret").should == 99
end
+ it "raises TypeError for frozen objects when tries to set receiver's instance variables" do
+ -> { nil.instance_eval { @foo = 42 } }.should raise_error(FrozenError, "can't modify frozen NilClass: nil")
+ -> { true.instance_eval { @foo = 42 } }.should raise_error(FrozenError, "can't modify frozen TrueClass: true")
+ -> { false.instance_eval { @foo = 42 } }.should raise_error(FrozenError, "can't modify frozen FalseClass: false")
+ -> { 1.instance_eval { @foo = 42 } }.should raise_error(FrozenError, "can't modify frozen Integer: 1")
+ -> { :symbol.instance_eval { @foo = 42 } }.should raise_error(FrozenError, "can't modify frozen Symbol: :symbol")
+
+ obj = Object.new
+ obj.freeze
+ -> { obj.instance_eval { @foo = 42 } }.should raise_error(FrozenError)
+ end
+
it "treats block-local variables as local to the block" do
prc = instance_eval <<-CODE
proc do |x, prc|
@@ -99,11 +124,6 @@ describe "BasicObject#instance_eval" do
prc.call(false, prc).should == 1
end
- it "sets class variables in the receiver" do
- BasicObjectSpecs::InstEvalCVar.class_variables.should include(:@@count)
- BasicObjectSpecs::InstEvalCVar.send(:class_variable_get, :@@count).should == 2
- end
-
it "makes the receiver metaclass the scoped class when used with a string" do
obj = Object.new
obj.instance_eval %{
@@ -113,8 +133,52 @@ describe "BasicObject#instance_eval" do
obj.singleton_class.const_get(:B).should be_an_instance_of(Class)
end
- it "gets constants in the receiver if a string given" do
- BasicObjectSpecs::InstEvalOuter::Inner::X_BY_STR.should == 2
+ describe "constants lookup when a String given" do
+ it "looks in the receiver singleton class first" do
+ receiver = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverSingletonClass::ReceiverScope::Receiver.new
+ caller = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverSingletonClass::CallerScope::Caller.new
+
+ caller.get_constant_with_string(receiver).should == :singleton_class
+ end
+
+ ruby_version_is ""..."3.1" do
+ it "looks in the caller scope next" do
+ receiver = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverClass::ReceiverScope::Receiver.new
+ caller = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverClass::CallerScope::Caller.new
+
+ caller.get_constant_with_string(receiver).should == :Caller
+ end
+ end
+
+ ruby_version_is "3.1" do
+ it "looks in the receiver class next" do
+ receiver = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverClass::ReceiverScope::Receiver.new
+ caller = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverClass::CallerScope::Caller.new
+
+ caller.get_constant_with_string(receiver).should == :Receiver
+ end
+ end
+
+ it "looks in the caller class next" do
+ receiver = BasicObjectSpecs::InstEval::Constants::ConstantInCallerClass::ReceiverScope::Receiver.new
+ caller = BasicObjectSpecs::InstEval::Constants::ConstantInCallerClass::CallerScope::Caller.new
+
+ caller.get_constant_with_string(receiver).should == :Caller
+ end
+
+ it "looks in the caller outer scopes next" do
+ receiver = BasicObjectSpecs::InstEval::Constants::ConstantInCallerOuterScopes::ReceiverScope::Receiver.new
+ caller = BasicObjectSpecs::InstEval::Constants::ConstantInCallerOuterScopes::CallerScope::Caller.new
+
+ caller.get_constant_with_string(receiver).should == :CallerScope
+ end
+
+ it "looks in the receiver class hierarchy next" do
+ receiver = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverParentClass::ReceiverScope::Receiver.new
+ caller = BasicObjectSpecs::InstEval::Constants::ConstantInReceiverParentClass::CallerScope::Caller.new
+
+ caller.get_constant_with_string(receiver).should == :ReceiverParent
+ end
end
it "doesn't get constants in the receiver if a block given" do
@@ -130,17 +194,51 @@ describe "BasicObject#instance_eval" do
end.should raise_error(TypeError)
end
-quarantine! do # Not clean, leaves cvars lying around to break other specs
- it "scopes class var accesses in the caller when called on an Integer" do
- # Integer can take instance vars
- Integer.class_eval "@@__tmp_instance_eval_spec = 1"
- (defined? @@__tmp_instance_eval_spec).should be_nil
+ describe "class variables lookup" do
+ it "gets class variables in the caller class when called with a String" do
+ receiver = BasicObjectSpecs::InstEval::CVar::Get::ReceiverScope.new
+ caller = BasicObjectSpecs::InstEval::CVar::Get::CallerScope.new
- @@__tmp_instance_eval_spec = 2
- 1.instance_eval { @@__tmp_instance_eval_spec }.should == 2
- Integer.__send__(:remove_class_variable, :@@__tmp_instance_eval_spec)
+ caller.get_class_variable_with_string(receiver).should == :value_defined_in_caller_scope
+ end
+
+ it "gets class variables in the block definition scope when called with a block" do
+ receiver = BasicObjectSpecs::InstEval::CVar::Get::ReceiverScope.new
+ caller = BasicObjectSpecs::InstEval::CVar::Get::CallerScope.new
+ block = BasicObjectSpecs::InstEval::CVar::Get::BlockDefinitionScope.new.block
+
+ caller.get_class_variable_with_block(receiver, block).should == :value_defined_in_block_definition_scope
+ end
+
+ it "sets class variables in the caller class when called with a String" do
+ receiver = BasicObjectSpecs::InstEval::CVar::Set::ReceiverScope.new
+ caller = BasicObjectSpecs::InstEval::CVar::Set::CallerScope.new
+
+ caller.set_class_variable_with_string(receiver, 1)
+ BasicObjectSpecs::InstEval::CVar::Set::CallerScope.get_class_variable.should == 1
+ end
+
+ it "sets class variables in the block definition scope when called with a block" do
+ receiver = BasicObjectSpecs::InstEval::CVar::Set::ReceiverScope.new
+ caller = BasicObjectSpecs::InstEval::CVar::Set::CallerScope.new
+ block = BasicObjectSpecs::InstEval::CVar::Set::BlockDefinitionScope.new.block_to_assign(1)
+
+ caller.set_class_variable_with_block(receiver, block)
+ BasicObjectSpecs::InstEval::CVar::Set::BlockDefinitionScope.get_class_variable.should == 1
+ end
+
+ it "does not have access to class variables in the receiver class when called with a String" do
+ receiver = BasicObjectSpecs::InstEval::CVar::Get::ReceiverScope.new
+ caller = BasicObjectSpecs::InstEval::CVar::Get::CallerWithoutCVarScope.new
+ -> { caller.get_class_variable_with_string(receiver) }.should raise_error(NameError, /uninitialized class variable @@cvar/)
+ end
+
+ it "does not have access to class variables in the receiver's singleton class when called with a String" do
+ receiver = BasicObjectSpecs::InstEval::CVar::Get::ReceiverWithCVarDefinedInSingletonClass
+ caller = BasicObjectSpecs::InstEval::CVar::Get::CallerWithoutCVarScope.new
+ -> { caller.get_class_variable_with_string(receiver) }.should raise_error(NameError, /uninitialized class variable @@cvar/)
+ end
end
-end
it "raises a TypeError when defining methods on numerics" do
-> do
@@ -185,4 +283,58 @@ end
x.should == :value
end
+
+ it "converts string argument with #to_str method" do
+ source_code = Object.new
+ def source_code.to_str() "1" end
+
+ a = BasicObject.new
+ a.instance_eval(source_code).should == 1
+ end
+
+ it "raises ArgumentError if returned value is not String" do
+ source_code = Object.new
+ def source_code.to_str() :symbol end
+
+ a = BasicObject.new
+ -> { a.instance_eval(source_code) }.should raise_error(TypeError, /can't convert Object to String/)
+ end
+
+ it "converts filename argument with #to_str method" do
+ filename = Object.new
+ def filename.to_str() "file.rb" end
+
+ err = begin
+ Object.new.instance_eval("raise", filename)
+ rescue => e
+ e
+ end
+ err.backtrace.first.split(":")[0].should == "file.rb"
+ end
+
+ it "raises ArgumentError if returned value is not String" do
+ filename = Object.new
+ def filename.to_str() :symbol end
+
+ -> { Object.new.instance_eval("raise", filename) }.should raise_error(TypeError, /can't convert Object to String/)
+ end
+
+ it "converts lineno argument with #to_int method" do
+ lineno = Object.new
+ def lineno.to_int() 15 end
+
+ err = begin
+ Object.new.instance_eval("raise", "file.rb", lineno)
+ rescue => e
+ e
+ end
+ err.backtrace.first.split(":")[1].should == "15"
+ end
+
+ it "raises ArgumentError if returned value is not Integer" do
+ lineno = Object.new
+ def lineno.to_int() :symbol end
+
+ -> { Object.new.instance_eval("raise", "file.rb", lineno) }.should raise_error(TypeError, /can't convert Object to Integer/)
+ end
end
diff --git a/spec/ruby/core/basicobject/method_missing_spec.rb b/spec/ruby/core/basicobject/method_missing_spec.rb
index b048780ee8..a29d4375bc 100644
--- a/spec/ruby/core/basicobject/method_missing_spec.rb
+++ b/spec/ruby/core/basicobject/method_missing_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../spec_helper"
require_relative '../../shared/basicobject/method_missing'
describe "BasicObject#method_missing" do
diff --git a/spec/ruby/core/basicobject/singleton_method_added_spec.rb b/spec/ruby/core/basicobject/singleton_method_added_spec.rb
index ab6b2a2d10..fc65a091aa 100644
--- a/spec/ruby/core/basicobject/singleton_method_added_spec.rb
+++ b/spec/ruby/core/basicobject/singleton_method_added_spec.rb
@@ -94,7 +94,7 @@ describe "BasicObject#singleton_method_added" do
-> {
def self.foo
end
- }.should raise_error(NoMethodError, /undefined method `singleton_method_added' for/)
+ }.should raise_error(NoMethodError, /undefined method [`']singleton_method_added' for/)
end
end
@@ -106,16 +106,16 @@ describe "BasicObject#singleton_method_added" do
-> {
def foo
end
- }.should raise_error(NoMethodError, /undefined method `singleton_method_added' for #<Object:/)
+ }.should raise_error(NoMethodError, /undefined method [`']singleton_method_added' for #<Object:/)
-> {
define_method(:bar) {}
- }.should raise_error(NoMethodError, /undefined method `singleton_method_added' for #<Object:/)
+ }.should raise_error(NoMethodError, /undefined method [`']singleton_method_added' for #<Object:/)
end
-> {
object.define_singleton_method(:baz) {}
- }.should raise_error(NoMethodError, /undefined method `singleton_method_added' for #<Object:/)
+ }.should raise_error(NoMethodError, /undefined method [`']singleton_method_added' for #<Object:/)
end
it "calls #method_missing" do
diff --git a/spec/ruby/core/binding/clone_spec.rb b/spec/ruby/core/binding/clone_spec.rb
index ebd40f5377..f1769ac6de 100644
--- a/spec/ruby/core/binding/clone_spec.rb
+++ b/spec/ruby/core/binding/clone_spec.rb
@@ -4,4 +4,10 @@ require_relative 'shared/clone'
describe "Binding#clone" do
it_behaves_like :binding_clone, :clone
+
+ it "preserves frozen status" do
+ bind = binding.freeze
+ bind.frozen?.should == true
+ bind.clone.frozen?.should == true
+ end
end
diff --git a/spec/ruby/core/binding/dup_spec.rb b/spec/ruby/core/binding/dup_spec.rb
index 43968213c8..55fac6e333 100644
--- a/spec/ruby/core/binding/dup_spec.rb
+++ b/spec/ruby/core/binding/dup_spec.rb
@@ -4,4 +4,10 @@ require_relative 'shared/clone'
describe "Binding#dup" do
it_behaves_like :binding_clone, :dup
+
+ it "resets frozen status" do
+ bind = binding.freeze
+ bind.frozen?.should == true
+ bind.dup.frozen?.should == false
+ end
end
diff --git a/spec/ruby/core/binding/eval_spec.rb b/spec/ruby/core/binding/eval_spec.rb
index 4bb3da7a6c..bb2036f739 100644
--- a/spec/ruby/core/binding/eval_spec.rb
+++ b/spec/ruby/core/binding/eval_spec.rb
@@ -23,58 +23,29 @@ describe "Binding#eval" do
bind2.local_variables.should == []
end
- ruby_version_is ""..."3.0" do
- it "inherits __LINE__ from the enclosing scope" do
- obj = BindingSpecs::Demo.new(1)
- bind = obj.get_binding
- suppress_warning {bind.eval("__LINE__")}.should == obj.get_line_of_binding
- end
-
- it "preserves __LINE__ across multiple calls to eval" do
- obj = BindingSpecs::Demo.new(1)
- bind = obj.get_binding
- suppress_warning {bind.eval("__LINE__")}.should == obj.get_line_of_binding
- suppress_warning {bind.eval("__LINE__")}.should == obj.get_line_of_binding
- end
-
- it "increments __LINE__ on each line of a multiline eval" do
- obj = BindingSpecs::Demo.new(1)
- bind = obj.get_binding
- suppress_warning {bind.eval("#foo\n__LINE__")}.should == obj.get_line_of_binding + 1
- end
-
- it "inherits __LINE__ from the enclosing scope even if the Binding is created with #send" do
- obj = BindingSpecs::Demo.new(1)
- bind, line = obj.get_binding_with_send_and_line
- suppress_warning {bind.eval("__LINE__")}.should == line
- end
+ it "starts with line 1 if single argument is given" do
+ obj = BindingSpecs::Demo.new(1)
+ bind = obj.get_binding
+ bind.eval("__LINE__").should == 1
end
- ruby_version_is "3.0" do
- it "starts with line 1 if single argument is given" do
- obj = BindingSpecs::Demo.new(1)
- bind = obj.get_binding
- bind.eval("__LINE__").should == 1
- end
-
- it "preserves __LINE__ across multiple calls to eval" do
- obj = BindingSpecs::Demo.new(1)
- bind = obj.get_binding
- bind.eval("__LINE__").should == 1
- bind.eval("__LINE__").should == 1
- end
+ it "preserves __LINE__ across multiple calls to eval" do
+ obj = BindingSpecs::Demo.new(1)
+ bind = obj.get_binding
+ bind.eval("__LINE__").should == 1
+ bind.eval("__LINE__").should == 1
+ end
- it "increments __LINE__ on each line of a multiline eval" do
- obj = BindingSpecs::Demo.new(1)
- bind = obj.get_binding
- bind.eval("#foo\n__LINE__").should == 2
- end
+ it "increments __LINE__ on each line of a multiline eval" do
+ obj = BindingSpecs::Demo.new(1)
+ bind = obj.get_binding
+ bind.eval("#foo\n__LINE__").should == 2
+ end
- it "starts with line 1 if the Binding is created with #send" do
- obj = BindingSpecs::Demo.new(1)
- bind, line = obj.get_binding_with_send_and_line
- bind.eval("__LINE__").should == 1
- end
+ it "starts with line 1 if the Binding is created with #send" do
+ obj = BindingSpecs::Demo.new(1)
+ bind, line = obj.get_binding_with_send_and_line
+ bind.eval("__LINE__").should == 1
end
it "starts with a __LINE__ of 1 if a filename is passed" do
@@ -89,32 +60,18 @@ describe "Binding#eval" do
bind.eval("#foo\n__LINE__", "(test)", 88).should == 89
end
- ruby_version_is ""..."3.0" do
- it "inherits __FILE__ from the enclosing scope" do
- obj = BindingSpecs::Demo.new(1)
- bind = obj.get_binding
- suppress_warning { bind.eval("__FILE__") }.should == obj.get_file_of_binding
- end
-
- it "inherits __LINE__ from the enclosing scope" do
- obj = BindingSpecs::Demo.new(1)
- bind, line = obj.get_binding_and_line
- suppress_warning { bind.eval("__LINE__") }.should == line
- end
- end
-
- ruby_version_is "3.0" do
+ ruby_version_is ""..."3.3" do
it "uses (eval) as __FILE__ if single argument given" do
obj = BindingSpecs::Demo.new(1)
bind = obj.get_binding
bind.eval("__FILE__").should == '(eval)'
end
+ end
- it "uses 1 as __LINE__" do
- obj = BindingSpecs::Demo.new(1)
- bind = obj.get_binding
- suppress_warning { bind.eval("__LINE__") }.should == 1
- end
+ it "uses 1 as __LINE__" do
+ obj = BindingSpecs::Demo.new(1)
+ bind = obj.get_binding
+ suppress_warning { bind.eval("__LINE__") }.should == 1
end
it "uses the __FILE__ that is passed in" do
@@ -149,4 +106,10 @@ describe "Binding#eval" do
bind.eval("'bar'.foo").should == "foo"
end
+
+ ruby_version_is "3.3" do
+ it "uses the caller location as default filename" do
+ binding.eval("[__FILE__, __LINE__]").should == ["(eval at #{__FILE__}:#{__LINE__})", 1]
+ end
+ end
end
diff --git a/spec/ruby/core/binding/fixtures/irbrc b/spec/ruby/core/binding/fixtures/irbrc
deleted file mode 100644
index 2bc12af2f7..0000000000
--- a/spec/ruby/core/binding/fixtures/irbrc
+++ /dev/null
@@ -1 +0,0 @@
-# empty configuration
diff --git a/spec/ruby/core/binding/irb_spec.rb b/spec/ruby/core/binding/irb_spec.rb
index b3bc274f78..25521f0dd7 100644
--- a/spec/ruby/core/binding/irb_spec.rb
+++ b/spec/ruby/core/binding/irb_spec.rb
@@ -1,16 +1,19 @@
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"
- irbrc_fixture = fixture __FILE__, "irbrc"
+ envs = %w[IRBRC HOME XDG_CONFIG_HOME].to_h {|e| [e, nil]}
- out = IO.popen([{"IRBRC"=>irbrc_fixture}, *ruby_exe, irb_fixture], "r+") do |pipe|
- pipe.puts "a ** 2"
- pipe.puts "exit"
- pipe.readlines.map(&:chomp)
+ 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)
+ end
end
- out[-3..-1].should == ["a ** 2", "100", "exit"]
+ 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 0e934ac1b5..1224b8ec7d 100644
--- a/spec/ruby/core/binding/shared/clone.rb
+++ b/spec/ruby/core/binding/shared/clone.rb
@@ -31,4 +31,26 @@ describe :binding_clone, shared: true do
b2.local_variable_defined?(:x).should == false
end
end
+
+ ruby_version_is "3.4" do
+ it "copies instance variables" do
+ @b1.instance_variable_set(:@ivar, 1)
+ cl = @b1.send(@method)
+ cl.instance_variables.should == [:@ivar]
+ end
+
+ it "copies the finalizer" do
+ code = <<-RUBY
+ obj = binding
+
+ ObjectSpace.define_finalizer(obj, Proc.new { STDOUT.write "finalized\n" })
+
+ obj.clone
+
+ exit 0
+ RUBY
+
+ ruby_exe(code).lines.sort.should == ["finalized\n", "finalized\n"]
+ end
+ end
end
diff --git a/spec/ruby/core/binding/source_location_spec.rb b/spec/ruby/core/binding/source_location_spec.rb
index d439c3e399..d1c8191ea8 100644
--- a/spec/ruby/core/binding/source_location_spec.rb
+++ b/spec/ruby/core/binding/source_location_spec.rb
@@ -6,4 +6,9 @@ describe "Binding#source_location" do
b = BindingSpecs::LocationMethod::TEST_BINDING
b.source_location.should == [BindingSpecs::LocationMethod::FILE_PATH, 4]
end
+
+ it "works for eval with a given line" do
+ b = eval('binding', nil, "foo", 100)
+ b.source_location.should == ["foo", 100]
+ end
end
diff --git a/spec/ruby/core/builtin_constants/builtin_constants_spec.rb b/spec/ruby/core/builtin_constants/builtin_constants_spec.rb
index 7c87a970d7..1960f5721f 100644
--- a/spec/ruby/core/builtin_constants/builtin_constants_spec.rb
+++ b/spec/ruby/core/builtin_constants/builtin_constants_spec.rb
@@ -34,12 +34,6 @@ describe "RUBY_PLATFORM" do
it "is a String" do
RUBY_PLATFORM.should be_kind_of(String)
end
-
- platform_is :darwin do
- it 'ends with the build time kernel major version on darwin' do
- RUBY_PLATFORM.should =~ /-darwin\d+$/
- end
- end
end
describe "RUBY_RELEASE_DATE" do
@@ -49,15 +43,7 @@ describe "RUBY_RELEASE_DATE" do
end
describe "RUBY_REVISION" do
- ruby_version_is ""..."2.7" do
- it "is an Integer" do
- RUBY_REVISION.should be_kind_of(Integer)
- end
- end
-
- ruby_version_is "2.7" do
- it "is a String" do
- RUBY_REVISION.should be_kind_of(String)
- end
+ it "is a String" do
+ RUBY_REVISION.should be_kind_of(String)
end
end
diff --git a/spec/ruby/core/class/attached_object_spec.rb b/spec/ruby/core/class/attached_object_spec.rb
new file mode 100644
index 0000000000..f1c0f63a44
--- /dev/null
+++ b/spec/ruby/core/class/attached_object_spec.rb
@@ -0,0 +1,31 @@
+require_relative '../../spec_helper'
+
+ruby_version_is '3.2' do
+ describe "Class#attached_object" do
+ it "returns the object that is attached to a singleton class" do
+ a = Class.new
+
+ a_obj = a.new
+ a_obj.singleton_class.attached_object.should == a_obj
+ end
+
+ it "returns the class object that is attached to a class's singleton class" do
+ a = Class.new
+ singleton_class = (class << a; self; end)
+
+ singleton_class.attached_object.should == a
+ end
+
+ it "raises TypeError if the class is not a singleton class" do
+ a = Class.new
+
+ -> { a.attached_object }.should raise_error(TypeError, /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
+end
diff --git a/spec/ruby/core/class/dup_spec.rb b/spec/ruby/core/class/dup_spec.rb
index 701fd72e19..c09ed71b31 100644
--- a/spec/ruby/core/class/dup_spec.rb
+++ b/spec/ruby/core/class/dup_spec.rb
@@ -61,4 +61,7 @@ describe "Class#dup" do
CoreClassSpecs::RecordCopy.name.should == "CoreClassSpecs::RecordCopy"
end
+ it "raises TypeError if called on BasicObject" do
+ -> { BasicObject.dup }.should raise_error(TypeError, "can't copy the root class")
+ end
end
diff --git a/spec/ruby/core/class/subclasses_spec.rb b/spec/ruby/core/class/subclasses_spec.rb
index ddbcfb02c0..50eb5358d9 100644
--- a/spec/ruby/core/class/subclasses_spec.rb
+++ b/spec/ruby/core/class/subclasses_spec.rb
@@ -7,7 +7,7 @@ ruby_version_is '3.1' do
assert_subclasses(ModuleSpecs::Parent, [ModuleSpecs::Child, ModuleSpecs::Child2])
end
- it "does not return included modules" do
+ it "does not return included modules from the parent" do
parent = Class.new
child = Class.new(parent)
mod = Module.new
@@ -16,6 +16,33 @@ ruby_version_is '3.1' do
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
+
+ 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
+
+ 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
+
it "does not return singleton classes" do
a = Class.new
@@ -31,6 +58,28 @@ ruby_version_is '3.1' do
ModuleSpecs::Parent.subclasses.should == ModuleSpecs::Parent.subclasses.uniq
end
+ it "works when creating subclasses concurrently" do
+ t = 16
+ n = 1000
+ go = false
+ superclass = Class.new
+
+ threads = t.times.map do
+ Thread.new do
+ Thread.pass until go
+ n.times.map do
+ Class.new(superclass)
+ end
+ end
+ end
+
+ go = true
+ classes = threads.map(&:value)
+
+ superclass.subclasses.size.should == t * n
+ superclass.subclasses.each { |c| c.should be_kind_of(Class) }
+ end
+
def assert_subclasses(mod,subclasses)
mod.subclasses.sort_by(&:inspect).should == subclasses.sort_by(&:inspect)
end
diff --git a/spec/ruby/core/comparable/clamp_spec.rb b/spec/ruby/core/comparable/clamp_spec.rb
index 393496fc76..796d4a18c1 100644
--- a/spec/ruby/core/comparable/clamp_spec.rb
+++ b/spec/ruby/core/comparable/clamp_spec.rb
@@ -2,14 +2,6 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe 'Comparable#clamp' do
- ruby_version_is ""..."2.7" do
- it 'raises an Argument error unless given 2 parameters' do
- c = ComparableSpecs::Weird.new(0)
- -> { c.clamp(c) }.should raise_error(ArgumentError)
- -> { c.clamp(c, c, c) }.should raise_error(ArgumentError)
- end
- end
-
it 'raises an Argument error unless the 2 parameters are correctly ordered' do
one = ComparableSpecs::WithOnlyCompareDefined.new(1)
two = ComparableSpecs::WithOnlyCompareDefined.new(2)
@@ -48,41 +40,39 @@ describe 'Comparable#clamp' do
c.clamp(one, two).should equal(two)
end
- ruby_version_is "2.7" do
- it 'returns self if within the given range parameters' do
- one = ComparableSpecs::WithOnlyCompareDefined.new(1)
- two = ComparableSpecs::WithOnlyCompareDefined.new(2)
- three = ComparableSpecs::WithOnlyCompareDefined.new(3)
- c = ComparableSpecs::Weird.new(2)
-
- c.clamp(one..two).should equal(c)
- c.clamp(two..two).should equal(c)
- c.clamp(one..three).should equal(c)
- c.clamp(two..three).should equal(c)
- end
-
- it 'returns the minimum value of the range parameters if smaller than it' do
- one = ComparableSpecs::WithOnlyCompareDefined.new(1)
- two = ComparableSpecs::WithOnlyCompareDefined.new(2)
- c = ComparableSpecs::Weird.new(0)
-
- c.clamp(one..two).should equal(one)
- end
-
- it 'returns the maximum value of the range parameters if greater than it' do
- one = ComparableSpecs::WithOnlyCompareDefined.new(1)
- two = ComparableSpecs::WithOnlyCompareDefined.new(2)
- c = ComparableSpecs::Weird.new(3)
-
- c.clamp(one..two).should equal(two)
- end
-
- it 'raises an Argument error if the range parameter is exclusive' do
- one = ComparableSpecs::WithOnlyCompareDefined.new(1)
- two = ComparableSpecs::WithOnlyCompareDefined.new(2)
- c = ComparableSpecs::Weird.new(3)
-
- -> { c.clamp(one...two) }.should raise_error(ArgumentError)
- end
+ it 'returns self if within the given range parameters' do
+ one = ComparableSpecs::WithOnlyCompareDefined.new(1)
+ two = ComparableSpecs::WithOnlyCompareDefined.new(2)
+ three = ComparableSpecs::WithOnlyCompareDefined.new(3)
+ c = ComparableSpecs::Weird.new(2)
+
+ c.clamp(one..two).should equal(c)
+ c.clamp(two..two).should equal(c)
+ c.clamp(one..three).should equal(c)
+ c.clamp(two..three).should equal(c)
+ end
+
+ it 'returns the minimum value of the range parameters if smaller than it' do
+ one = ComparableSpecs::WithOnlyCompareDefined.new(1)
+ two = ComparableSpecs::WithOnlyCompareDefined.new(2)
+ c = ComparableSpecs::Weird.new(0)
+
+ c.clamp(one..two).should equal(one)
+ end
+
+ it 'returns the maximum value of the range parameters if greater than it' do
+ one = ComparableSpecs::WithOnlyCompareDefined.new(1)
+ two = ComparableSpecs::WithOnlyCompareDefined.new(2)
+ c = ComparableSpecs::Weird.new(3)
+
+ c.clamp(one..two).should equal(two)
+ end
+
+ it 'raises an Argument error if the range parameter is exclusive' do
+ one = ComparableSpecs::WithOnlyCompareDefined.new(1)
+ two = ComparableSpecs::WithOnlyCompareDefined.new(2)
+ c = ComparableSpecs::Weird.new(3)
+
+ -> { c.clamp(one...two) }.should raise_error(ArgumentError)
end
end
diff --git a/spec/ruby/core/complex/comparison_spec.rb b/spec/ruby/core/complex/comparison_spec.rb
index 2a437afb71..3a3142f234 100644
--- a/spec/ruby/core/complex/comparison_spec.rb
+++ b/spec/ruby/core/complex/comparison_spec.rb
@@ -1,27 +1,25 @@
require_relative '../../spec_helper'
describe "Complex#<=>" do
- ruby_version_is "2.7" do
- it "returns nil if either self or argument has imaginary part" do
- (Complex(5, 1) <=> Complex(2)).should be_nil
- (Complex(1) <=> Complex(2, 1)).should be_nil
- (5 <=> Complex(2, 1)).should be_nil
- end
+ it "returns nil if either self or argument has imaginary part" do
+ (Complex(5, 1) <=> Complex(2)).should be_nil
+ (Complex(1) <=> Complex(2, 1)).should be_nil
+ (5 <=> Complex(2, 1)).should be_nil
+ end
- it "returns nil if argument is not numeric" do
- (Complex(5, 1) <=> "cmp").should be_nil
- (Complex(1) <=> "cmp").should be_nil
- (Complex(1) <=> Object.new).should be_nil
- end
+ it "returns nil if argument is not numeric" do
+ (Complex(5, 1) <=> "cmp").should be_nil
+ (Complex(1) <=> "cmp").should be_nil
+ (Complex(1) <=> Object.new).should be_nil
+ end
- it "returns 0, 1, or -1 if self and argument do not have imaginary part" do
- (Complex(5) <=> Complex(2)).should == 1
- (Complex(2) <=> Complex(3)).should == -1
- (Complex(2) <=> Complex(2)).should == 0
+ it "returns 0, 1, or -1 if self and argument do not have imaginary part" do
+ (Complex(5) <=> Complex(2)).should == 1
+ (Complex(2) <=> Complex(3)).should == -1
+ (Complex(2) <=> Complex(2)).should == 0
- (Complex(5) <=> 2).should == 1
- (Complex(2) <=> 3).should == -1
- (Complex(2) <=> 2).should == 0
- end
+ (Complex(5) <=> 2).should == 1
+ (Complex(2) <=> 3).should == -1
+ (Complex(2) <=> 2).should == 0
end
end
diff --git a/spec/ruby/core/complex/inspect_spec.rb b/spec/ruby/core/complex/inspect_spec.rb
index 71aabde5be..045be94b22 100644
--- a/spec/ruby/core/complex/inspect_spec.rb
+++ b/spec/ruby/core/complex/inspect_spec.rb
@@ -1,4 +1,5 @@
require_relative '../../spec_helper'
+require_relative '../numeric/fixtures/classes'
describe "Complex#inspect" do
it "returns (${real}+${image}i) for positive imaginary parts" do
@@ -13,4 +14,24 @@ describe "Complex#inspect" do
Complex(-1, -4).inspect.should == "(-1-4i)"
Complex(-7, -6.7).inspect.should == "(-7-6.7i)"
end
+
+ it "calls #inspect on real and imaginary" do
+ real = NumericSpecs::Subclass.new
+ # + because of https://bugs.ruby-lang.org/issues/20337
+ real.should_receive(:inspect).and_return(+"1")
+ imaginary = NumericSpecs::Subclass.new
+ imaginary.should_receive(:inspect).and_return("2")
+ imaginary.should_receive(:<).any_number_of_times.and_return(false)
+ Complex(real, imaginary).inspect.should == "(1+2i)"
+ end
+
+ it "adds an `*' before the `i' if the last character of the imaginary part is not numeric" do
+ real = NumericSpecs::Subclass.new
+ # + because of https://bugs.ruby-lang.org/issues/20337
+ real.should_receive(:inspect).and_return(+"(1)")
+ imaginary = NumericSpecs::Subclass.new
+ imaginary.should_receive(:inspect).and_return("(2)")
+ imaginary.should_receive(:<).any_number_of_times.and_return(false)
+ Complex(real, imaginary).inspect.should == "((1)+(2)*i)"
+ end
end
diff --git a/spec/ruby/core/complex/polar_spec.rb b/spec/ruby/core/complex/polar_spec.rb
index 2a5d8ebd69..3bb3751bc6 100644
--- a/spec/ruby/core/complex/polar_spec.rb
+++ b/spec/ruby/core/complex/polar_spec.rb
@@ -10,6 +10,22 @@ describe "Complex.polar" do
->{ Complex.polar(nil) }.should raise_error(TypeError)
->{ 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
+
+ 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
end
describe "Complex#polar" do
diff --git a/spec/ruby/core/complex/to_r_spec.rb b/spec/ruby/core/complex/to_r_spec.rb
index 4559921492..788027a500 100644
--- a/spec/ruby/core/complex/to_r_spec.rb
+++ b/spec/ruby/core/complex/to_r_spec.rb
@@ -34,8 +34,16 @@ describe "Complex#to_r" do
end
describe "when the imaginary part is Float 0.0" do
- it "raises RangeError" do
- -> { Complex(0, 0.0).to_r }.should raise_error(RangeError)
+ ruby_version_is ''...'3.4' do
+ it "raises RangeError" do
+ -> { Complex(0, 0.0).to_r }.should raise_error(RangeError)
+ end
+ end
+
+ ruby_version_is '3.4' do
+ it "returns a Rational" do
+ Complex(0, 0.0).to_r.should == 0r
+ end
end
end
end
diff --git a/spec/ruby/core/complex/to_s_spec.rb b/spec/ruby/core/complex/to_s_spec.rb
index 989a7ae0b7..ceccffe470 100644
--- a/spec/ruby/core/complex/to_s_spec.rb
+++ b/spec/ruby/core/complex/to_s_spec.rb
@@ -1,4 +1,5 @@
require_relative '../../spec_helper'
+require_relative '../numeric/fixtures/classes'
describe "Complex#to_s" do
describe "when self's real component is 0" do
@@ -41,4 +42,14 @@ describe "Complex#to_s" do
it "returns 1+NaN*i for Complex(1, NaN)" do
Complex(1, nan_value).to_s.should == "1+NaN*i"
end
+
+ it "treats real and imaginary parts as strings" do
+ real = NumericSpecs::Subclass.new
+ # + because of https://bugs.ruby-lang.org/issues/20337
+ real.should_receive(:to_s).and_return(+"1")
+ imaginary = NumericSpecs::Subclass.new
+ imaginary.should_receive(:to_s).and_return("2")
+ imaginary.should_receive(:<).any_number_of_times.and_return(false)
+ Complex(real, imaginary).to_s.should == "1+2i"
+ end
end
diff --git a/spec/ruby/core/conditionvariable/broadcast_spec.rb b/spec/ruby/core/conditionvariable/broadcast_spec.rb
index d88159df23..55a7b89c72 100644
--- a/spec/ruby/core/conditionvariable/broadcast_spec.rb
+++ b/spec/ruby/core/conditionvariable/broadcast_spec.rb
@@ -1,5 +1,4 @@
require_relative '../../spec_helper'
-require 'thread'
describe "ConditionVariable#broadcast" do
it "releases all threads waiting in line for this resource" do
diff --git a/spec/ruby/core/conditionvariable/marshal_dump_spec.rb b/spec/ruby/core/conditionvariable/marshal_dump_spec.rb
index f951a13e28..88b1cc38c1 100644
--- a/spec/ruby/core/conditionvariable/marshal_dump_spec.rb
+++ b/spec/ruby/core/conditionvariable/marshal_dump_spec.rb
@@ -1,5 +1,4 @@
require_relative '../../spec_helper'
-require 'thread'
describe "ConditionVariable#marshal_dump" do
it "raises a TypeError" do
diff --git a/spec/ruby/core/conditionvariable/signal_spec.rb b/spec/ruby/core/conditionvariable/signal_spec.rb
index 86383073f1..43a9cc611b 100644
--- a/spec/ruby/core/conditionvariable/signal_spec.rb
+++ b/spec/ruby/core/conditionvariable/signal_spec.rb
@@ -1,5 +1,4 @@
require_relative '../../spec_helper'
-require 'thread'
describe "ConditionVariable#signal" do
it "releases the first thread waiting in line for this resource" do
diff --git a/spec/ruby/core/conditionvariable/wait_spec.rb b/spec/ruby/core/conditionvariable/wait_spec.rb
index 9a68c2b5a1..fe73e513c0 100644
--- a/spec/ruby/core/conditionvariable/wait_spec.rb
+++ b/spec/ruby/core/conditionvariable/wait_spec.rb
@@ -1,5 +1,4 @@
require_relative '../../spec_helper'
-require 'thread'
describe "ConditionVariable#wait" do
it "calls #sleep on the given object" do
diff --git a/spec/ruby/core/data/constants_spec.rb b/spec/ruby/core/data/constants_spec.rb
index 1d469f9237..2eb43d501e 100644
--- a/spec/ruby/core/data/constants_spec.rb
+++ b/spec/ruby/core/data/constants_spec.rb
@@ -1,23 +1,21 @@
require_relative '../../spec_helper'
-ruby_version_is ''...'3.0' do
+ruby_version_is ''...'3.2' do
describe "Data" do
- it "is a subclass of Object" do
- suppress_warning do
- Data.superclass.should == Object
- end
- end
-
- it "is deprecated" do
- -> { Data }.should complain(/constant ::Data is deprecated/)
+ it "does not exist anymore" do
+ Object.should_not have_constant(:Data)
end
end
end
-ruby_version_is '3.0' do
+ruby_version_is '3.2' do
describe "Data" do
- it "does not exist anymore" do
- Object.should_not have_constant(:Data)
+ it "is a new constant" do
+ Data.superclass.should == Object
+ end
+
+ it "is not deprecated" do
+ -> { Data }.should_not complain
end
end
end
diff --git a/spec/ruby/core/data/define_spec.rb b/spec/ruby/core/data/define_spec.rb
new file mode 100644
index 0000000000..2aa2c50d4c
--- /dev/null
+++ b/spec/ruby/core/data/define_spec.rb
@@ -0,0 +1,36 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+
+ruby_version_is "3.2" do
+ describe "Data.define" do
+ it "accepts no arguments" do
+ empty_data = Data.define
+ empty_data.members.should == []
+ end
+
+ it "accepts symbols" do
+ movie = Data.define(:title, :year)
+ movie.members.should == [:title, :year]
+ end
+
+ it "accepts strings" do
+ movie = Data.define("title", "year")
+ movie.members.should == [:title, :year]
+ end
+
+ it "accepts a mix of strings and symbols" do
+ movie = Data.define("title", :year, "genre")
+ movie.members.should == [:title, :year, :genre]
+ end
+
+ it "accepts a block" do
+ movie = Data.define(:title, :year) do
+ def title_with_year
+ "#{title} (#{year})"
+ end
+ end
+ movie.members.should == [:title, :year]
+ movie.new("Matrix", 1999).title_with_year.should == "Matrix (1999)"
+ end
+ end
+end
diff --git a/spec/ruby/core/data/fixtures/classes.rb b/spec/ruby/core/data/fixtures/classes.rb
new file mode 100644
index 0000000000..46a6b48bb2
--- /dev/null
+++ b/spec/ruby/core/data/fixtures/classes.rb
@@ -0,0 +1,5 @@
+module DataSpecs
+ guard -> { ruby_version_is "3.2" and Data.respond_to?(:define) } do
+ Measure = Data.define(:amount, :unit)
+ end
+end
diff --git a/spec/ruby/core/data/initialize_spec.rb b/spec/ruby/core/data/initialize_spec.rb
new file mode 100644
index 0000000000..2c36bd3ac4
--- /dev/null
+++ b/spec/ruby/core/data/initialize_spec.rb
@@ -0,0 +1,65 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+
+ruby_version_is "3.2" do
+ describe "Data#initialize" do
+ it "accepts positional arguments" do
+ data = DataSpecs::Measure.new(42, "km")
+
+ data.amount.should == 42
+ data.unit.should == "km"
+ end
+
+ it "accepts alternative positional arguments" do
+ data = DataSpecs::Measure[42, "km"]
+
+ data.amount.should == 42
+ data.unit.should == "km"
+ end
+
+ it "accepts keyword arguments" do
+ data = DataSpecs::Measure.new(amount: 42, unit: "km")
+
+ data.amount.should == 42
+ data.unit.should == "km"
+ end
+
+ it "accepts alternative keyword arguments" do
+ data = DataSpecs::Measure[amount: 42, unit: "km"]
+
+ data.amount.should == 42
+ data.unit.should == "km"
+ end
+
+ it "accepts String keyword arguments" do
+ data = DataSpecs::Measure.new("amount" => 42, "unit" => "km")
+
+ data.amount.should == 42
+ data.unit.should == "km"
+ end
+
+ it "raises ArgumentError if no arguments are given" do
+ -> {
+ DataSpecs::Measure.new
+ }.should raise_error(ArgumentError) { |e|
+ e.message.should.include?("missing keywords: :amount, :unit")
+ }
+ end
+
+ it "raises ArgumentError if at least one argument is missing" do
+ -> {
+ DataSpecs::Measure.new(unit: "km")
+ }.should raise_error(ArgumentError) { |e|
+ e.message.should.include?("missing keyword: :amount")
+ }
+ end
+
+ it "raises ArgumentError if unknown keyword is given" do
+ -> {
+ DataSpecs::Measure.new(amount: 42, unit: "km", system: "metric")
+ }.should raise_error(ArgumentError) { |e|
+ e.message.should.include?("unknown keyword: :system")
+ }
+ end
+ end
+end
diff --git a/spec/ruby/core/data/with_spec.rb b/spec/ruby/core/data/with_spec.rb
new file mode 100644
index 0000000000..97e34c951f
--- /dev/null
+++ b/spec/ruby/core/data/with_spec.rb
@@ -0,0 +1,35 @@
+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
+
+ 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
+
+ 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 "raises ArgumentError if no keyword arguments are given" do
+ data = DataSpecs::Measure.new(amount: 42, unit: "km")
+
+ -> {
+ data.with(4, "m")
+ }.should raise_error(ArgumentError, "wrong number of arguments (given 2, expected 0)")
+ end
+ end
+end
diff --git a/spec/ruby/core/dir/children_spec.rb b/spec/ruby/core/dir/children_spec.rb
index 986c8f38c0..0ad3df4669 100644
--- a/spec/ruby/core/dir/children_spec.rb
+++ b/spec/ruby/core/dir/children_spec.rb
@@ -47,7 +47,7 @@ describe "Dir.children" do
encoding = Encoding.find("filesystem")
encoding = Encoding::BINARY if encoding == Encoding::US_ASCII
platform_is_not :windows do
- children.should include("こんにちは.txt".force_encoding(encoding))
+ children.should include("こんにちは.txt".dup.force_encoding(encoding))
end
children.first.encoding.should equal(Encoding.find("filesystem"))
end
@@ -105,14 +105,6 @@ describe "Dir#children" do
dirs.each { |d| d.encoding.should == Encoding::UTF_8 }
end
- ruby_version_is ""..."2.7" do
- it "accepts nil options" do
- @dir = Dir.new("#{DirSpecs.mock_dir}/deeply/nested", nil)
- dirs = @dir.to_a.sort
- dirs.each { |d| d.encoding.should == Encoding.find("filesystem") }
- end
- end
-
it "returns children encoded with the filesystem encoding by default" do
# This spec depends on the locale not being US-ASCII because if it is, the
# children that are not ascii_only? will be BINARY encoded.
@@ -121,7 +113,7 @@ describe "Dir#children" do
encoding = Encoding.find("filesystem")
encoding = Encoding::BINARY if encoding == Encoding::US_ASCII
platform_is_not :windows do
- children.should include("こんにちは.txt".force_encoding(encoding))
+ children.should include("こんにちは.txt".dup.force_encoding(encoding))
end
children.first.encoding.should equal(Encoding.find("filesystem"))
end
@@ -139,4 +131,17 @@ describe "Dir#children" do
children = @dir.children.sort
children.first.encoding.should equal(Encoding::EUC_KR)
end
+
+ it "returns the same result when called repeatedly" do
+ @dir = Dir.open DirSpecs.mock_dir
+
+ a = []
+ @dir.each {|dir| a << dir}
+
+ b = []
+ @dir.each {|dir| b << dir}
+
+ a.sort.should == b.sort
+ a.sort.should == DirSpecs.expected_paths
+ end
end
diff --git a/spec/ruby/core/dir/each_child_spec.rb b/spec/ruby/core/dir/each_child_spec.rb
index f7980991e5..7194273b95 100644
--- a/spec/ruby/core/dir/each_child_spec.rb
+++ b/spec/ruby/core/dir/each_child_spec.rb
@@ -15,13 +15,6 @@ describe "Dir.each_child" do
dirs.each {|dir| dir.encoding.should == Encoding::UTF_8}
end
- ruby_version_is ""..."2.7" do
- it "accepts nil options" do
- dirs = Dir.each_child("#{DirSpecs.mock_dir}/deeply/nested", nil).to_a.sort
- dirs.each {|dir| dir.encoding.should == Encoding.find("filesystem")}
- end
- end
-
it "yields all names in an existing directory to the provided block" do
a, b = [], []
@@ -93,6 +86,19 @@ describe "Dir#each_child" do
@dir.each_child { |f| f }.should == @dir
end
+ it "returns the same result when called repeatedly" do
+ @dir = Dir.open DirSpecs.mock_dir
+
+ a = []
+ @dir.each {|dir| a << dir}
+
+ b = []
+ @dir.each {|dir| b << dir}
+
+ a.sort.should == b.sort
+ a.sort.should == DirSpecs.expected_paths
+ end
+
describe "when no block is given" do
it "returns an Enumerator" do
@dir = Dir.new(DirSpecs.mock_dir)
diff --git a/spec/ruby/core/dir/each_spec.rb b/spec/ruby/core/dir/each_spec.rb
index 8c69a7212b..7674663d82 100644
--- a/spec/ruby/core/dir/each_spec.rb
+++ b/spec/ruby/core/dir/each_spec.rb
@@ -35,6 +35,17 @@ describe "Dir#each" do
ls.should include(@dir.read)
end
+ it "returns the same result when called repeatedly" do
+ a = []
+ @dir.each {|dir| a << dir}
+
+ b = []
+ @dir.each {|dir| b << dir}
+
+ a.sort.should == b.sort
+ a.sort.should == DirSpecs.expected_paths
+ end
+
describe "when no block is given" do
it "returns an Enumerator" do
@dir.each.should be_an_instance_of(Enumerator)
diff --git a/spec/ruby/core/dir/entries_spec.rb b/spec/ruby/core/dir/entries_spec.rb
index 9aa58657db..7462542acf 100644
--- a/spec/ruby/core/dir/entries_spec.rb
+++ b/spec/ruby/core/dir/entries_spec.rb
@@ -40,13 +40,6 @@ describe "Dir.entries" do
dirs.each {|dir| dir.encoding.should == Encoding::UTF_8}
end
- ruby_version_is ""..."2.7" do
- it "accepts nil options" do
- dirs = Dir.entries("#{DirSpecs.mock_dir}/deeply/nested", nil).to_a.sort
- dirs.each {|dir| dir.encoding.should == Encoding.find("filesystem")}
- end
- end
-
it "returns entries encoded with the filesystem encoding by default" do
# This spec depends on the locale not being US-ASCII because if it is, the
# entries that are not ascii_only? will be BINARY encoded.
@@ -54,7 +47,7 @@ describe "Dir.entries" do
encoding = Encoding.find("filesystem")
encoding = Encoding::BINARY if encoding == Encoding::US_ASCII
platform_is_not :windows do
- entries.should include("こんにちは.txt".force_encoding(encoding))
+ entries.should include("こんにちは.txt".dup.force_encoding(encoding))
end
entries.first.encoding.should equal(Encoding.find("filesystem"))
end
diff --git a/spec/ruby/core/dir/exist_spec.rb b/spec/ruby/core/dir/exist_spec.rb
index 43987b0f32..9023de533f 100644
--- a/spec/ruby/core/dir/exist_spec.rb
+++ b/spec/ruby/core/dir/exist_spec.rb
@@ -13,3 +13,11 @@ describe "Dir.exist?" do
it_behaves_like :dir_exist, :exist?
end
+
+ruby_version_is "3.2" do
+ describe "Dir.exists?" do
+ it "has been removed" do
+ Dir.should_not.respond_to?(:exists?)
+ end
+ end
+end
diff --git a/spec/ruby/core/dir/fchdir_spec.rb b/spec/ruby/core/dir/fchdir_spec.rb
new file mode 100644
index 0000000000..429e569691
--- /dev/null
+++ b/spec/ruby/core/dir/fchdir_spec.rb
@@ -0,0 +1,68 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/common'
+
+ruby_version_is '3.3' do
+ guard -> { Dir.respond_to? :fchdir } do
+ describe "Dir.fchdir" do
+ before :all do
+ DirSpecs.create_mock_dirs
+ end
+
+ after :all do
+ DirSpecs.delete_mock_dirs
+ end
+
+ before :each do
+ @dirs = [Dir.new('.')]
+ @original = @dirs.first.fileno
+ end
+
+ after :each do
+ Dir.fchdir(@original)
+ @dirs.each(&:close)
+ end
+
+ it "changes to the specified directory" do
+ dir = Dir.new(DirSpecs.mock_dir)
+ @dirs << dir
+ Dir.fchdir dir.fileno
+ Dir.pwd.should == DirSpecs.mock_dir
+ end
+
+ it "returns 0 when successfully changing directory" do
+ Dir.fchdir(@original).should == 0
+ end
+
+ it "returns the value of the block when a block is given" do
+ Dir.fchdir(@original) { :block_value }.should == :block_value
+ end
+
+ it "changes to the specified directory for the duration of the block" do
+ pwd = Dir.pwd
+ dir = Dir.new(DirSpecs.mock_dir)
+ @dirs << dir
+ Dir.fchdir(dir.fileno) { Dir.pwd }.should == DirSpecs.mock_dir
+ Dir.pwd.should == pwd
+ end
+
+ it "raises a SystemCallError if the file descriptor given is not valid" do
+ -> { Dir.fchdir(-1) }.should raise_error(SystemCallError)
+ -> { Dir.fchdir(-1) { } }.should raise_error(SystemCallError)
+ end
+
+ it "raises a SystemCallError if the file descriptor given is not for a directory" do
+ -> { Dir.fchdir $stdout.fileno }.should raise_error(SystemCallError)
+ -> { Dir.fchdir($stdout.fileno) { } }.should raise_error(SystemCallError)
+ end
+ end
+ end
+
+ guard_not -> { Dir.respond_to? :fchdir } do
+ describe "Dir.fchdir" do
+ it "raises NotImplementedError" do
+ -> { Dir.fchdir 1 }.should raise_error(NotImplementedError)
+ -> { Dir.fchdir(1) { } }.should raise_error(NotImplementedError)
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/dir/fixtures/common.rb b/spec/ruby/core/dir/fixtures/common.rb
index c32b056819..087f46b331 100644
--- a/spec/ruby/core/dir/fixtures/common.rb
+++ b/spec/ruby/core/dir/fixtures/common.rb
@@ -82,6 +82,7 @@ module DirSpecs
special/test{1}/file[1]
special/{}/special
+ special/test\ +()[]{}/hello_world.erb
]
platform_is_not :windows do
@@ -94,18 +95,37 @@ module DirSpecs
special/こんにちは.txt
special/\a
]
+ @mock_dir_files << "special/_\u{1f60e}.erb"
end
end
@mock_dir_files
end
+ def self.mock_dir_links
+ unless @mock_dir_links
+ @mock_dir_links = []
+ platform_is_not :windows do
+ @mock_dir_links += [
+ ['special/ln', 'subdir_one']
+ ]
+ end
+ end
+ @mock_dir_links
+ end
+
def self.create_mock_dirs
mock_dir_files.each do |name|
file = File.join mock_dir, name
mkdir_p File.dirname(file)
touch file
end
+ mock_dir_links.each do |link, target|
+ full_link = File.join mock_dir, link
+ full_target = File.join mock_dir, target
+
+ File.symlink full_target, full_link
+ end
end
def self.delete_mock_dirs
diff --git a/spec/ruby/core/dir/foreach_spec.rb b/spec/ruby/core/dir/foreach_spec.rb
index c3ddb27a84..9cf34b1d71 100644
--- a/spec/ruby/core/dir/foreach_spec.rb
+++ b/spec/ruby/core/dir/foreach_spec.rb
@@ -41,13 +41,13 @@ describe "Dir.foreach" do
it "accepts an encoding keyword for the encoding of the entries" do
dirs = Dir.foreach("#{DirSpecs.mock_dir}/deeply/nested", encoding: "utf-8").to_a.sort
- dirs.each {|dir| dir.encoding.should == Encoding::UTF_8}
- end
+ dirs.each { |dir| dir.encoding.should == Encoding::UTF_8 }
+
+ dirs = Dir.foreach("#{DirSpecs.mock_dir}/deeply/nested", encoding: Encoding::ISO_8859_1).to_a.sort
+ dirs.each { |dir| dir.encoding.should == Encoding::ISO_8859_1 }
- ruby_version_is ""..."2.7" do
- it "accepts nil options" do
- dirs = Dir.foreach("#{DirSpecs.mock_dir}/deeply/nested", nil).to_a.sort
- dirs.each {|dir| dir.encoding.should == Encoding.find("filesystem")}
+ Dir.foreach("#{DirSpecs.mock_dir}/deeply/nested", encoding: Encoding::ISO_8859_1) do |f|
+ f.encoding.should == Encoding::ISO_8859_1
end
end
diff --git a/spec/ruby/core/dir/glob_spec.rb b/spec/ruby/core/dir/glob_spec.rb
index 295a7ab920..32f515c81d 100644
--- a/spec/ruby/core/dir/glob_spec.rb
+++ b/spec/ruby/core/dir/glob_spec.rb
@@ -79,6 +79,7 @@ describe "Dir.glob" do
nested/
nested/.dotsubir/
special/
+ special/test\ +()[]{}/
special/test{1}/
special/{}/
subdir_one/
@@ -105,11 +106,11 @@ describe "Dir.glob" do
ruby_version_is '3.1' do
it "recursively matches files and directories in nested dot subdirectory except . with 'nested/**/*' from the current directory and option File::FNM_DOTMATCH" do
expected = %w[
- nested/.
- nested/.dotsubir
- nested/.dotsubir/.dotfile
- nested/.dotsubir/nondotfile
- ]
+ nested/.
+ nested/.dotsubir
+ nested/.dotsubir/.dotfile
+ nested/.dotsubir/nondotfile
+ ]
Dir.glob('nested/**/*', File::FNM_DOTMATCH).sort.should == expected.sort
end
@@ -130,6 +131,7 @@ describe "Dir.glob" do
./nested/
./nested/.dotsubir/
./special/
+ ./special/test\ +()[]{}/
./special/test{1}/
./special/{}/
./subdir_one/
@@ -180,6 +182,134 @@ describe "Dir.glob" do
Dir.glob('**/**/**').should_not.empty?
end
+ it "handles **/** with base keyword argument" do
+ Dir.glob('**/**', base: "dir").should == ["filename_ordering"]
+
+ expected = %w[
+ nested
+ nested/directory
+ nested/directory/structure
+ nested/directory/structure/bar
+ nested/directory/structure/baz
+ nested/directory/structure/file_one
+ nested/directory/structure/file_one.ext
+ nested/directory/structure/foo
+ nondotfile
+ ].sort
+
+ Dir.glob('**/**', base: "deeply").sort.should == expected
+ end
+
+ it "handles **/ with base keyword argument" do
+ expected = %w[
+ /
+ directory/
+ directory/structure/
+ ]
+ Dir.glob('**/', base: "deeply/nested").sort.should == expected
+ end
+
+ it "handles **/nondotfile with base keyword argument" do
+ expected = %w[
+ deeply/nondotfile
+ nondotfile
+ subdir_one/nondotfile
+ subdir_two/nondotfile
+ ]
+ Dir.glob('**/nondotfile', base: ".").sort.should == expected
+ end
+
+ it "handles **/nondotfile with base keyword argument and FNM_DOTMATCH" do
+ expected = %w[
+ .dotsubdir/nondotfile
+ deeply/nondotfile
+ nested/.dotsubir/nondotfile
+ nondotfile
+ subdir_one/nondotfile
+ subdir_two/nondotfile
+ ]
+ Dir.glob('**/nondotfile', File::FNM_DOTMATCH, base: ".").sort.should == expected
+ end
+
+ it "handles **/.dotfile with base keyword argument" do
+ expected = %w[
+ .dotfile
+ deeply/.dotfile
+ subdir_one/.dotfile
+ ]
+ Dir.glob('**/.dotfile', base: ".").sort.should == expected
+ end
+
+ it "handles **/.dotfile with base keyword argument and FNM_DOTMATCH" do
+ expected = %w[
+ .dotfile
+ .dotsubdir/.dotfile
+ deeply/.dotfile
+ nested/.dotsubir/.dotfile
+ subdir_one/.dotfile
+ ]
+ Dir.glob('**/.dotfile', File::FNM_DOTMATCH, base: ".").sort.should == expected
+ end
+
+ it "handles **/.* with base keyword argument" do
+ expected = %w[
+ .dotfile.ext
+ directory/structure/.ext
+ ].sort
+
+ Dir.glob('**/.*', base: "deeply/nested").sort.should == expected
+ end
+
+ # < 3.1 include a "." entry for every dir: ["directory/.", "directory/structure/.", ...]
+ ruby_version_is '3.1' do
+ it "handles **/.* with base keyword argument and FNM_DOTMATCH" do
+ expected = %w[
+ .
+ .dotfile.ext
+ directory/structure/.ext
+ ].sort
+
+ Dir.glob('**/.*', File::FNM_DOTMATCH, base: "deeply/nested").sort.should == expected
+ end
+
+ it "handles **/** with base keyword argument and FNM_DOTMATCH" do
+ expected = %w[
+ .
+ .dotfile.ext
+ directory
+ directory/structure
+ directory/structure/.ext
+ directory/structure/bar
+ directory/structure/baz
+ directory/structure/file_one
+ directory/structure/file_one.ext
+ directory/structure/foo
+ ].sort
+
+ Dir.glob('**/**', File::FNM_DOTMATCH, base: "deeply/nested").sort.should == expected
+ end
+ end
+
+ it "handles **/*pattern* with base keyword argument and FNM_DOTMATCH" do
+ expected = %w[
+ .dotfile.ext
+ directory/structure/file_one
+ directory/structure/file_one.ext
+ ]
+
+ Dir.glob('**/*file*', File::FNM_DOTMATCH, base: "deeply/nested").sort.should == expected
+ end
+
+ it "handles **/glob with base keyword argument and FNM_EXTGLOB" do
+ expected = %w[
+ directory/structure/bar
+ directory/structure/file_one
+ directory/structure/file_one.ext
+ ]
+
+ Dir.glob('**/*{file,bar}*', File::FNM_EXTGLOB, base: "deeply/nested").sort.should == expected
+ end
+
it "handles simple filename patterns" do
Dir.glob('.dotfile').should == ['.dotfile']
end
@@ -222,5 +352,30 @@ describe "Dir.glob" do
Dir.rmdir('no_permission')
end
end
+
+ it "will follow symlinks when processing a `*/` pattern." do
+ expected = ['special/ln/nondotfile']
+ Dir.glob('special/*/nondotfile').should == expected
+ end
+
+ it "will not follow symlinks when recursively traversing directories" do
+ expected = %w[
+ deeply/nondotfile
+ nondotfile
+ subdir_one/nondotfile
+ subdir_two/nondotfile
+ ]
+ Dir.glob('**/nondotfile').sort.should == expected
+ end
+
+ it "will follow symlinks when testing directory after recursive directory in pattern" do
+ expected = %w[
+ deeply/nondotfile
+ special/ln/nondotfile
+ subdir_one/nondotfile
+ subdir_two/nondotfile
+ ]
+ Dir.glob('**/*/nondotfile').sort.should == expected
+ end
end
end
diff --git a/spec/ruby/core/dir/home_spec.rb b/spec/ruby/core/dir/home_spec.rb
index 713ba9db9a..3cf745ab46 100644
--- a/spec/ruby/core/dir/home_spec.rb
+++ b/spec/ruby/core/dir/home_spec.rb
@@ -19,6 +19,44 @@ describe "Dir.home" do
it "returns a non-frozen string" do
Dir.home.should_not.frozen?
end
+
+ it "returns a string with the filesystem encoding" do
+ Dir.home.encoding.should == Encoding.find("filesystem")
+ end
+
+ platform_is_not :windows do
+ it "works even if HOME is unset" do
+ ENV.delete('HOME')
+ Dir.home.should.start_with?('/')
+ Dir.home.encoding.should == Encoding.find("filesystem")
+ end
+ end
+
+ platform_is :windows do
+ ruby_version_is "3.2" do
+ it "returns the home directory with forward slashs and as UTF-8" do
+ ENV['HOME'] = "C:\\rubyspäc\\home"
+ home = Dir.home
+ home.should == "C:/rubyspäc/home"
+ home.encoding.should == Encoding::UTF_8
+ end
+
+ it "retrieves the directory from HOME, USERPROFILE, HOMEDRIVE/HOMEPATH and the WinAPI in that order" do
+ old_dirs = [ENV.delete('HOME'), ENV.delete('USERPROFILE'), ENV.delete('HOMEDRIVE'), ENV.delete('HOMEPATH')]
+
+ Dir.home.should == old_dirs[1].gsub("\\", "/")
+ ENV['HOMEDRIVE'] = "C:"
+ ENV['HOMEPATH'] = "\\rubyspec\\home1"
+ Dir.home.should == "C:/rubyspec/home1"
+ ENV['USERPROFILE'] = "C:\\rubyspec\\home2"
+ Dir.home.should == "C:/rubyspec/home2"
+ ENV['HOME'] = "C:\\rubyspec\\home3"
+ Dir.home.should == "C:/rubyspec/home3"
+ ensure
+ ENV['HOME'], ENV['USERPROFILE'], ENV['HOMEDRIVE'], ENV['HOMEPATH'] = *old_dirs
+ end
+ end
+ end
end
describe "when called with the current user name" do
@@ -28,7 +66,7 @@ describe "Dir.home" do
end
end
- platform_is_not :windows, :solaris, :android do
+ platform_is_not :windows, :solaris, :android, :wasi do
it "returns the named user's home directory, from the user database" do
Dir.home(ENV['USER']).should == `echo ~#{ENV['USER']}`.chomp
end
@@ -37,9 +75,19 @@ describe "Dir.home" do
it "returns a non-frozen string" do
Dir.home(ENV['USER']).should_not.frozen?
end
+
+ it "returns a string with the filesystem encoding" do
+ Dir.home(ENV['USER']).encoding.should == Encoding.find("filesystem")
+ end
end
it "raises an ArgumentError if the named user doesn't exist" do
-> { Dir.home('geuw2n288dh2k') }.should raise_error(ArgumentError)
end
+
+ describe "when called with a nil user name" do
+ it "returns the current user's home directory, reading $HOME first" do
+ Dir.home(nil).should == "/rubyspec_home"
+ end
+ end
end
diff --git a/spec/ruby/core/dir/mkdir_spec.rb b/spec/ruby/core/dir/mkdir_spec.rb
index 0ed28f5a99..076ec19dd9 100644
--- a/spec/ruby/core/dir/mkdir_spec.rb
+++ b/spec/ruby/core/dir/mkdir_spec.rb
@@ -46,7 +46,7 @@ describe "Dir.mkdir" do
end
end
- it "calls #to_path on non-String arguments" do
+ it "calls #to_path on non-String path arguments" do
DirSpecs.clear_dirs
p = mock('path')
p.should_receive(:to_path).and_return(DirSpecs.mock_dir('nonexisting'))
@@ -54,6 +54,22 @@ describe "Dir.mkdir" do
DirSpecs.clear_dirs
end
+ it "calls #to_int on non-Integer permissions argument" do
+ DirSpecs.clear_dirs
+ path = DirSpecs.mock_dir('nonexisting')
+ permissions = mock('permissions')
+ permissions.should_receive(:to_int).and_return(0666)
+ Dir.mkdir(path, permissions)
+ DirSpecs.clear_dirs
+ end
+
+ it "raises TypeError if non-Integer permissions argument does not have #to_int method" do
+ path = DirSpecs.mock_dir('nonexisting')
+ permissions = Object.new
+
+ -> { Dir.mkdir(path, permissions) }.should raise_error(TypeError, 'no implicit conversion of Object into Integer')
+ end
+
it "raises a SystemCallError if any of the directories in the path before the last does not exist" do
-> { Dir.mkdir "#{DirSpecs.nonexistent}/subdir" }.should raise_error(SystemCallError)
end
diff --git a/spec/ruby/core/dir/read_spec.rb b/spec/ruby/core/dir/read_spec.rb
index 59de2e81cf..276930c6b7 100644
--- a/spec/ruby/core/dir/read_spec.rb
+++ b/spec/ruby/core/dir/read_spec.rb
@@ -39,5 +39,38 @@ describe "Dir#read" do
entries.sort.should == DirSpecs.expected_paths
end
+ platform_is_not :windows do
+ it "returns all directory entries even when encoding conversion will fail" do
+ dir = Dir.open(File.join(DirSpecs.mock_dir, 'special'))
+ utf8_entries = []
+ begin
+ while entry = dir.read
+ utf8_entries << entry
+ end
+ ensure
+ dir.close
+ end
+ old_internal_encoding = Encoding::default_internal
+ old_external_encoding = Encoding::default_external
+ Encoding.default_internal = Encoding::UTF_8
+ Encoding.default_external = Encoding::SHIFT_JIS
+ shift_jis_entries = []
+ begin
+ Dir.open(File.join(DirSpecs.mock_dir, 'special')) do |d|
+ -> {
+ while entry = d.read
+ shift_jis_entries << entry
+ end
+ }.should_not raise_error
+ end
+ ensure
+ Encoding.default_internal = old_internal_encoding
+ Encoding.default_external = old_external_encoding
+ end
+ shift_jis_entries.size.should == utf8_entries.size
+ shift_jis_entries.filter { |f| f.encoding == Encoding::SHIFT_JIS }.size.should == 1
+ end
+ end
+
it_behaves_like :dir_closed, :read
end
diff --git a/spec/ruby/core/dir/shared/chroot.rb b/spec/ruby/core/dir/shared/chroot.rb
index b14a433670..a8f7c10a19 100644
--- a/spec/ruby/core/dir/shared/chroot.rb
+++ b/spec/ruby/core/dir/shared/chroot.rb
@@ -2,8 +2,8 @@ describe :dir_chroot_as_root, shared: true do
before :all do
DirSpecs.create_mock_dirs
- @real_root = "../" * (File.dirname(__FILE__).count('/') - 1)
- @ref_dir = File.join("/", Dir.new('/').entries.first)
+ @real_root = "../" * (__dir__.count('/') - 1)
+ @ref_dir = File.join("/", File.basename(Dir["/*"].first))
end
after :all do
@@ -14,10 +14,13 @@ describe :dir_chroot_as_root, shared: true do
DirSpecs.delete_mock_dirs
end
+ # Pending until https://github.com/ruby/ruby/runs/8075149420 is fixed
+ compilations_ci = ENV["GITHUB_WORKFLOW"] == "Compilations"
+
it "can be used to change the process' root directory" do
- -> { Dir.send(@method, File.dirname(__FILE__)) }.should_not raise_error
+ -> { Dir.send(@method, __dir__) }.should_not raise_error
File.should.exist?("/#{File.basename(__FILE__)}")
- end
+ end unless compilations_ci
it "returns 0 if successful" do
Dir.send(@method, '/').should == 0
@@ -31,7 +34,7 @@ describe :dir_chroot_as_root, shared: true do
Dir.send(@method, @real_root)
File.should.exist?(@ref_dir)
File.should_not.exist?("/#{File.basename(__FILE__)}")
- end
+ end unless compilations_ci
it "calls #to_path on non-String argument" do
p = mock('path')
diff --git a/spec/ruby/core/dir/shared/exist.rb b/spec/ruby/core/dir/shared/exist.rb
index 765d1b656c..2ea4f88a80 100644
--- a/spec/ruby/core/dir/shared/exist.rb
+++ b/spec/ruby/core/dir/shared/exist.rb
@@ -1,6 +1,6 @@
describe :dir_exist, shared: true do
it "returns true if the given directory exists" do
- Dir.send(@method, File.dirname(__FILE__)).should be_true
+ Dir.send(@method, __dir__).should be_true
end
it "returns true for '.'" do
@@ -20,7 +20,7 @@ describe :dir_exist, shared: true do
end
it "understands relative paths" do
- Dir.send(@method, File.dirname(__FILE__) + '/../').should be_true
+ Dir.send(@method, __dir__ + '/../').should be_true
end
it "returns false if the given directory doesn't exist" do
@@ -28,7 +28,7 @@ describe :dir_exist, shared: true do
end
it "doesn't require the name to have a trailing slash" do
- dir = File.dirname(__FILE__)
+ dir = __dir__
dir.sub!(/\/$/,'')
Dir.send(@method, dir).should be_true
end
@@ -50,7 +50,7 @@ describe :dir_exist, shared: true do
it "calls #to_path on non String arguments" do
p = mock('path')
- p.should_receive(:to_path).and_return(File.dirname(__FILE__))
+ p.should_receive(:to_path).and_return(__dir__)
Dir.send(@method, p)
end
end
diff --git a/spec/ruby/core/dir/shared/glob.rb b/spec/ruby/core/dir/shared/glob.rb
index a38ff8aa68..745f02d46b 100644
--- a/spec/ruby/core/dir/shared/glob.rb
+++ b/spec/ruby/core/dir/shared/glob.rb
@@ -12,7 +12,7 @@ describe :dir_glob, shared: true do
end
it "raises an Encoding::CompatibilityError if the argument encoding is not compatible with US-ASCII" do
- pattern = "file*".force_encoding Encoding::UTF_16BE
+ pattern = "file*".dup.force_encoding Encoding::UTF_16BE
-> { Dir.send(@method, pattern) }.should raise_error(Encoding::CompatibilityError)
end
@@ -23,39 +23,26 @@ describe :dir_glob, shared: true do
Dir.send(@method, obj).should == %w[file_one.ext]
end
- ruby_version_is ""..."2.7" do
- it "splits the string on \\0 if there is only one string given and warns" do
- -> {
- Dir.send(@method, "file_o*\0file_t*").should ==
- %w!file_one.ext file_two.ext!
- }.should complain(/warning: use glob patterns list instead of nul-separated patterns/)
- end
+ it "raises an ArgumentError if the string contains \\0" do
+ -> {Dir.send(@method, "file_o*\0file_t*")}.should raise_error ArgumentError, /nul-separated/
end
- ruby_version_is "2.7" do
- it "raises an ArgumentError if the string contains \\0" do
- -> {Dir.send(@method, "file_o*\0file_t*")}.should raise_error ArgumentError, /nul-separated/
- end
+ it "result is sorted by default" do
+ result = Dir.send(@method, '*')
+ result.should == result.sort
end
- ruby_version_is "3.0" do
- it "result is sorted by default" do
- result = Dir.send(@method, '*')
- result.should == result.sort
- end
-
- it "result is sorted with sort: true" do
- result = Dir.send(@method, '*', sort: true)
- result.should == result.sort
- end
+ it "result is sorted with sort: true" do
+ result = Dir.send(@method, '*', sort: true)
+ result.should == result.sort
+ end
- it "sort: false returns same files" do
- result = Dir.send(@method,'*', sort: false)
- result.sort.should == Dir.send(@method, '*').sort
- end
+ it "sort: false returns same files" do
+ result = Dir.send(@method,'*', sort: false)
+ result.sort.should == Dir.send(@method, '*').sort
end
- ruby_version_is "3.0"..."3.1" do
+ 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
@@ -122,6 +109,10 @@ describe :dir_glob, shared: true do
it "matches files with backslashes in their name" do
Dir.glob('special/\\\\{a,b}').should == ['special/\a']
end
+
+ it "matches directory with special characters in their name in complex patterns" do
+ Dir.glob("special/test +()\\[\\]\\{\\}/hello_world{.{en},}{.{html},}{+{phone},}{.{erb},}").should == ['special/test +()[]{}/hello_world.erb']
+ end
end
it "matches regexp special ^" do
@@ -236,6 +227,7 @@ describe :dir_glob, shared: true do
dir/
nested/
special/
+ special/test\ +()[]{}/
special/test{1}/
special/{}/
subdir_one/
diff --git a/spec/ruby/core/encoding/compatible_spec.rb b/spec/ruby/core/encoding/compatible_spec.rb
index 80ecab6155..f18d8680a9 100644
--- a/spec/ruby/core/encoding/compatible_spec.rb
+++ b/spec/ruby/core/encoding/compatible_spec.rb
@@ -7,7 +7,7 @@ require_relative '../../spec_helper'
describe "Encoding.compatible? String, String" do
describe "when the first's Encoding is valid US-ASCII" do
before :each do
- @str = "abc".force_encoding Encoding::US_ASCII
+ @str = "abc".dup.force_encoding Encoding::US_ASCII
end
it "returns US-ASCII when the second's is US-ASCII" do
@@ -33,28 +33,28 @@ describe "Encoding.compatible? String, String" do
describe "when the first's Encoding is ASCII compatible and ASCII only" do
it "returns the first's Encoding if the second is ASCII compatible and ASCII only" do
- [ [Encoding, "abc".force_encoding("UTF-8"), "123".force_encoding("Shift_JIS"), Encoding::UTF_8],
- [Encoding, "123".force_encoding("Shift_JIS"), "abc".force_encoding("UTF-8"), Encoding::Shift_JIS]
+ [ [Encoding, "abc".dup.force_encoding("UTF-8"), "123".dup.force_encoding("Shift_JIS"), Encoding::UTF_8],
+ [Encoding, "123".dup.force_encoding("Shift_JIS"), "abc".dup.force_encoding("UTF-8"), Encoding::Shift_JIS]
].should be_computed_by(:compatible?)
end
it "returns the first's Encoding if the second is ASCII compatible and ASCII only" do
- [ [Encoding, "abc".force_encoding("BINARY"), "123".force_encoding("US-ASCII"), Encoding::BINARY],
- [Encoding, "123".force_encoding("US-ASCII"), "abc".force_encoding("BINARY"), Encoding::US_ASCII]
+ [ [Encoding, "abc".dup.force_encoding("BINARY"), "123".dup.force_encoding("US-ASCII"), Encoding::BINARY],
+ [Encoding, "123".dup.force_encoding("US-ASCII"), "abc".dup.force_encoding("BINARY"), Encoding::US_ASCII]
].should be_computed_by(:compatible?)
end
it "returns the second's Encoding if the second is ASCII compatible but not ASCII only" do
- [ [Encoding, "abc".force_encoding("UTF-8"), "\xff".force_encoding("Shift_JIS"), Encoding::Shift_JIS],
- [Encoding, "123".force_encoding("Shift_JIS"), "\xff".force_encoding("UTF-8"), Encoding::UTF_8],
- [Encoding, "abc".force_encoding("BINARY"), "\xff".force_encoding("US-ASCII"), Encoding::US_ASCII],
- [Encoding, "123".force_encoding("US-ASCII"), "\xff".force_encoding("BINARY"), Encoding::BINARY],
+ [ [Encoding, "abc".dup.force_encoding("UTF-8"), "\xff".dup.force_encoding("Shift_JIS"), Encoding::Shift_JIS],
+ [Encoding, "123".dup.force_encoding("Shift_JIS"), "\xff".dup.force_encoding("UTF-8"), Encoding::UTF_8],
+ [Encoding, "abc".dup.force_encoding("BINARY"), "\xff".dup.force_encoding("US-ASCII"), Encoding::US_ASCII],
+ [Encoding, "123".dup.force_encoding("US-ASCII"), "\xff".dup.force_encoding("BINARY"), Encoding::BINARY],
].should be_computed_by(:compatible?)
end
it "returns nil if the second's Encoding is not ASCII compatible" do
- a = "abc".force_encoding("UTF-8")
- b = "1234".force_encoding("UTF-16LE")
+ a = "abc".dup.force_encoding("UTF-8")
+ b = "1234".dup.force_encoding("UTF-16LE")
Encoding.compatible?(a, b).should be_nil
end
end
@@ -75,7 +75,7 @@ describe "Encoding.compatible? String, String" do
describe "when the first's Encoding is not ASCII compatible" do
before :each do
- @str = "abc".force_encoding Encoding::UTF_7
+ @str = "abc".dup.force_encoding Encoding::UTF_7
end
it "returns nil when the second String is US-ASCII" do
@@ -91,14 +91,14 @@ describe "Encoding.compatible? String, String" do
end
it "returns the Encoding when the second's Encoding is not ASCII compatible but the same as the first's Encoding" do
- encoding = Encoding.compatible?(@str, "def".force_encoding("utf-7"))
+ encoding = Encoding.compatible?(@str, "def".dup.force_encoding("utf-7"))
encoding.should == Encoding::UTF_7
end
end
describe "when the first's Encoding is invalid" do
before :each do
- @str = "\xff".force_encoding Encoding::UTF_8
+ @str = "\xff".dup.force_encoding Encoding::UTF_8
end
it "returns the first's Encoding when the second's Encoding is US-ASCII" do
@@ -114,11 +114,11 @@ describe "Encoding.compatible? String, String" do
end
it "returns nil when the second's Encoding is invalid and ASCII only" do
- Encoding.compatible?(@str, "\x7f".force_encoding("utf-16be")).should be_nil
+ Encoding.compatible?(@str, "\x7f".dup.force_encoding("utf-16be")).should be_nil
end
it "returns nil when the second's Encoding is invalid and not ASCII only" do
- Encoding.compatible?(@str, "\xff".force_encoding("utf-16be")).should be_nil
+ Encoding.compatible?(@str, "\xff".dup.force_encoding("utf-16be")).should be_nil
end
it "returns the Encoding when the second's Encoding is invalid but the same as the first" do
@@ -129,7 +129,7 @@ describe "Encoding.compatible? String, String" do
describe "when the first String is empty and the second is not" do
describe "and the first's Encoding is ASCII compatible" do
before :each do
- @str = "".force_encoding("utf-8")
+ @str = "".dup.force_encoding("utf-8")
end
it "returns the first's encoding when the second String is ASCII only" do
@@ -143,7 +143,7 @@ describe "Encoding.compatible? String, String" do
describe "when the first's Encoding is not ASCII compatible" do
before :each do
- @str = "".force_encoding Encoding::UTF_7
+ @str = "".dup.force_encoding Encoding::UTF_7
end
it "returns the second string's encoding" do
@@ -154,7 +154,7 @@ describe "Encoding.compatible? String, String" do
describe "when the second String is empty" do
before :each do
- @str = "abc".force_encoding("utf-7")
+ @str = "abc".dup.force_encoding("utf-7")
end
it "returns the first Encoding" do
@@ -165,7 +165,7 @@ end
describe "Encoding.compatible? String, Regexp" do
it "returns US-ASCII if both are US-ASCII" do
- str = "abc".force_encoding("us-ascii")
+ str = "abc".dup.force_encoding("us-ascii")
Encoding.compatible?(str, /abc/).should == Encoding::US_ASCII
end
@@ -180,15 +180,15 @@ describe "Encoding.compatible? String, Regexp" do
it "returns the String's Encoding if the String is not ASCII only" do
[ [Encoding, "\xff", Encoding::BINARY],
[Encoding, "\u3042".encode("utf-8"), Encoding::UTF_8],
- [Encoding, "\xa4\xa2".force_encoding("euc-jp"), Encoding::EUC_JP],
- [Encoding, "\x82\xa0".force_encoding("shift_jis"), Encoding::Shift_JIS],
+ [Encoding, "\xa4\xa2".dup.force_encoding("euc-jp"), Encoding::EUC_JP],
+ [Encoding, "\x82\xa0".dup.force_encoding("shift_jis"), Encoding::Shift_JIS],
].should be_computed_by(:compatible?, /abc/)
end
end
describe "Encoding.compatible? String, Symbol" do
it "returns US-ASCII if both are ASCII only" do
- str = "abc".force_encoding("us-ascii")
+ str = "abc".dup.force_encoding("us-ascii")
Encoding.compatible?(str, :abc).should == Encoding::US_ASCII
end
@@ -203,8 +203,8 @@ describe "Encoding.compatible? String, Symbol" do
it "returns the String's Encoding if the String is not ASCII only" do
[ [Encoding, "\xff", Encoding::BINARY],
[Encoding, "\u3042".encode("utf-8"), Encoding::UTF_8],
- [Encoding, "\xa4\xa2".force_encoding("euc-jp"), Encoding::EUC_JP],
- [Encoding, "\x82\xa0".force_encoding("shift_jis"), Encoding::Shift_JIS],
+ [Encoding, "\xa4\xa2".dup.force_encoding("euc-jp"), Encoding::EUC_JP],
+ [Encoding, "\x82\xa0".dup.force_encoding("shift_jis"), Encoding::Shift_JIS],
].should be_computed_by(:compatible?, :abc)
end
end
@@ -221,8 +221,8 @@ describe "Encoding.compatible? String, Encoding" do
it "returns the String's encoding if the Encoding is US-ASCII" do
[ [Encoding, "\xff", Encoding::BINARY],
[Encoding, "\u3042".encode("utf-8"), Encoding::UTF_8],
- [Encoding, "\xa4\xa2".force_encoding("euc-jp"), Encoding::EUC_JP],
- [Encoding, "\x82\xa0".force_encoding("shift_jis"), Encoding::Shift_JIS],
+ [Encoding, "\xa4\xa2".dup.force_encoding("euc-jp"), Encoding::EUC_JP],
+ [Encoding, "\x82\xa0".dup.force_encoding("shift_jis"), Encoding::Shift_JIS],
].should be_computed_by(:compatible?, Encoding::US_ASCII)
end
@@ -242,7 +242,7 @@ end
describe "Encoding.compatible? Regexp, String" do
it "returns US-ASCII if both are US-ASCII" do
- str = "abc".force_encoding("us-ascii")
+ str = "abc".dup.force_encoding("us-ascii")
Encoding.compatible?(/abc/, str).should == Encoding::US_ASCII
end
@@ -256,8 +256,8 @@ describe "Encoding.compatible? Regexp, Regexp" do
it "returns the first's Encoding if it is not US-ASCII and not ASCII only" do
[ [Encoding, Regexp.new("\xff"), Encoding::BINARY],
[Encoding, Regexp.new("\u3042".encode("utf-8")), Encoding::UTF_8],
- [Encoding, Regexp.new("\xa4\xa2".force_encoding("euc-jp")), Encoding::EUC_JP],
- [Encoding, Regexp.new("\x82\xa0".force_encoding("shift_jis")), Encoding::Shift_JIS],
+ [Encoding, Regexp.new("\xa4\xa2".dup.force_encoding("euc-jp")), Encoding::EUC_JP],
+ [Encoding, Regexp.new("\x82\xa0".dup.force_encoding("shift_jis")), Encoding::Shift_JIS],
].should be_computed_by(:compatible?, /abc/)
end
end
@@ -270,15 +270,15 @@ describe "Encoding.compatible? Regexp, Symbol" do
it "returns the first's Encoding if it is not US-ASCII and not ASCII only" do
[ [Encoding, Regexp.new("\xff"), Encoding::BINARY],
[Encoding, Regexp.new("\u3042".encode("utf-8")), Encoding::UTF_8],
- [Encoding, Regexp.new("\xa4\xa2".force_encoding("euc-jp")), Encoding::EUC_JP],
- [Encoding, Regexp.new("\x82\xa0".force_encoding("shift_jis")), Encoding::Shift_JIS],
+ [Encoding, Regexp.new("\xa4\xa2".dup.force_encoding("euc-jp")), Encoding::EUC_JP],
+ [Encoding, Regexp.new("\x82\xa0".dup.force_encoding("shift_jis")), Encoding::Shift_JIS],
].should be_computed_by(:compatible?, /abc/)
end
end
describe "Encoding.compatible? Symbol, String" do
it "returns US-ASCII if both are ASCII only" do
- str = "abc".force_encoding("us-ascii")
+ str = "abc".dup.force_encoding("us-ascii")
Encoding.compatible?(str, :abc).should == Encoding::US_ASCII
end
end
@@ -291,8 +291,8 @@ describe "Encoding.compatible? Symbol, Regexp" do
it "returns the Regexp's Encoding if it is not US-ASCII and not ASCII only" do
a = Regexp.new("\xff")
b = Regexp.new("\u3042".encode("utf-8"))
- c = Regexp.new("\xa4\xa2".force_encoding("euc-jp"))
- d = Regexp.new("\x82\xa0".force_encoding("shift_jis"))
+ c = Regexp.new("\xa4\xa2".dup.force_encoding("euc-jp"))
+ d = Regexp.new("\x82\xa0".dup.force_encoding("shift_jis"))
[ [Encoding, :abc, a, Encoding::BINARY],
[Encoding, :abc, b, Encoding::UTF_8],
@@ -310,8 +310,8 @@ describe "Encoding.compatible? Symbol, Symbol" do
it "returns the first's Encoding if it is not ASCII only" do
[ [Encoding, "\xff".to_sym, Encoding::BINARY],
[Encoding, "\u3042".encode("utf-8").to_sym, Encoding::UTF_8],
- [Encoding, "\xa4\xa2".force_encoding("euc-jp").to_sym, Encoding::EUC_JP],
- [Encoding, "\x82\xa0".force_encoding("shift_jis").to_sym, Encoding::Shift_JIS],
+ [Encoding, "\xa4\xa2".dup.force_encoding("euc-jp").to_sym, Encoding::EUC_JP],
+ [Encoding, "\x82\xa0".dup.force_encoding("shift_jis").to_sym, Encoding::Shift_JIS],
].should be_computed_by(:compatible?, :abc)
end
end
diff --git a/spec/ruby/core/encoding/converter/convert_spec.rb b/spec/ruby/core/encoding/converter/convert_spec.rb
index 95a9e0b758..7f249d90a3 100644
--- a/spec/ruby/core/encoding/converter/convert_spec.rb
+++ b/spec/ruby/core/encoding/converter/convert_spec.rb
@@ -1,4 +1,5 @@
# -*- encoding: binary -*-
+# frozen_string_literal: true
require_relative '../../../spec_helper'
describe "Encoding::Converter#convert" do
@@ -9,31 +10,31 @@ describe "Encoding::Converter#convert" do
it "sets the encoding of the result to the target encoding" do
ec = Encoding::Converter.new('ascii', 'utf-8')
- str = 'glark'.force_encoding('ascii')
+ str = 'glark'.dup.force_encoding('ascii')
ec.convert(str).encoding.should == Encoding::UTF_8
end
it "transcodes the given String to the target encoding" do
ec = Encoding::Converter.new("utf-8", "euc-jp")
- ec.convert("\u3042".force_encoding('UTF-8')).should == \
- "\xA4\xA2".force_encoding('EUC-JP')
+ ec.convert("\u3042".dup.force_encoding('UTF-8')).should == \
+ "\xA4\xA2".dup.force_encoding('EUC-JP')
end
it "allows Strings of different encodings to the source encoding" do
ec = Encoding::Converter.new('ascii', 'utf-8')
- str = 'glark'.force_encoding('SJIS')
+ str = 'glark'.dup.force_encoding('SJIS')
ec.convert(str).encoding.should == Encoding::UTF_8
end
it "reuses the given encoding pair if called multiple times" do
ec = Encoding::Converter.new('ascii', 'SJIS')
- ec.convert('a'.force_encoding('ASCII')).should == 'a'.force_encoding('SJIS')
- ec.convert('b'.force_encoding('ASCII')).should == 'b'.force_encoding('SJIS')
+ ec.convert('a'.dup.force_encoding('ASCII')).should == 'a'.dup.force_encoding('SJIS')
+ ec.convert('b'.dup.force_encoding('ASCII')).should == 'b'.dup.force_encoding('SJIS')
end
it "raises UndefinedConversionError if the String contains characters invalid for the target encoding" do
ec = Encoding::Converter.new('UTF-8', Encoding.find('macCyrillic'))
- -> { ec.convert("\u{6543}".force_encoding('UTF-8')) }.should \
+ -> { ec.convert("\u{6543}".dup.force_encoding('UTF-8')) }.should \
raise_error(Encoding::UndefinedConversionError)
end
diff --git a/spec/ruby/core/encoding/converter/finish_spec.rb b/spec/ruby/core/encoding/converter/finish_spec.rb
index 11ca7e8510..239243430b 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".force_encoding('iso-2022-jp')
- @ec.finish.should == "\e(B".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 68567737b7..78779be70b 100644
--- a/spec/ruby/core/encoding/converter/last_error_spec.rb
+++ b/spec/ruby/core/encoding/converter/last_error_spec.rb
@@ -9,45 +9,45 @@ describe "Encoding::Converter#last_error" do
it "returns nil when the last conversion did not produce an error" do
ec = Encoding::Converter.new('ascii','utf-8')
- ec.convert('a'.force_encoding('ascii'))
+ ec.convert('a'.dup.force_encoding('ascii'))
ec.last_error.should be_nil
end
it "returns nil when #primitive_convert last returned :destination_buffer_full" do
ec = Encoding::Converter.new("utf-8", "iso-2022-jp")
- ec.primitive_convert("\u{9999}", "", 0, 0, partial_input: false) \
+ ec.primitive_convert(+"\u{9999}", +"", 0, 0, partial_input: false) \
.should == :destination_buffer_full
ec.last_error.should be_nil
end
it "returns nil when #primitive_convert last returned :finished" do
ec = Encoding::Converter.new("utf-8", "iso-8859-1")
- ec.primitive_convert("glark".force_encoding('utf-8'),"").should == :finished
+ ec.primitive_convert("glark".dup.force_encoding('utf-8'), +"").should == :finished
ec.last_error.should be_nil
end
it "returns nil if the last conversion succeeded but the penultimate failed" do
ec = Encoding::Converter.new("utf-8", "iso-8859-1")
- ec.primitive_convert("\xf1abcd","").should == :invalid_byte_sequence
- ec.primitive_convert("glark".force_encoding('utf-8'),"").should == :finished
+ ec.primitive_convert(+"\xf1abcd", +"").should == :invalid_byte_sequence
+ ec.primitive_convert("glark".dup.force_encoding('utf-8'), +"").should == :finished
ec.last_error.should be_nil
end
it "returns an Encoding::InvalidByteSequenceError when #primitive_convert last returned :invalid_byte_sequence" do
ec = Encoding::Converter.new("utf-8", "iso-8859-1")
- ec.primitive_convert("\xf1abcd","").should == :invalid_byte_sequence
+ ec.primitive_convert(+"\xf1abcd", +"").should == :invalid_byte_sequence
ec.last_error.should be_an_instance_of(Encoding::InvalidByteSequenceError)
end
it "returns an Encoding::UndefinedConversionError when #primitive_convert last returned :undefined_conversion" do
ec = Encoding::Converter.new("utf-8", "iso-8859-1")
- ec.primitive_convert("\u{9876}","").should == :undefined_conversion
+ ec.primitive_convert(+"\u{9876}", +"").should == :undefined_conversion
ec.last_error.should be_an_instance_of(Encoding::UndefinedConversionError)
end
it "returns an Encoding::InvalidByteSequenceError when #primitive_convert last returned :incomplete_input" do
ec = Encoding::Converter.new("EUC-JP", "ISO-8859-1")
- ec.primitive_convert("\xa4", "", nil, 10).should == :incomplete_input
+ ec.primitive_convert(+"\xa4", +"", nil, 10).should == :incomplete_input
ec.last_error.should be_an_instance_of(Encoding::InvalidByteSequenceError)
end
diff --git a/spec/ruby/core/encoding/converter/new_spec.rb b/spec/ruby/core/encoding/converter/new_spec.rb
index 1f7affc72b..db9c3364d7 100644
--- a/spec/ruby/core/encoding/converter/new_spec.rb
+++ b/spec/ruby/core/encoding/converter/new_spec.rb
@@ -107,7 +107,7 @@ describe "Encoding::Converter.new" do
it "sets the replacement String to '\\uFFFD'" do
conv = Encoding::Converter.new("us-ascii", "utf-8", replace: nil)
- conv.replacement.should == "\u{fffd}".force_encoding("utf-8")
+ conv.replacement.should == "\u{fffd}".dup.force_encoding("utf-8")
end
it "sets the replacement String encoding to UTF-8" do
diff --git a/spec/ruby/core/encoding/converter/primitive_convert_spec.rb b/spec/ruby/core/encoding/converter/primitive_convert_spec.rb
index 802d8e7cb1..63f25eddef 100644
--- a/spec/ruby/core/encoding/converter/primitive_convert_spec.rb
+++ b/spec/ruby/core/encoding/converter/primitive_convert_spec.rb
@@ -1,4 +1,5 @@
# -*- encoding: binary -*-
+# frozen_string_literal: false
require_relative '../../../spec_helper'
describe "Encoding::Converter#primitive_convert" do
@@ -14,6 +15,10 @@ describe "Encoding::Converter#primitive_convert" do
-> { @ec.primitive_convert("","") }.should_not raise_error
end
+ it "raises FrozenError when the destination buffer is a frozen String" do
+ -> { @ec.primitive_convert("", "".freeze) }.should raise_error(FrozenError)
+ end
+
it "accepts nil for the destination byte offset" do
-> { @ec.primitive_convert("","", nil) }.should_not raise_error
end
diff --git a/spec/ruby/core/encoding/converter/primitive_errinfo_spec.rb b/spec/ruby/core/encoding/converter/primitive_errinfo_spec.rb
index 1f836b259f..668eb9a924 100644
--- a/spec/ruby/core/encoding/converter/primitive_errinfo_spec.rb
+++ b/spec/ruby/core/encoding/converter/primitive_errinfo_spec.rb
@@ -1,4 +1,5 @@
# -*- encoding: binary -*-
+# frozen_string_literal: false
require_relative '../../../spec_helper'
describe "Encoding::Converter#primitive_errinfo" do
diff --git a/spec/ruby/core/encoding/converter/putback_spec.rb b/spec/ruby/core/encoding/converter/putback_spec.rb
index c4e0a5da21..e19fe6c314 100644
--- a/spec/ruby/core/encoding/converter/putback_spec.rb
+++ b/spec/ruby/core/encoding/converter/putback_spec.rb
@@ -4,7 +4,7 @@ require_relative '../../../spec_helper'
describe "Encoding::Converter#putback" do
before :each do
@ec = Encoding::Converter.new("EUC-JP", "ISO-8859-1")
- @ret = @ec.primitive_convert(@src="abc\xa1def", @dst="", nil, 10)
+ @ret = @ec.primitive_convert(@src=+"abc\xa1def", @dst=+"", nil, 10)
end
it "returns a String" do
@@ -36,21 +36,21 @@ describe "Encoding::Converter#putback" do
it "returns the problematic bytes for UTF-16LE" do
ec = Encoding::Converter.new("utf-16le", "iso-8859-1")
- src = "\x00\xd8\x61\x00"
- dst = ""
+ src = +"\x00\xd8\x61\x00"
+ dst = +""
ec.primitive_convert(src, dst).should == :invalid_byte_sequence
ec.primitive_errinfo.should == [:invalid_byte_sequence, "UTF-16LE", "UTF-8", "\x00\xD8", "a\x00"]
- ec.putback.should == "a\x00".force_encoding("utf-16le")
+ ec.putback.should == "a\x00".dup.force_encoding("utf-16le")
ec.putback.should == ""
end
it "accepts an integer argument corresponding to the number of bytes to be put back" do
ec = Encoding::Converter.new("utf-16le", "iso-8859-1")
- src = "\x00\xd8\x61\x00"
- dst = ""
+ src = +"\x00\xd8\x61\x00"
+ dst = +""
ec.primitive_convert(src, dst).should == :invalid_byte_sequence
ec.primitive_errinfo.should == [:invalid_byte_sequence, "UTF-16LE", "UTF-8", "\x00\xD8", "a\x00"]
- ec.putback(2).should == "a\x00".force_encoding("utf-16le")
+ ec.putback(2).should == "a\x00".dup.force_encoding("utf-16le")
ec.putback.should == ""
end
end
diff --git a/spec/ruby/core/encoding/converter/replacement_spec.rb b/spec/ruby/core/encoding/converter/replacement_spec.rb
index 5ca42e7e5a..ea514ca8dd 100644
--- a/spec/ruby/core/encoding/converter/replacement_spec.rb
+++ b/spec/ruby/core/encoding/converter/replacement_spec.rb
@@ -13,7 +13,7 @@ describe "Encoding::Converter#replacement" do
it "returns \\uFFFD when the destination encoding is UTF-8" do
ec = Encoding::Converter.new("us-ascii", "utf-8")
- ec.replacement.should == "\u{fffd}".force_encoding('utf-8')
+ ec.replacement.should == "\u{fffd}".dup.force_encoding('utf-8')
ec.replacement.encoding.should == Encoding::UTF_8
end
end
@@ -38,33 +38,33 @@ describe "Encoding::Converter#replacement=" do
it "sets #replacement" do
ec = Encoding::Converter.new("us-ascii", "utf-8")
- ec.replacement.should == "\u{fffd}".force_encoding('utf-8')
+ ec.replacement.should == "\u{fffd}".dup.force_encoding('utf-8')
ec.replacement = '?'.encode('utf-8')
- ec.replacement.should == '?'.force_encoding('utf-8')
+ ec.replacement.should == '?'.dup.force_encoding('utf-8')
end
it "raises an UndefinedConversionError is the argument cannot be converted into the destination encoding" do
ec = Encoding::Converter.new("sjis", "ascii")
- utf8_q = "\u{986}".force_encoding('utf-8')
- ec.primitive_convert(utf8_q.dup, "").should == :undefined_conversion
+ utf8_q = "\u{986}".dup.force_encoding('utf-8')
+ ec.primitive_convert(utf8_q.dup, +"").should == :undefined_conversion
-> { ec.replacement = utf8_q }.should \
raise_error(Encoding::UndefinedConversionError)
end
it "does not change the replacement character if the argument cannot be converted into the destination encoding" do
ec = Encoding::Converter.new("sjis", "ascii")
- utf8_q = "\u{986}".force_encoding('utf-8')
- ec.primitive_convert(utf8_q.dup, "").should == :undefined_conversion
+ utf8_q = "\u{986}".dup.force_encoding('utf-8')
+ ec.primitive_convert(utf8_q.dup, +"").should == :undefined_conversion
-> { ec.replacement = utf8_q }.should \
raise_error(Encoding::UndefinedConversionError)
- ec.replacement.should == "?".force_encoding('us-ascii')
+ ec.replacement.should == "?".dup.force_encoding('us-ascii')
end
it "uses the replacement character" do
ec = Encoding::Converter.new("utf-8", "us-ascii", :invalid => :replace, :undef => :replace)
ec.replacement = "!"
- dest = ""
- status = ec.primitive_convert "中文123", dest
+ dest = +""
+ status = ec.primitive_convert(+"中文123", dest)
status.should == :finished
dest.should == "!!123"
diff --git a/spec/ruby/core/encoding/default_external_spec.rb b/spec/ruby/core/encoding/default_external_spec.rb
index 682d49d37c..9aae4976e0 100644
--- a/spec/ruby/core/encoding/default_external_spec.rb
+++ b/spec/ruby/core/encoding/default_external_spec.rb
@@ -18,11 +18,9 @@ describe "Encoding.default_external" do
Encoding.default_external.should == Encoding::SHIFT_JIS
end
- ruby_version_is "3.0" do
- platform_is :windows do
- it 'is UTF-8 by default on Windows' do
- Encoding.default_external.should == Encoding::UTF_8
- end
+ platform_is :windows do
+ it 'is UTF-8 by default on Windows' do
+ Encoding.default_external.should == Encoding::UTF_8
end
end
end
diff --git a/spec/ruby/core/encoding/inspect_spec.rb b/spec/ruby/core/encoding/inspect_spec.rb
index 9a930b2a77..df96141db9 100644
--- a/spec/ruby/core/encoding/inspect_spec.rb
+++ b/spec/ruby/core/encoding/inspect_spec.rb
@@ -5,9 +5,23 @@ describe "Encoding#inspect" do
Encoding::UTF_8.inspect.should be_an_instance_of(String)
end
- it "returns #<Encoding:name> for a non-dummy encoding named 'name'" do
- Encoding.list.to_a.reject {|e| e.dummy? }.each do |enc|
- enc.inspect.should =~ /#<Encoding:#{enc.name}>/
+ ruby_version_is ""..."3.4" do
+ it "returns #<Encoding:name> for a non-dummy encoding named 'name'" do
+ Encoding.list.to_a.reject {|e| e.dummy? }.each do |enc|
+ enc.inspect.should =~ /#<Encoding:#{enc.name}>/
+ end
+ end
+ end
+
+ ruby_version_is "3.4" do
+ it "returns #<Encoding:name> for a non-dummy encoding named 'name'" do
+ Encoding.list.to_a.reject {|e| e.dummy? }.each do |enc|
+ if enc.name == "ASCII-8BIT"
+ enc.inspect.should == "#<Encoding:BINARY (ASCII-8BIT)>"
+ else
+ enc.inspect.should =~ /#<Encoding:#{enc.name}>/
+ end
+ end
end
end
diff --git a/spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_name_spec.rb b/spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_name_spec.rb
index f5fa6f55e3..2b15fc1a0f 100644
--- a/spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_name_spec.rb
+++ b/spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_name_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
require_relative '../fixtures/classes'
describe "Encoding::InvalidByteSequenceError#destination_encoding_name" do
diff --git a/spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_spec.rb b/spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_spec.rb
index 43be3ddd71..c2ed6de1d8 100644
--- a/spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_spec.rb
+++ b/spec/ruby/core/encoding/invalid_byte_sequence_error/destination_encoding_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
require_relative '../fixtures/classes'
describe "Encoding::InvalidByteSequenceError#destination_encoding" do
diff --git a/spec/ruby/core/encoding/invalid_byte_sequence_error/error_bytes_spec.rb b/spec/ruby/core/encoding/invalid_byte_sequence_error/error_bytes_spec.rb
index a8f7354b16..d2fc360dce 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,5 @@
# -*- encoding: binary -*-
+require_relative "../../../spec_helper"
require_relative '../fixtures/classes'
describe "Encoding::InvalidByteSequenceError#error_bytes" do
diff --git a/spec/ruby/core/encoding/invalid_byte_sequence_error/incomplete_input_spec.rb b/spec/ruby/core/encoding/invalid_byte_sequence_error/incomplete_input_spec.rb
index 94201a9b15..8a3f3de69a 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
@@ -8,7 +8,7 @@ describe "Encoding::InvalidByteSequenceError#incomplete_input?" do
it "returns true if #primitive_convert returned :incomplete_input for the same data" do
ec = Encoding::Converter.new("EUC-JP", "ISO-8859-1")
- ec.primitive_convert("\xA1",'').should == :incomplete_input
+ ec.primitive_convert(+"\xA1", +'').should == :incomplete_input
begin
ec.convert("\xA1")
rescue Encoding::InvalidByteSequenceError => e
@@ -18,7 +18,7 @@ describe "Encoding::InvalidByteSequenceError#incomplete_input?" do
it "returns false if #primitive_convert returned :invalid_byte_sequence for the same data" do
ec = Encoding::Converter.new("ascii", "utf-8")
- ec.primitive_convert("\xfffffffff",'').should == :invalid_byte_sequence
+ ec.primitive_convert(+"\xfffffffff", +'').should == :invalid_byte_sequence
begin
ec.convert("\xfffffffff")
rescue Encoding::InvalidByteSequenceError => e
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 93823b5db4..a5e2824984 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,5 @@
# -*- encoding: binary -*-
+require_relative "../../../spec_helper"
require_relative '../fixtures/classes'
describe "Encoding::InvalidByteSequenceError#readagain_bytes" do
@@ -14,11 +15,11 @@ describe "Encoding::InvalidByteSequenceError#readagain_bytes" do
it "returns the bytes to be read again" do
@exception.readagain_bytes.size.should == 1
- @exception.readagain_bytes.should == "a".force_encoding('binary')
+ @exception.readagain_bytes.should == "a".dup.force_encoding('binary')
@exception.readagain_bytes.should == @errinfo[-1]
@exception2.readagain_bytes.size.should == 1
- @exception2.readagain_bytes.should == "\xFF".force_encoding('binary')
+ @exception2.readagain_bytes.should == "\xFF".dup.force_encoding('binary')
@exception2.readagain_bytes.should == @errinfo2[-1]
end
diff --git a/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_name_spec.rb b/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_name_spec.rb
index bd3a51cbc5..a9464114a8 100644
--- a/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_name_spec.rb
+++ b/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_name_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
require_relative '../fixtures/classes'
describe "Encoding::UndefinedConversionError#source_encoding_name" do
diff --git a/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_spec.rb b/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_spec.rb
index f43d6d5830..7fdc0a122b 100644
--- a/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_spec.rb
+++ b/spec/ruby/core/encoding/invalid_byte_sequence_error/source_encoding_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
require_relative '../fixtures/classes'
describe "Encoding::InvalidByteSequenceError#source_encoding" do
diff --git a/spec/ruby/core/encoding/list_spec.rb b/spec/ruby/core/encoding/list_spec.rb
index 8efd94ab9c..bd3d5b7bc0 100644
--- a/spec/ruby/core/encoding/list_spec.rb
+++ b/spec/ruby/core/encoding/list_spec.rb
@@ -40,10 +40,8 @@ describe "Encoding.list" do
Encoding.list.should.include?(Encoding::UTF_8)
end
- ruby_version_is "2.7" do
- it 'includes CESU-8 encoding' do
- Encoding.list.should.include?(Encoding::CESU_8)
- end
+ it 'includes CESU-8 encoding' do
+ Encoding.list.should.include?(Encoding::CESU_8)
end
# TODO: Find example that illustrates this
diff --git a/spec/ruby/core/encoding/name_spec.rb b/spec/ruby/core/encoding/name_spec.rb
index 5eadb1d2f5..dce9347978 100644
--- a/spec/ruby/core/encoding/name_spec.rb
+++ b/spec/ruby/core/encoding/name_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../spec_helper"
require_relative 'shared/name'
describe "Encoding#name" do
diff --git a/spec/ruby/core/encoding/replicate_spec.rb b/spec/ruby/core/encoding/replicate_spec.rb
index 45727a5c0d..e22673db7d 100644
--- a/spec/ruby/core/encoding/replicate_spec.rb
+++ b/spec/ruby/core/encoding/replicate_spec.rb
@@ -2,66 +2,87 @@
require_relative '../../spec_helper'
describe "Encoding#replicate" do
- before :all do
- @i = 0
- end
+ ruby_version_is ""..."3.3" do
+ before :all do
+ @i = 0
+ end
- before :each do
- @i += 1
- @prefix = "RS#{@i}"
- end
+ before :each do
+ @i += 1
+ @prefix = "RS#{@i}"
+ end
- it "returns a replica of ASCII" do
- name = @prefix + '-ASCII'
- e = Encoding::ASCII.replicate(name)
- e.name.should == name
- Encoding.find(name).should == e
+ it "returns a replica of ASCII" do
+ name = @prefix + '-ASCII'
+ e = suppress_warning { Encoding::ASCII.replicate(name) }
+ e.name.should == name
+ Encoding.find(name).should == e
- "a".force_encoding(e).valid_encoding?.should be_true
- "\x80".force_encoding(e).valid_encoding?.should be_false
- end
+ "a".dup.force_encoding(e).valid_encoding?.should be_true
+ "\x80".dup.force_encoding(e).valid_encoding?.should be_false
+ end
- it "returns a replica of UTF-8" do
- name = @prefix + 'UTF-8'
- e = Encoding::UTF_8.replicate(name)
- e.name.should == name
- Encoding.find(name).should == e
+ it "returns a replica of UTF-8" do
+ name = @prefix + 'UTF-8'
+ e = suppress_warning { Encoding::UTF_8.replicate(name) }
+ e.name.should == name
+ Encoding.find(name).should == e
- "a".force_encoding(e).valid_encoding?.should be_true
- "\u3042".force_encoding(e).valid_encoding?.should be_true
- "\x80".force_encoding(e).valid_encoding?.should be_false
- end
+ "a".dup.force_encoding(e).valid_encoding?.should be_true
+ "\u3042".dup.force_encoding(e).valid_encoding?.should be_true
+ "\x80".dup.force_encoding(e).valid_encoding?.should be_false
+ end
- it "returns a replica of UTF-16BE" do
- name = @prefix + 'UTF-16-BE'
- e = Encoding::UTF_16BE.replicate(name)
- e.name.should == name
- Encoding.find(name).should == e
+ it "returns a replica of UTF-16BE" do
+ name = @prefix + 'UTF-16-BE'
+ e = suppress_warning { Encoding::UTF_16BE.replicate(name) }
+ e.name.should == name
+ Encoding.find(name).should == e
- "a".force_encoding(e).valid_encoding?.should be_false
- "\x30\x42".force_encoding(e).valid_encoding?.should be_true
- "\x80".force_encoding(e).valid_encoding?.should be_false
- end
+ "a".dup.force_encoding(e).valid_encoding?.should be_false
+ "\x30\x42".dup.force_encoding(e).valid_encoding?.should be_true
+ "\x80".dup.force_encoding(e).valid_encoding?.should be_false
+ end
- it "returns a replica of ISO-2022-JP" do
- name = @prefix + 'ISO-2022-JP'
- e = Encoding::ISO_2022_JP.replicate(name)
- Encoding.find(name).should == e
+ it "returns a replica of ISO-2022-JP" do
+ name = @prefix + 'ISO-2022-JP'
+ e = suppress_warning { Encoding::ISO_2022_JP.replicate(name) }
+ Encoding.find(name).should == e
- e.name.should == name
- e.dummy?.should be_true
+ e.name.should == name
+ e.dummy?.should be_true
+ end
+
+ # NOTE: it's unclear of the value of this (for the complexity cost of it),
+ # but it is the current CRuby behavior.
+ it "can be associated with a String" do
+ name = @prefix + '-US-ASCII'
+ e = suppress_warning { Encoding::US_ASCII.replicate(name) }
+ e.name.should == name
+ Encoding.find(name).should == e
+
+ s = "abc".dup.force_encoding(e)
+ s.encoding.should == e
+ s.encoding.name.should == name
+ end
end
- # NOTE: it's unclear of the value of this (for the complexity cost of it),
- # but it is the current CRuby behavior.
- it "can be associated with a String" do
- name = @prefix + '-US-ASCII'
- e = Encoding::US_ASCII.replicate(name)
- e.name.should == name
- Encoding.find(name).should == e
+ ruby_version_is "3.2"..."3.3" do
+ it "warns about deprecation" do
+ -> {
+ Encoding::US_ASCII.replicate('MY-US-ASCII')
+ }.should complain(/warning: Encoding#replicate is deprecated and will be removed in Ruby 3.3; use the original encoding instead/)
+ end
+
+ it "raises EncodingError if too many encodings" do
+ code = '1_000.times {|i| Encoding::US_ASCII.replicate("R_#{i}") }'
+ ruby_exe(code, args: "2>&1", exit_status: 1).should.include?('too many encoding (> 256) (EncodingError)')
+ end
+ end
- s = "abc".force_encoding(e)
- s.encoding.should == e
- s.encoding.name.should == name
+ ruby_version_is "3.3" do
+ it "has been removed" do
+ Encoding::US_ASCII.should_not.respond_to?(:replicate, true)
+ end
end
end
diff --git a/spec/ruby/core/encoding/to_s_spec.rb b/spec/ruby/core/encoding/to_s_spec.rb
index 82d282386b..bab394a888 100644
--- a/spec/ruby/core/encoding/to_s_spec.rb
+++ b/spec/ruby/core/encoding/to_s_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../spec_helper"
require_relative 'shared/name'
describe "Encoding#to_s" do
diff --git a/spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_name_spec.rb b/spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_name_spec.rb
index 106fc7ecac..a51a9f46a0 100644
--- a/spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_name_spec.rb
+++ b/spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_name_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
require_relative '../fixtures/classes'
describe "Encoding::UndefinedConversionError#destination_encoding_name" do
diff --git a/spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_spec.rb b/spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_spec.rb
index c6e24732fd..905556407c 100644
--- a/spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_spec.rb
+++ b/spec/ruby/core/encoding/undefined_conversion_error/destination_encoding_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
require_relative '../fixtures/classes'
describe "Encoding::UndefinedConversionError#destination_encoding" do
diff --git a/spec/ruby/core/encoding/undefined_conversion_error/error_char_spec.rb b/spec/ruby/core/encoding/undefined_conversion_error/error_char_spec.rb
index 780d81c1ee..9cb55e6d95 100644
--- a/spec/ruby/core/encoding/undefined_conversion_error/error_char_spec.rb
+++ b/spec/ruby/core/encoding/undefined_conversion_error/error_char_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
require_relative '../fixtures/classes'
describe "Encoding::UndefinedConversionError#error_char" do
diff --git a/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_name_spec.rb b/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_name_spec.rb
index 3b697cb82f..d5e60e78db 100644
--- a/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_name_spec.rb
+++ b/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_name_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
require_relative '../fixtures/classes'
describe "Encoding::UndefinedConversionError#source_encoding_name" do
diff --git a/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_spec.rb b/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_spec.rb
index 9101d51e11..de456a4b5a 100644
--- a/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_spec.rb
+++ b/spec/ruby/core/encoding/undefined_conversion_error/source_encoding_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
require_relative '../fixtures/classes'
describe "Encoding::UndefinedConversionError#source_encoding" do
diff --git a/spec/ruby/core/enumerable/all_spec.rb b/spec/ruby/core/enumerable/all_spec.rb
index b782f94a3e..160cd52628 100644
--- a/spec/ruby/core/enumerable/all_spec.rb
+++ b/spec/ruby/core/enumerable/all_spec.rb
@@ -131,7 +131,6 @@ describe "Enumerable#all?" do
pattern.yielded.should == [[0], [1], [2], [-1]]
end
- # may raise an exception in future versions
it "always returns true on empty enumeration" do
@empty.all?(Integer).should == true
[].all?(Integer).should == true
@@ -178,5 +177,11 @@ describe "Enumerable#all?" do
multi.all?(pattern).should == true
pattern.yielded.should == [[[1, 2]], [[3, 4, 5]], [[6, 7, 8, 9]]]
end
+
+ it "ignores the block if there is an argument" do
+ -> {
+ EnumerableSpecs::Numerous.new(1, 2, 3, 4, 5).all?(String) { true }.should == false
+ }.should complain(/given block not used/)
+ end
end
end
diff --git a/spec/ruby/core/enumerable/any_spec.rb b/spec/ruby/core/enumerable/any_spec.rb
index 636b1fa450..243f8735d5 100644
--- a/spec/ruby/core/enumerable/any_spec.rb
+++ b/spec/ruby/core/enumerable/any_spec.rb
@@ -145,7 +145,6 @@ describe "Enumerable#any?" do
pattern.yielded.should == [[0], [1], [2]]
end
- # may raise an exception in future versions
it "always returns false on empty enumeration" do
@empty.any?(Integer).should == false
[].any?(Integer).should == false
@@ -191,5 +190,11 @@ describe "Enumerable#any?" do
multi.any?(pattern).should == false
pattern.yielded.should == [[[1, 2]], [[3, 4, 5]], [[6, 7, 8, 9]]]
end
+
+ it "ignores the block if there is an argument" do
+ -> {
+ EnumerableSpecs::Numerous.new(1, 2, 3, 4, 5).any?(String) { true }.should == false
+ }.should complain(/given block not used/)
+ end
end
end
diff --git a/spec/ruby/core/enumerable/chunk_spec.rb b/spec/ruby/core/enumerable/chunk_spec.rb
index c5579d67fa..ed6304307f 100644
--- a/spec/ruby/core/enumerable/chunk_spec.rb
+++ b/spec/ruby/core/enumerable/chunk_spec.rb
@@ -29,6 +29,11 @@ describe "Enumerable#chunk" do
result.should == [[1, [1, 2]], [0, [3]], [1, [2]], [0, [3]], [1, [2, 1]]]
end
+ it "returns a partitioned Array of values" do
+ e = EnumerableSpecs::Numerous.new(1,2,3)
+ e.chunk { |x| x > 2 }.map(&:last).should == [[1, 2], [3]]
+ end
+
it "returns elements for which the block returns :_alone in separate Arrays" do
e = EnumerableSpecs::Numerous.new(1, 2, 3, 2, 1)
result = e.chunk { |x| x < 2 && :_alone }.to_a
diff --git a/spec/ruby/core/enumerable/compact_spec.rb b/spec/ruby/core/enumerable/compact_spec.rb
new file mode 100644
index 0000000000..86e95dce08
--- /dev/null
+++ b/spec/ruby/core/enumerable/compact_spec.rb
@@ -0,0 +1,11 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+
+ruby_version_is '3.1' do
+ describe "Enumerable#compact" do
+ it 'returns array without nil elements' do
+ arr = EnumerableSpecs::Numerous.new(nil, 1, 2, nil, true)
+ arr.compact.should == [1, 2, true]
+ end
+ end
+end
diff --git a/spec/ruby/core/enumerable/each_cons_spec.rb b/spec/ruby/core/enumerable/each_cons_spec.rb
index ba658203a2..8fb31fb925 100644
--- a/spec/ruby/core/enumerable/each_cons_spec.rb
+++ b/spec/ruby/core/enumerable/each_cons_spec.rb
@@ -56,6 +56,12 @@ describe "Enumerable#each_cons" do
multi.each_cons(2).to_a.should == [[[1, 2], [3, 4, 5]], [[3, 4, 5], [6, 7, 8, 9]]]
end
+ ruby_version_is "3.1" do
+ it "returns self when a block is given" do
+ @enum.each_cons(3){}.should == @enum
+ end
+ end
+
describe "when no block is given" do
it "returns an enumerator" do
e = @enum.each_cons(3)
diff --git a/spec/ruby/core/enumerable/each_slice_spec.rb b/spec/ruby/core/enumerable/each_slice_spec.rb
index 2ea89f5e72..a57a1dba81 100644
--- a/spec/ruby/core/enumerable/each_slice_spec.rb
+++ b/spec/ruby/core/enumerable/each_slice_spec.rb
@@ -57,6 +57,12 @@ describe "Enumerable#each_slice" do
e.to_a.should == @sliced
end
+ ruby_version_is "3.1" do
+ it "returns self when a block is given" do
+ @enum.each_slice(3){}.should == @enum
+ end
+ end
+
it "gathers whole arrays as elements when each yields multiple" do
multi = EnumerableSpecs::YieldsMulti.new
multi.each_slice(2).to_a.should == [[[1, 2], [3, 4, 5]], [[6, 7, 8, 9]]]
diff --git a/spec/ruby/core/enumerable/filter_map_spec.rb b/spec/ruby/core/enumerable/filter_map_spec.rb
index 31acc277b4..aa4894230b 100644
--- a/spec/ruby/core/enumerable/filter_map_spec.rb
+++ b/spec/ruby/core/enumerable/filter_map_spec.rb
@@ -1,26 +1,24 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-ruby_version_is '2.7' do
- describe 'Enumerable#filter_map' do
- before :each do
- @numerous = EnumerableSpecs::Numerous.new(*(1..8).to_a)
- end
+describe 'Enumerable#filter_map' do
+ before :each do
+ @numerous = EnumerableSpecs::Numerous.new(*(1..8).to_a)
+ end
- it 'returns an empty array if there are no elements' do
- EnumerableSpecs::Empty.new.filter_map { true }.should == []
- end
+ it 'returns an empty array if there are no elements' do
+ EnumerableSpecs::Empty.new.filter_map { true }.should == []
+ end
- it 'returns an array with truthy results of passing each element to block' do
- @numerous.filter_map { |i| i * 2 if i.even? }.should == [4, 8, 12, 16]
- @numerous.filter_map { |i| i * 2 }.should == [2, 4, 6, 8, 10, 12, 14, 16]
- @numerous.filter_map { 0 }.should == [0, 0, 0, 0, 0, 0, 0, 0]
- @numerous.filter_map { false }.should == []
- @numerous.filter_map { nil }.should == []
- end
+ it 'returns an array with truthy results of passing each element to block' do
+ @numerous.filter_map { |i| i * 2 if i.even? }.should == [4, 8, 12, 16]
+ @numerous.filter_map { |i| i * 2 }.should == [2, 4, 6, 8, 10, 12, 14, 16]
+ @numerous.filter_map { 0 }.should == [0, 0, 0, 0, 0, 0, 0, 0]
+ @numerous.filter_map { false }.should == []
+ @numerous.filter_map { nil }.should == []
+ end
- it 'returns an enumerator when no block given' do
- @numerous.filter_map.should be_an_instance_of(Enumerator)
- end
+ it 'returns an enumerator when no block given' do
+ @numerous.filter_map.should be_an_instance_of(Enumerator)
end
end
diff --git a/spec/ruby/core/enumerable/fixtures/classes.rb b/spec/ruby/core/enumerable/fixtures/classes.rb
index fb4951c6e6..2701c6999c 100644
--- a/spec/ruby/core/enumerable/fixtures/classes.rb
+++ b/spec/ruby/core/enumerable/fixtures/classes.rb
@@ -342,4 +342,10 @@ module EnumerableSpecs
@block.call(*args)
end
end
+
+ # Set is a core class since Ruby 3.2
+ ruby_version_is '3.2' do
+ class SetSubclass < Set
+ end
+ end
end # EnumerableSpecs utility classes
diff --git a/spec/ruby/core/enumerable/grep_spec.rb b/spec/ruby/core/enumerable/grep_spec.rb
index b81075291f..989358f01b 100644
--- a/spec/ruby/core/enumerable/grep_spec.rb
+++ b/spec/ruby/core/enumerable/grep_spec.rb
@@ -40,43 +40,28 @@ describe "Enumerable#grep" do
$~.should == nil
end
- ruby_version_is ""..."3.0.0" do
- it "sets $~ to the last match when given no block" do
- "z" =~ /z/ # Reset $~
- ["abc", "def"].grep(/b/).should == ["abc"]
-
- # Set by the failed match of "def"
- $~.should == nil
-
- ["abc", "def"].grep(/e/)
- $&.should == "e"
- end
+ it "does not set $~ when given no block" do
+ "z" =~ /z/ # Reset $~
+ ["abc", "def"].grep(/b/).should == ["abc"]
+ $&.should == "z"
end
- ruby_version_is "3.0.0" do
- it "does not set $~ when given no block" do
- "z" =~ /z/ # Reset $~
- ["abc", "def"].grep(/b/).should == ["abc"]
- $&.should == "z"
- end
-
- it "does not modify Regexp.last_match without block" do
- "z" =~ /z/ # Reset last match
- ["abc", "def"].grep(/b/).should == ["abc"]
- Regexp.last_match[0].should == "z"
- end
+ it "does not modify Regexp.last_match without block" do
+ "z" =~ /z/ # Reset last match
+ ["abc", "def"].grep(/b/).should == ["abc"]
+ Regexp.last_match[0].should == "z"
+ end
- it "correctly handles non-string elements" do
- 'set last match' =~ /set last (.*)/
- [:a, 'b', 'z', :c, 42, nil].grep(/[a-d]/).should == [:a, 'b', :c]
- $1.should == 'match'
+ it "correctly handles non-string elements" do
+ 'set last match' =~ /set last (.*)/
+ [:a, 'b', 'z', :c, 42, nil].grep(/[a-d]/).should == [:a, 'b', :c]
+ $1.should == 'match'
- o = Object.new
- def o.to_str
- 'hello'
- end
- [o].grep(/ll/).first.should.equal?(o)
+ o = Object.new
+ def o.to_str
+ 'hello'
end
+ [o].grep(/ll/).first.should.equal?(o)
end
describe "with a block" do
diff --git a/spec/ruby/core/enumerable/grep_v_spec.rb b/spec/ruby/core/enumerable/grep_v_spec.rb
index 35fde27eb6..ba19216968 100644
--- a/spec/ruby/core/enumerable/grep_v_spec.rb
+++ b/spec/ruby/core/enumerable/grep_v_spec.rb
@@ -20,43 +20,28 @@ describe "Enumerable#grep_v" do
$&.should == "e"
end
- ruby_version_is ""..."3.0.0" do
- it "sets $~ to the last match when given no block" do
- "z" =~ /z/ # Reset $~
- ["abc", "def"].grep_v(/e/).should == ["abc"]
-
- # Set by the match of "def"
- $&.should == "e"
-
- ["abc", "def"].grep_v(/b/)
- $&.should == nil
- end
+ it "does not set $~ when given no block" do
+ "z" =~ /z/ # Reset $~
+ ["abc", "def"].grep_v(/e/).should == ["abc"]
+ $&.should == "z"
end
- ruby_version_is "3.0.0" do
- it "does not set $~ when given no block" do
- "z" =~ /z/ # Reset $~
- ["abc", "def"].grep_v(/e/).should == ["abc"]
- $&.should == "z"
- end
-
- it "does not modify Regexp.last_match without block" do
- "z" =~ /z/ # Reset last match
- ["abc", "def"].grep_v(/e/).should == ["abc"]
- Regexp.last_match[0].should == "z"
- end
+ it "does not modify Regexp.last_match without block" do
+ "z" =~ /z/ # Reset last match
+ ["abc", "def"].grep_v(/e/).should == ["abc"]
+ Regexp.last_match[0].should == "z"
+ end
- it "correctly handles non-string elements" do
- 'set last match' =~ /set last (.*)/
- [:a, 'b', 'z', :c, 42, nil].grep_v(/[a-d]/).should == ['z', 42, nil]
- $1.should == 'match'
+ it "correctly handles non-string elements" do
+ 'set last match' =~ /set last (.*)/
+ [:a, 'b', 'z', :c, 42, nil].grep_v(/[a-d]/).should == ['z', 42, nil]
+ $1.should == 'match'
- o = Object.new
- def o.to_str
- 'hello'
- end
- [o].grep_v(/mm/).first.should.equal?(o)
+ o = Object.new
+ def o.to_str
+ 'hello'
end
+ [o].grep_v(/mm/).first.should.equal?(o)
end
describe "without block" do
diff --git a/spec/ruby/core/enumerable/group_by_spec.rb b/spec/ruby/core/enumerable/group_by_spec.rb
index 52b5a68d64..4fd1603819 100644
--- a/spec/ruby/core/enumerable/group_by_spec.rb
+++ b/spec/ruby/core/enumerable/group_by_spec.rb
@@ -33,15 +33,5 @@ describe "Enumerable#group_by" do
[3, 4, 5] => [[3, 4, 5]] }
end
- ruby_version_is ''...'2.7' do
- it "returns a tainted hash if self is tainted" do
- EnumerableSpecs::Empty.new.taint.group_by {}.tainted?.should be_true
- end
-
- it "returns an untrusted hash if self is untrusted" do
- EnumerableSpecs::Empty.new.untrust.group_by {}.untrusted?.should be_true
- end
- end
-
it_behaves_like :enumerable_enumeratorized_with_origin_size, :group_by
end
diff --git a/spec/ruby/core/enumerable/none_spec.rb b/spec/ruby/core/enumerable/none_spec.rb
index b898d00063..fb42f13386 100644
--- a/spec/ruby/core/enumerable/none_spec.rb
+++ b/spec/ruby/core/enumerable/none_spec.rb
@@ -100,7 +100,6 @@ describe "Enumerable#none?" do
pattern.yielded.should == [[0], [1], [2], [-1]]
end
- # may raise an exception in future versions
it "always returns true on empty enumeration" do
@empty.none?(Integer).should == true
[].none?(Integer).should == true
@@ -144,5 +143,11 @@ describe "Enumerable#none?" do
multi.none?(pattern).should == true
pattern.yielded.should == [[[1, 2]], [[3, 4, 5]], [[6, 7, 8, 9]]]
end
+
+ it "ignores the block if there is an argument" do
+ -> {
+ EnumerableSpecs::Numerous.new(1, 2, 3, 4, 5).none?(String) { true }.should == true
+ }.should complain(/given block not used/)
+ end
end
end
diff --git a/spec/ruby/core/enumerable/one_spec.rb b/spec/ruby/core/enumerable/one_spec.rb
index d54dd4a527..4bf8623d2e 100644
--- a/spec/ruby/core/enumerable/one_spec.rb
+++ b/spec/ruby/core/enumerable/one_spec.rb
@@ -83,7 +83,6 @@ describe "Enumerable#one?" do
end
end
-
describe 'when given a pattern argument' do
it "calls `===` on the pattern the return value " do
pattern = EnumerableSpecs::Pattern.new { |x| x == 1 }
@@ -91,7 +90,6 @@ describe "Enumerable#one?" do
pattern.yielded.should == [[0], [1], [2], [-1]]
end
- # may raise an exception in future versions
it "always returns false on empty enumeration" do
@empty.one?(Integer).should == false
[].one?(Integer).should == false
@@ -146,5 +144,11 @@ describe "Enumerable#one?" do
multi.one?(pattern).should == false
pattern.yielded.should == [[[1, 2]], [[3, 4, 5]], [[6, 7, 8, 9]]]
end
+
+ it "ignores the block if there is an argument" do
+ -> {
+ EnumerableSpecs::Numerous.new(1, 2, 3, 4, "5").one?(String) { false }.should == true
+ }.should complain(/given block not used/)
+ end
end
end
diff --git a/spec/ruby/core/enumerable/shared/entries.rb b/spec/ruby/core/enumerable/shared/entries.rb
index 590ce73bcf..e32eb23d2a 100644
--- a/spec/ruby/core/enumerable/shared/entries.rb
+++ b/spec/ruby/core/enumerable/shared/entries.rb
@@ -13,14 +13,4 @@ describe :enumerable_entries, shared: true do
count.send(@method, :hello, "world").should == [1, 2, 3]
count.arguments_passed.should == [:hello, "world"]
end
-
- ruby_version_is ''...'2.7' do
- it "returns a tainted array if self is tainted" do
- EnumerableSpecs::Empty.new.taint.send(@method).tainted?.should be_true
- end
-
- it "returns an untrusted array if self is untrusted" do
- EnumerableSpecs::Empty.new.untrust.send(@method).untrusted?.should be_true
- end
- end
end
diff --git a/spec/ruby/core/enumerable/shared/inject.rb b/spec/ruby/core/enumerable/shared/inject.rb
index 12e0665dda..693d34d675 100644
--- a/spec/ruby/core/enumerable/shared/inject.rb
+++ b/spec/ruby/core/enumerable/shared/inject.rb
@@ -1,3 +1,5 @@
+require_relative '../../array/shared/iterable_and_tolerating_size_increasing'
+
describe :enumerable_inject, shared: true do
it "with argument takes a block with an accumulator (with argument as initial value) and the current element. Value of block becomes new accumulator" do
a = []
@@ -17,7 +19,22 @@ describe :enumerable_inject, shared: true do
end
it "ignores the block if two arguments" do
- EnumerableSpecs::Numerous.new(1, 2, 3).send(@method, 10, :-){ raise "we never get here"}.should == 4
+ -> {
+ EnumerableSpecs::Numerous.new(1, 2, 3).send(@method, 10, :-) { raise "we never get here"}.should == 4
+ }.should complain(/#{__FILE__}:#{__LINE__-1}: warning: given block not used/, verbose: true)
+
+ -> {
+ [1, 2, 3].send(@method, 10, :-) { raise "we never get here"}.should == 4
+ }.should complain(/#{__FILE__}:#{__LINE__-1}: warning: given block not used/, verbose: true)
+ end
+
+ it "does not warn when given a Symbol with $VERBOSE true" do
+ -> {
+ [1, 2].send(@method, 0, :+)
+ [1, 2].send(@method, :+)
+ EnumerableSpecs::Numerous.new(1, 2).send(@method, 0, :+)
+ EnumerableSpecs::Numerous.new(1, 2).send(@method, :+)
+ }.should_not complain(verbose: true)
end
it "can take a symbol argument" do
@@ -30,10 +47,10 @@ describe :enumerable_inject, shared: true do
a.should == [[2, 5], [5, 3], [3, 6], [6, 1], [1, 4]]
end
- it "gathers whole arrays as elements when each yields multiple" do
- multi = EnumerableSpecs::YieldsMulti.new
- multi.send(@method, []) {|acc, e| acc << e }.should == [[1, 2], [3, 4, 5], [6, 7, 8, 9]]
- end
+ it "gathers whole arrays as elements when each yields multiple" do
+ multi = EnumerableSpecs::YieldsMulti.new
+ multi.send(@method, []) {|acc, e| acc << e }.should == [[1, 2], [3, 4, 5], [6, 7, 8, 9]]
+ end
it "with inject arguments(legacy rubycon)" do
# with inject argument
@@ -66,4 +83,27 @@ describe :enumerable_inject, shared: true do
it "returns nil when fails(legacy rubycon)" do
EnumerableSpecs::EachDefiner.new().send(@method) {|acc,x| 999 }.should == nil
end
+
+ it "tolerates increasing a collection size during iterating Array" do
+ array = [:a, :b, :c]
+ ScratchPad.record []
+ i = 0
+
+ array.send(@method, nil) do |_, e|
+ ScratchPad << e
+ array << i if i < 100
+ i += 1
+ end
+
+ actual = ScratchPad.recorded
+ expected = [:a, :b, :c] + (0..99).to_a
+ actual.sort_by(&:to_s).should == expected.sort_by(&:to_s)
+ end
+
+ ruby_bug '#18635', ''...'3.2' do
+ it "raises an ArgumentError when no parameters or block is given" do
+ -> { [1,2].send(@method) }.should raise_error(ArgumentError)
+ -> { {one: 1, two: 2}.send(@method) }.should raise_error(ArgumentError)
+ end
+ end
end
diff --git a/spec/ruby/core/enumerable/sum_spec.rb b/spec/ruby/core/enumerable/sum_spec.rb
index 4a978794e5..2eb74db6ac 100644
--- a/spec/ruby/core/enumerable/sum_spec.rb
+++ b/spec/ruby/core/enumerable/sum_spec.rb
@@ -22,12 +22,25 @@ describe 'Enumerable#sum' do
@enum.sum.should == 5/3r
end
- it 'takes a block to transform the elements' do
- @enum.sum { |element| element * 2 }.should == 10/3r
+ context 'with a block' do
+ it 'transforms the elements' do
+ @enum.sum { |element| element * 2 }.should == 10/3r
+ end
+
+ it 'does not destructure array elements' do
+ class << @enum
+ def each
+ yield [1,2]
+ yield [3]
+ end
+ end
+
+ @enum.sum(&:last).should == 5
+ end
end
# https://bugs.ruby-lang.org/issues/12217
- # https://github.com/ruby/ruby/blob/master/doc/ChangeLog-2.4.0#L6208-L6214
+ # https://github.com/ruby/ruby/blob/master/doc/ChangeLog/ChangeLog-2.4.0#L6208-L6214
it "uses Kahan's compensated summation algorithm for precise sum of float numbers" do
floats = [2.7800000000000002, 5.0, 2.5, 4.44, 3.89, 3.89, 4.44, 7.78, 5.0, 2.7800000000000002, 5.0, 2.5].to_enum
naive_sum = floats.reduce { |sum, e| sum + e }
diff --git a/spec/ruby/core/enumerable/tally_spec.rb b/spec/ruby/core/enumerable/tally_spec.rb
index 92aac507ff..e0edc8dc75 100644
--- a/spec/ruby/core/enumerable/tally_spec.rb
+++ b/spec/ruby/core/enumerable/tally_spec.rb
@@ -1,36 +1,34 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-ruby_version_is "2.7" do
- describe "Enumerable#tally" do
- before :each do
- ScratchPad.record []
- end
+describe "Enumerable#tally" do
+ before :each do
+ ScratchPad.record []
+ end
- it "returns a hash with counts according to the value" do
- enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
- enum.tally.should == { 'foo' => 2, 'bar' => 1, 'baz' => 1}
- end
+ it "returns a hash with counts according to the value" do
+ enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
+ enum.tally.should == { 'foo' => 2, 'bar' => 1, 'baz' => 1}
+ end
- it "returns a hash without default" do
- hash = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz').tally
- hash.default_proc.should be_nil
- hash.default.should be_nil
- end
+ it "returns a hash without default" do
+ hash = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz').tally
+ hash.default_proc.should be_nil
+ hash.default.should be_nil
+ end
- it "returns an empty hash for empty enumerables" do
- EnumerableSpecs::Empty.new.tally.should == {}
- end
+ it "returns an empty hash for empty enumerables" do
+ EnumerableSpecs::Empty.new.tally.should == {}
+ end
- it "counts values as gathered array when yielded with multiple arguments" do
- EnumerableSpecs::YieldsMixed2.new.tally.should == EnumerableSpecs::YieldsMixed2.gathered_yields.group_by(&:itself).transform_values(&:size)
- end
+ it "counts values as gathered array when yielded with multiple arguments" do
+ EnumerableSpecs::YieldsMixed2.new.tally.should == EnumerableSpecs::YieldsMixed2.gathered_yields.group_by(&:itself).transform_values(&:size)
+ end
- it "does not call given block" do
- enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
- enum.tally { |v| ScratchPad << v }
- ScratchPad.recorded.should == []
- end
+ it "does not call given block" do
+ enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
+ enum.tally { |v| ScratchPad << v }
+ ScratchPad.recorded.should == []
end
end
@@ -51,6 +49,13 @@ ruby_version_is "3.1" do
enum.tally(hash).should equal(hash)
end
+ it "calls #to_hash to convert argument to Hash implicitly if passed not a Hash" do
+ enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
+ object = Object.new
+ def object.to_hash; { 'foo' => 1 }; end
+ enum.tally(object).should == { 'foo' => 3, 'bar' => 1, 'baz' => 1}
+ end
+
it "raises a FrozenError and does not update the given hash when the hash is frozen" do
enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
hash = { 'foo' => 1 }.freeze
@@ -58,6 +63,12 @@ ruby_version_is "3.1" do
hash.should == { 'foo' => 1 }
end
+ it "raises a FrozenError even if enumerable is empty" do
+ enum = EnumerableSpecs::Numerous.new()
+ hash = { 'foo' => 1 }.freeze
+ -> { enum.tally(hash) }.should raise_error(FrozenError)
+ end
+
it "does not call given block" do
enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
enum.tally({ 'foo' => 1 }) { |v| ScratchPad << v }
diff --git a/spec/ruby/core/enumerable/to_set_spec.rb b/spec/ruby/core/enumerable/to_set_spec.rb
new file mode 100644
index 0000000000..c21a2772c4
--- /dev/null
+++ b/spec/ruby/core/enumerable/to_set_spec.rb
@@ -0,0 +1,29 @@
+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
+
+ it "passes down passed blocks" do
+ [1, 2, 3].to_set { |x| x * x }.should == Set[1, 4, 9]
+ end
+
+ 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
+
+ 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}>"
+ end
+ end
+end
diff --git a/spec/ruby/core/enumerable/uniq_spec.rb b/spec/ruby/core/enumerable/uniq_spec.rb
index e58dd36366..a1ed44796f 100644
--- a/spec/ruby/core/enumerable/uniq_spec.rb
+++ b/spec/ruby/core/enumerable/uniq_spec.rb
@@ -31,76 +31,32 @@ describe 'Enumerable#uniq' do
[x, y].to_enum.uniq.should == [x, y]
end
- ruby_version_is '2.7' do
- it "compares elements with matching hash codes with #eql?" do
- a = Array.new(2) do
- obj = mock('0')
- obj.should_receive(:hash).at_least(1).and_return(0)
-
- def obj.eql?(o)
- false
- end
-
- obj
- end
-
- a.uniq.should == a
+ it "compares elements with matching hash codes with #eql?" do
+ a = Array.new(2) do
+ obj = mock('0')
+ obj.should_receive(:hash).at_least(1).and_return(0)
- a = Array.new(2) do
- obj = mock('0')
- obj.should_receive(:hash).at_least(1).and_return(0)
-
- def obj.eql?(o)
- true
- end
-
- obj
+ def obj.eql?(o)
+ false
end
- a.to_enum.uniq.size.should == 1
+ obj
end
- end
- ruby_version_is ''...'2.7' do
- it "compares elements with matching hash codes with #eql?" do
- a = Array.new(2) do
- obj = mock('0')
- obj.should_receive(:hash).at_least(1).and_return(0)
-
- def obj.eql?(o)
- # It's undefined whether the impl does a[0].eql?(a[1]) or
- # a[1].eql?(a[0]) so we taint both.
- taint
- o.taint
- false
- end
-
- obj
- end
-
- a.uniq.should == a
- a[0].should.tainted?
- a[1].should.tainted?
+ a.uniq.should == a
- a = Array.new(2) do
- obj = mock('0')
- obj.should_receive(:hash).at_least(1).and_return(0)
+ a = Array.new(2) do
+ obj = mock('0')
+ obj.should_receive(:hash).at_least(1).and_return(0)
- def obj.eql?(o)
- # It's undefined whether the impl does a[0].eql?(a[1]) or
- # a[1].eql?(a[0]) so we taint both.
- taint
- o.taint
- true
- end
-
- obj
+ def obj.eql?(o)
+ true
end
- a.to_enum.uniq.size.should == 1
- a[0].should.tainted?
- a[1].should.tainted?
+ obj
end
+
+ a.to_enum.uniq.size.should == 1
end
context 'when yielded with multiple arguments' do
diff --git a/spec/ruby/core/enumerable/zip_spec.rb b/spec/ruby/core/enumerable/zip_spec.rb
index 9ec15aa030..ab148f2a6e 100644
--- a/spec/ruby/core/enumerable/zip_spec.rb
+++ b/spec/ruby/core/enumerable/zip_spec.rb
@@ -38,4 +38,9 @@ describe "Enumerable#zip" do
multi.zip(multi).should == [[[1, 2], [1, 2]], [[3, 4, 5], [3, 4, 5]], [[6, 7, 8, 9], [6, 7, 8, 9]]]
end
+ it "raises TypeError when some argument isn't Array and doesn't respond to #to_ary and #to_enum" do
+ -> { EnumerableSpecs::Numerous.new(1,2,3).zip(Object.new) }.should raise_error(TypeError, "wrong argument type Object (must respond to :each)")
+ -> { EnumerableSpecs::Numerous.new(1,2,3).zip(1) }.should raise_error(TypeError, "wrong argument type Integer (must respond to :each)")
+ -> { EnumerableSpecs::Numerous.new(1,2,3).zip(true) }.should raise_error(TypeError, "wrong argument type TrueClass (must respond to :each)")
+ end
end
diff --git a/spec/ruby/core/enumerator/arithmetic_sequence/begin_spec.rb b/spec/ruby/core/enumerator/arithmetic_sequence/begin_spec.rb
index 1837a4f246..bd243fa0b5 100644
--- a/spec/ruby/core/enumerator/arithmetic_sequence/begin_spec.rb
+++ b/spec/ruby/core/enumerator/arithmetic_sequence/begin_spec.rb
@@ -7,12 +7,10 @@ describe "Enumerator::ArithmeticSequence#begin" do
(1...10).step.begin.should == 1
end
- ruby_version_is "2.7" do
- context "with beginless" do
- it "returns nil as begin of the sequence" do
- eval("(..10).step(1)").begin.should == nil
- eval("(...10).step(1)").begin.should == nil
- end
+ context "with beginless" do
+ it "returns nil as begin of the sequence" do
+ (..10).step(1).begin.should == nil
+ (...10).step(1).begin.should == nil
end
end
end
diff --git a/spec/ruby/core/enumerator/chain/initialize_spec.rb b/spec/ruby/core/enumerator/chain/initialize_spec.rb
index 69484dfcb4..daa30351d7 100644
--- a/spec/ruby/core/enumerator/chain/initialize_spec.rb
+++ b/spec/ruby/core/enumerator/chain/initialize_spec.rb
@@ -22,10 +22,10 @@ describe "Enumerator::Chain#initialize" do
end
describe "on frozen instance" do
- it "raises a RuntimeError" do
+ it "raises a FrozenError" do
-> {
@uninitialized.freeze.send(:initialize)
- }.should raise_error(RuntimeError)
+ }.should raise_error(FrozenError)
end
end
end
diff --git a/spec/ruby/core/enumerator/chain/inspect_spec.rb b/spec/ruby/core/enumerator/chain/inspect_spec.rb
index a0450c808a..9b5a442b75 100644
--- a/spec/ruby/core/enumerator/chain/inspect_spec.rb
+++ b/spec/ruby/core/enumerator/chain/inspect_spec.rb
@@ -11,4 +11,8 @@ describe "Enumerator::Chain#inspect" do
obj.should_receive(:inspect).and_return('some desc')
Enumerator::Chain.new(obj).inspect.should == "#<Enumerator::Chain: [some desc]>"
end
+
+ it "returns a not initialized representation if #initialized is not called yet" do
+ Enumerator::Chain.allocate.inspect.should == "#<Enumerator::Chain: uninitialized>"
+ end
end
diff --git a/spec/ruby/core/enumerator/each_spec.rb b/spec/ruby/core/enumerator/each_spec.rb
index 99ac3120af..3af16e5587 100644
--- a/spec/ruby/core/enumerator/each_spec.rb
+++ b/spec/ruby/core/enumerator/each_spec.rb
@@ -10,41 +10,41 @@ describe "Enumerator#each" do
@enum_with_arguments = object_each_with_arguments.to_enum(:each_with_arguments, :arg0, :arg1, :arg2)
- @enum_with_yielder = Enumerator.new {|y| y.yield :ok}
+ @enum_with_yielder = Enumerator.new { |y| y.yield :ok }
end
it "yields each element of self to the given block" do
acc = []
- [1,2,3].to_enum.each {|e| acc << e }
- acc.should == [1,2,3]
+ [1, 2, 3].to_enum.each { |e| acc << e }
+ acc.should == [1, 2, 3]
end
it "calls #each on the object given in the constructor by default" do
each = mock('each')
each.should_receive(:each)
- each.to_enum.each {|e| e }
+ each.to_enum.each { |e| e }
end
it "calls #each on the underlying object until it's exhausted" do
each = mock('each')
each.should_receive(:each).and_yield(1).and_yield(2).and_yield(3)
acc = []
- each.to_enum.each {|e| acc << e }
- acc.should == [1,2,3]
+ each.to_enum.each { |e| acc << e }
+ acc.should == [1, 2, 3]
end
it "calls the method given in the constructor instead of #each" do
each = mock('peach')
each.should_receive(:peach)
- each.to_enum(:peach).each {|e| e }
+ each.to_enum(:peach).each { |e| e }
end
it "calls the method given in the constructor until it's exhausted" do
each = mock('peach')
each.should_receive(:peach).and_yield(1).and_yield(2).and_yield(3)
acc = []
- each.to_enum(:peach).each {|e| acc << e }
- acc.should == [1,2,3]
+ each.to_enum(:peach).each { |e| acc << e }
+ acc.should == [1, 2, 3]
end
it "raises a NoMethodError if the object doesn't respond to #each" do
diff --git a/spec/ruby/core/enumerator/generator/initialize_spec.rb b/spec/ruby/core/enumerator/generator/initialize_spec.rb
index f75c7d6f26..acc1174253 100644
--- a/spec/ruby/core/enumerator/generator/initialize_spec.rb
+++ b/spec/ruby/core/enumerator/generator/initialize_spec.rb
@@ -17,10 +17,10 @@ describe "Enumerator::Generator#initialize" do
end
describe "on frozen instance" do
- it "raises a RuntimeError" do
+ it "raises a FrozenError" do
-> {
@uninitialized.freeze.send(:initialize) {}
- }.should raise_error(RuntimeError)
+ }.should raise_error(FrozenError)
end
end
end
diff --git a/spec/ruby/core/enumerator/initialize_spec.rb b/spec/ruby/core/enumerator/initialize_spec.rb
index 217af1d3bc..5e0256ca46 100644
--- a/spec/ruby/core/enumerator/initialize_spec.rb
+++ b/spec/ruby/core/enumerator/initialize_spec.rb
@@ -11,14 +11,6 @@ describe "Enumerator#initialize" do
Enumerator.should have_private_instance_method(:initialize, false)
end
- ruby_version_is ''...'3.0' do
- it "returns self when given an object" do
- suppress_warning do
- @uninitialized.send(:initialize, Object.new).should equal(@uninitialized)
- end
- end
- end
-
it "returns self when given a block" do
@uninitialized.send(:initialize) {}.should equal(@uninitialized)
end
@@ -56,10 +48,10 @@ describe "Enumerator#initialize" do
end
describe "on frozen instance" do
- it "raises a RuntimeError" do
+ it "raises a FrozenError" do
-> {
@uninitialized.freeze.send(:initialize) {}
- }.should raise_error(RuntimeError)
+ }.should raise_error(FrozenError)
end
end
end
diff --git a/spec/ruby/core/enumerator/inspect_spec.rb b/spec/ruby/core/enumerator/inspect_spec.rb
index 3bcf07e754..7e97864246 100644
--- a/spec/ruby/core/enumerator/inspect_spec.rb
+++ b/spec/ruby/core/enumerator/inspect_spec.rb
@@ -14,4 +14,9 @@ describe "Enumerator#inspect" do
(1..3).each.each_slice(2).inspect.should == "#<Enumerator: #<Enumerator: 1..3:each>:each_slice(2)>"
end
end
+
+ it "returns a not initialized representation if #initialized is not called yet" do
+ Enumerator.allocate.inspect.should == "#<Enumerator: uninitialized>"
+ Enumerator::Lazy.allocate.inspect.should == "#<Enumerator::Lazy: uninitialized>"
+ end
end
diff --git a/spec/ruby/core/enumerator/lazy/compact_spec.rb b/spec/ruby/core/enumerator/lazy/compact_spec.rb
new file mode 100644
index 0000000000..e678bc71eb
--- /dev/null
+++ b/spec/ruby/core/enumerator/lazy/compact_spec.rb
@@ -0,0 +1,16 @@
+require_relative '../../../spec_helper'
+require_relative 'fixtures/classes'
+
+ruby_version_is '3.1' do
+ describe "Enumerator::Lazy#compact" do
+ it 'returns array without nil elements' do
+ arr = [1, nil, 3, false, 5].to_enum.lazy.compact
+ arr.should be_an_instance_of(Enumerator::Lazy)
+ arr.force.should == [1, 3, false, 5]
+ end
+
+ it "sets #size to nil" do
+ Enumerator::Lazy.new(Object.new, 100) {}.compact.size.should == nil
+ end
+ end
+end
diff --git a/spec/ruby/core/enumerator/lazy/eager_spec.rb b/spec/ruby/core/enumerator/lazy/eager_spec.rb
index 30ba2dfe0e..592da4fd8c 100644
--- a/spec/ruby/core/enumerator/lazy/eager_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/eager_spec.rb
@@ -1,29 +1,27 @@
require_relative '../../../spec_helper'
-ruby_version_is "2.7" do
- describe "Enumerator::Lazy#eager" do
- it "returns a non-lazy Enumerator converted from the lazy enumerator" do
- enum = [1, 2, 3].lazy
+describe "Enumerator::Lazy#eager" do
+ it "returns a non-lazy Enumerator converted from the lazy enumerator" do
+ enum = [1, 2, 3].lazy
- enum.class.should == Enumerator::Lazy
- enum.eager.class.should == Enumerator
- end
+ enum.class.should == Enumerator::Lazy
+ enum.eager.class.should == Enumerator
+ end
- it "does not enumerate an enumerator" do
- ScratchPad.record []
+ it "does not enumerate an enumerator" do
+ ScratchPad.record []
- sequence = [1, 2, 3]
- enum_lazy = Enumerator::Lazy.new(sequence) do |yielder, value|
- yielder << value
- ScratchPad << value
- end
+ sequence = [1, 2, 3]
+ enum_lazy = Enumerator::Lazy.new(sequence) do |yielder, value|
+ yielder << value
+ ScratchPad << value
+ end
- ScratchPad.recorded.should == []
- enum = enum_lazy.eager
- ScratchPad.recorded.should == []
+ ScratchPad.recorded.should == []
+ enum = enum_lazy.eager
+ ScratchPad.recorded.should == []
- enum.map { |i| i }.should == [1, 2, 3]
- ScratchPad.recorded.should == [1, 2, 3]
- end
+ enum.map { |i| i }.should == [1, 2, 3]
+ ScratchPad.recorded.should == [1, 2, 3]
end
end
diff --git a/spec/ruby/core/enumerator/lazy/filter_map_spec.rb b/spec/ruby/core/enumerator/lazy/filter_map_spec.rb
index 3480af0865..99dd59cebe 100644
--- a/spec/ruby/core/enumerator/lazy/filter_map_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/filter_map_spec.rb
@@ -3,14 +3,12 @@
require_relative '../../../spec_helper'
require_relative 'fixtures/classes'
-ruby_version_is "2.7" do
- describe "Enumerator::Lazy#filter_map" do
- it "maps only truthy results" do
- (1..Float::INFINITY).lazy.filter_map { |i| i if i.odd? }.first(4).should == [1, 3, 5, 7]
- end
+describe "Enumerator::Lazy#filter_map" do
+ it "maps only truthy results" do
+ (1..Float::INFINITY).lazy.filter_map { |i| i if i.odd? }.first(4).should == [1, 3, 5, 7]
+ end
- it "does not map false results" do
- (1..Float::INFINITY).lazy.filter_map { |i| i.odd? ? i : false }.first(4).should == [1, 3, 5, 7]
- end
+ it "does not map false results" do
+ (1..Float::INFINITY).lazy.filter_map { |i| i.odd? ? i : false }.first(4).should == [1, 3, 5, 7]
end
end
diff --git a/spec/ruby/core/enumerator/lazy/initialize_spec.rb b/spec/ruby/core/enumerator/lazy/initialize_spec.rb
index f23018d010..e1e0b1d608 100644
--- a/spec/ruby/core/enumerator/lazy/initialize_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/initialize_spec.rb
@@ -56,8 +56,8 @@ describe "Enumerator::Lazy#initialize" do
end
describe "on frozen instance" do
- it "raises a RuntimeError" do
- -> { @uninitialized.freeze.send(:initialize, @receiver) {} }.should raise_error(RuntimeError)
+ it "raises a FrozenError" do
+ -> { @uninitialized.freeze.send(:initialize, @receiver) {} }.should raise_error(FrozenError)
end
end
end
diff --git a/spec/ruby/core/enumerator/lazy/lazy_spec.rb b/spec/ruby/core/enumerator/lazy/lazy_spec.rb
index cde9b31066..0fb104e25a 100644
--- a/spec/ruby/core/enumerator/lazy/lazy_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/lazy_spec.rb
@@ -16,6 +16,10 @@ describe "Enumerator::Lazy" do
]
lazy_methods += [:chunk_while, :uniq]
+ ruby_version_is '3.1' do
+ lazy_methods += [:compact]
+ end
+
Enumerator::Lazy.instance_methods(false).should include(*lazy_methods)
end
end
diff --git a/spec/ruby/core/enumerator/lazy/with_index_spec.rb b/spec/ruby/core/enumerator/lazy/with_index_spec.rb
index 3a59ba4116..a6b5c38777 100644
--- a/spec/ruby/core/enumerator/lazy/with_index_spec.rb
+++ b/spec/ruby/core/enumerator/lazy/with_index_spec.rb
@@ -3,28 +3,34 @@
require_relative '../../../spec_helper'
require_relative 'fixtures/classes'
-ruby_version_is "2.7" do
- describe "Enumerator::Lazy#with_index" do
- it "enumerates with an index" do
- (0..Float::INFINITY).lazy.with_index.map { |i, idx| [i, idx] }.first(3).should == [[0, 0], [1, 1], [2, 2]]
- end
+describe "Enumerator::Lazy#with_index" do
+ it "enumerates with an index" do
+ (0..Float::INFINITY).lazy.with_index.map { |i, idx| [i, idx] }.first(3).should == [[0, 0], [1, 1], [2, 2]]
+ end
+
+ it "enumerates with an index starting at a given offset" do
+ (0..Float::INFINITY).lazy.with_index(3).map { |i, idx| [i, idx] }.first(3).should == [[0, 3], [1, 4], [2, 5]]
+ end
- it "enumerates with an index starting at a given offset" do
- (0..Float::INFINITY).lazy.with_index(3).map { |i, idx| [i, idx] }.first(3).should == [[0, 3], [1, 4], [2, 5]]
- end
+ it "enumerates with an index starting at 0 when offset is nil" do
+ (0..Float::INFINITY).lazy.with_index(nil).map { |i, idx| [i, idx] }.first(3).should == [[0, 0], [1, 1], [2, 2]]
+ end
- it "enumerates with an index starting at 0 when offset is nil" do
- (0..Float::INFINITY).lazy.with_index(nil).map { |i, idx| [i, idx] }.first(3).should == [[0, 0], [1, 1], [2, 2]]
- end
+ it "raises TypeError when offset does not convert to Integer" do
+ -> { (0..Float::INFINITY).lazy.with_index(false).map { |i, idx| i }.first(3) }.should raise_error(TypeError)
+ end
- it "raises TypeError when offset does not convert to Integer" do
- -> { (0..Float::INFINITY).lazy.with_index(false).map { |i, idx| i }.first(3) }.should raise_error(TypeError)
- end
+ it "enumerates with a given block" do
+ result = []
+ (0..Float::INFINITY).lazy.with_index { |i, idx| result << [i * 2, idx] }.first(3)
+ result.should == [[0,0],[2,1],[4,2]]
+ end
- it "enumerates with a given block" do
- result = []
- (0..Float::INFINITY).lazy.with_index { |i, idx| result << [i * 2, idx] }.first(3)
- result.should == [[0,0],[2,1],[4,2]]
- end
+ it "resets after a new call to each" do
+ enum = (0..2).lazy.with_index.map { |i, idx| [i, idx] }
+ result = []
+ enum.each { |i, idx| result << [i, idx] }
+ enum.each { |i, idx| result << [i, idx] }
+ result.should == [[0,0], [1,1], [2,2], [0,0], [1,1], [2,2]]
end
end
diff --git a/spec/ruby/core/enumerator/new_spec.rb b/spec/ruby/core/enumerator/new_spec.rb
index 5cc0b3ff2e..671912224f 100644
--- a/spec/ruby/core/enumerator/new_spec.rb
+++ b/spec/ruby/core/enumerator/new_spec.rb
@@ -2,51 +2,8 @@ require_relative '../../spec_helper'
describe "Enumerator.new" do
context "no block given" do
- ruby_version_is '3.0' do
- it "raises" do
- -> { Enumerator.new(1, :upto, 3) }.should raise_error(ArgumentError)
- end
- end
-
- ruby_version_is ''...'3.0' do
- it "creates a new custom enumerator with the given object, iterator and arguments" do
- enum = suppress_warning { Enumerator.new(1, :upto, 3) }
- enum.should be_an_instance_of(Enumerator)
- end
-
- it "creates a new custom enumerator that responds to #each" do
- enum = suppress_warning { Enumerator.new(1, :upto, 3) }
- enum.respond_to?(:each).should == true
- end
-
- it "creates a new custom enumerator that runs correctly" do
- suppress_warning { Enumerator.new(1, :upto, 3) }.map{ |x| x }.should == [1,2,3]
- end
-
- it "aliases the second argument to :each" do
- suppress_warning { Enumerator.new(1..2) }.to_a.should ==
- suppress_warning { Enumerator.new(1..2, :each) }.to_a
- end
-
- it "doesn't check for the presence of the iterator method" do
- suppress_warning { Enumerator.new(nil) }.should be_an_instance_of(Enumerator)
- end
-
- it "uses the latest define iterator method" do
- class StrangeEach
- def each
- yield :foo
- end
- end
- enum = suppress_warning { Enumerator.new(StrangeEach.new) }
- enum.to_a.should == [:foo]
- class StrangeEach
- def each
- yield :bar
- end
- end
- enum.to_a.should == [:bar]
- end
+ it "raises" do
+ -> { Enumerator.new(1, :upto, 3) }.should raise_error(ArgumentError)
end
end
@@ -77,14 +34,12 @@ describe "Enumerator.new" do
enum.take(3).should == [1, 2, 3]
end
- ruby_version_is "2.7" do
- it "defines iteration with block, yielder argument and treating it as a proc" do
- enum = Enumerator.new do |yielder|
- "a\nb\nc".each_line(&yielder)
- end
-
- enum.to_a.should == ["a\n", "b\n", "c"]
+ it "defines iteration with block, yielder argument and treating it as a proc" do
+ enum = Enumerator.new do |yielder|
+ "a\nb\nc".each_line(&yielder)
end
+
+ enum.to_a.should == ["a\n", "b\n", "c"]
end
describe 'yielded values' do
diff --git a/spec/ruby/core/enumerator/produce_spec.rb b/spec/ruby/core/enumerator/produce_spec.rb
index f6f1dcd429..c69fb49303 100644
--- a/spec/ruby/core/enumerator/produce_spec.rb
+++ b/spec/ruby/core/enumerator/produce_spec.rb
@@ -1,36 +1,34 @@
require_relative '../../spec_helper'
-ruby_version_is "2.7" do
- describe "Enumerator.produce" do
- it "creates an infinite enumerator" do
- enum = Enumerator.produce(0) { |prev| prev + 1 }
- enum.take(5).should == [0, 1, 2, 3, 4]
- end
-
- it "terminates iteration when block raises StopIteration exception" do
- enum = Enumerator.produce(0) do | prev|
- raise StopIteration if prev >= 2
- prev + 1
- end
+describe "Enumerator.produce" do
+ it "creates an infinite enumerator" do
+ enum = Enumerator.produce(0) { |prev| prev + 1 }
+ enum.take(5).should == [0, 1, 2, 3, 4]
+ end
- enum.to_a.should == [0, 1, 2]
+ it "terminates iteration when block raises StopIteration exception" do
+ enum = Enumerator.produce(0) do | prev|
+ raise StopIteration if prev >= 2
+ prev + 1
end
- context "when initial value skipped" do
- it "uses nil instead" do
- ScratchPad.record []
- enum = Enumerator.produce { |prev| ScratchPad << prev; (prev || 0) + 1 }
+ enum.to_a.should == [0, 1, 2]
+ end
+
+ context "when initial value skipped" do
+ it "uses nil instead" do
+ ScratchPad.record []
+ enum = Enumerator.produce { |prev| ScratchPad << prev; (prev || 0) + 1 }
- enum.take(3).should == [1, 2, 3]
- ScratchPad.recorded.should == [nil, 1, 2]
- end
+ enum.take(3).should == [1, 2, 3]
+ ScratchPad.recorded.should == [nil, 1, 2]
+ end
- it "starts enumerable from result of first block call" do
- array = "a\nb\nc\nd".lines
- lines = Enumerator.produce { array.shift }.take_while { |s| s }
+ it "starts enumerable from result of first block call" do
+ array = "a\nb\nc\nd".lines
+ lines = Enumerator.produce { array.shift }.take_while { |s| s }
- lines.should == ["a\n", "b\n", "c\n", "d"]
- end
+ lines.should == ["a\n", "b\n", "c\n", "d"]
end
end
end
diff --git a/spec/ruby/core/enumerator/product/each_spec.rb b/spec/ruby/core/enumerator/product/each_spec.rb
new file mode 100644
index 0000000000..cabeb9d93a
--- /dev/null
+++ b/spec/ruby/core/enumerator/product/each_spec.rb
@@ -0,0 +1,73 @@
+require_relative '../../../spec_helper'
+require_relative '../../enumerable/shared/enumeratorized'
+
+ruby_version_is "3.2" do
+ describe "Enumerator::Product#each" do
+ it_behaves_like :enumeratorized_with_origin_size, :each, Enumerator::Product.new([1, 2], [:a, :b])
+
+ it "yields each element of Cartesian product of enumerators" do
+ enum = Enumerator::Product.new([1, 2], [:a, :b])
+ acc = []
+ enum.each { |e| acc << e }
+ acc.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
+ end
+
+ it "calls #each_entry method on enumerators" do
+ object1 = Object.new
+ def object1.each_entry
+ yield 1
+ yield 2
+ end
+
+ object2 = Object.new
+ def object2.each_entry
+ yield :a
+ yield :b
+ end
+
+ enum = Enumerator::Product.new(object1, object2)
+ acc = []
+ enum.each { |e| acc << e }
+ acc.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
+ end
+
+ it "raises a NoMethodError if the object doesn't respond to #each_entry" do
+ -> {
+ Enumerator::Product.new(Object.new).each {}
+ }.should raise_error(NoMethodError, /undefined method [`']each_entry' for/)
+ end
+
+ it "returns enumerator if not given a block" do
+ enum = Enumerator::Product.new([1, 2], [:a, :b])
+ enum.each.should.kind_of?(Enumerator)
+
+ enum = Enumerator::Product.new([1, 2], [:a, :b])
+ enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
+ end
+
+ it "returns self if given a block" do
+ enum = Enumerator::Product.new([1, 2], [:a, :b])
+ enum.each {}.should.equal?(enum)
+ end
+
+ it "doesn't accept arguments" do
+ Enumerator::Product.instance_method(:each).arity.should == 0
+ end
+
+ it "yields each element to a block that takes multiple arguments" do
+ enum = Enumerator::Product.new([1, 2], [:a, :b])
+
+ acc = []
+ enum.each { |x, y| acc << x }
+ acc.should == [1, 1, 2, 2]
+
+ acc = []
+ enum.each { |x, y| acc << y }
+ acc.should == [:a, :b, :a, :b]
+
+ acc = []
+ enum.each { |x, y, z| acc << z }
+ acc.should == [nil, nil, nil, nil]
+ end
+ end
+end
diff --git a/spec/ruby/core/enumerator/product/initialize_copy_spec.rb b/spec/ruby/core/enumerator/product/initialize_copy_spec.rb
new file mode 100644
index 0000000000..46e8421322
--- /dev/null
+++ b/spec/ruby/core/enumerator/product/initialize_copy_spec.rb
@@ -0,0 +1,54 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is "3.2" do
+ describe "Enumerator::Product#initialize_copy" do
+ it "replaces content of the receiver with content of the other object" do
+ enum = Enumerator::Product.new([true, false])
+ enum2 = Enumerator::Product.new([1, 2], [:a, :b])
+
+ enum.send(:initialize_copy, enum2)
+ enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
+ end
+
+ it "returns self" do
+ enum = Enumerator::Product.new([true, false])
+ enum2 = Enumerator::Product.new([1, 2], [:a, :b])
+
+ enum.send(:initialize_copy, enum2).should.equal?(enum)
+ end
+
+ it "is a private method" do
+ Enumerator::Product.should have_private_instance_method(:initialize_copy, false)
+ end
+
+ it "does nothing if the argument is the same as the receiver" do
+ enum = Enumerator::Product.new(1..2)
+ enum.send(:initialize_copy, enum).should.equal?(enum)
+
+ enum.freeze
+ enum.send(:initialize_copy, enum).should.equal?(enum)
+ end
+
+ it "raises FrozenError if the receiver is frozen" do
+ enum = Enumerator::Product.new(1..2)
+ enum2 = Enumerator::Product.new(3..4)
+
+ -> { enum.freeze.send(:initialize_copy, enum2) }.should raise_error(FrozenError)
+ end
+
+ it "raises TypeError if the objects are of different class" do
+ enum = Enumerator::Product.new(1..2)
+ enum2 = Class.new(Enumerator::Product).new(3..4)
+
+ -> { enum.send(:initialize_copy, enum2) }.should raise_error(TypeError, 'initialize_copy should take same class object')
+ -> { enum2.send(:initialize_copy, enum) }.should raise_error(TypeError, 'initialize_copy should take same class object')
+ end
+
+ it "raises ArgumentError if the argument is not initialized yet" do
+ enum = Enumerator::Product.new(1..2)
+ enum2 = Enumerator::Product.allocate
+
+ -> { enum.send(:initialize_copy, enum2) }.should raise_error(ArgumentError, 'uninitialized product')
+ end
+ end
+end
diff --git a/spec/ruby/core/enumerator/product/initialize_spec.rb b/spec/ruby/core/enumerator/product/initialize_spec.rb
new file mode 100644
index 0000000000..4b60564240
--- /dev/null
+++ b/spec/ruby/core/enumerator/product/initialize_spec.rb
@@ -0,0 +1,33 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is "3.2" do
+ describe "Enumerator::Product#initialize" do
+ before :each do
+ @uninitialized = Enumerator::Product.allocate
+ end
+
+ it "is a private method" do
+ Enumerator::Product.should have_private_instance_method(:initialize, false)
+ end
+
+ it "returns self" do
+ @uninitialized.send(:initialize).should equal(@uninitialized)
+ end
+
+ it "accepts many arguments" do
+ @uninitialized.send(:initialize, 0..1, 2..3, 4..5).should equal(@uninitialized)
+ end
+
+ it "accepts arguments that are not Enumerable nor responding to :each_entry" do
+ @uninitialized.send(:initialize, Object.new).should equal(@uninitialized)
+ end
+
+ describe "on frozen instance" do
+ it "raises a FrozenError" do
+ -> {
+ @uninitialized.freeze.send(:initialize, 0..1)
+ }.should raise_error(FrozenError)
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/enumerator/product/inspect_spec.rb b/spec/ruby/core/enumerator/product/inspect_spec.rb
new file mode 100644
index 0000000000..1ea8e9c49b
--- /dev/null
+++ b/spec/ruby/core/enumerator/product/inspect_spec.rb
@@ -0,0 +1,22 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is "3.2" do
+ describe "Enumerator::Product#inspect" do
+ it "returns a String including enumerators" do
+ enum = Enumerator::Product.new([1, 2], [:a, :b])
+ enum.inspect.should == "#<Enumerator::Product: [[1, 2], [:a, :b]]>"
+ end
+
+ it "represents a recursive element with '[...]'" do
+ enum = [1, 2]
+ enum_recursive = Enumerator::Product.new(enum)
+
+ enum << enum_recursive
+ enum_recursive.inspect.should == "#<Enumerator::Product: [[1, 2, #<Enumerator::Product: ...>]]>"
+ end
+
+ it "returns a not initialized representation if #initialized is not called yet" do
+ Enumerator::Product.allocate.inspect.should == "#<Enumerator::Product: uninitialized>"
+ end
+ end
+end
diff --git a/spec/ruby/core/enumerator/product/rewind_spec.rb b/spec/ruby/core/enumerator/product/rewind_spec.rb
new file mode 100644
index 0000000000..e8ee730239
--- /dev/null
+++ b/spec/ruby/core/enumerator/product/rewind_spec.rb
@@ -0,0 +1,64 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is "3.2" do
+ describe "Enumerator::Product#rewind" do
+ before :each do
+ @enum = Enumerator::Product.new([1, 2].each.to_enum, [:a, :b].each.to_enum)
+ end
+
+ it "resets the enumerator to its initial state" do
+ @enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
+ @enum.rewind
+ @enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
+ end
+
+ it "returns self" do
+ @enum.rewind.should.equal? @enum
+ end
+
+ it "has no effect on a new enumerator" do
+ @enum.rewind
+ @enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
+ end
+
+ it "has no effect if called multiple, consecutive times" do
+ @enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
+ @enum.rewind
+ @enum.rewind
+ @enum.each.to_a.should == [[1, :a], [1, :b], [2, :a], [2, :b]]
+ end
+
+ it "calls the enclosed object's rewind method if one exists" do
+ obj = mock('rewinder')
+ enum = Enumerator::Product.new(obj.to_enum)
+
+ obj.should_receive(:rewind)
+ enum.rewind
+ end
+
+ it "does nothing if the object doesn't have a #rewind method" do
+ obj = mock('rewinder')
+ enum = Enumerator::Product.new(obj.to_enum)
+
+ enum.rewind.should == enum
+ end
+
+ it "calls a rewind method on each enumerable in direct order" do
+ ScratchPad.record []
+
+ object1 = Object.new
+ def object1.rewind; ScratchPad << :object1; end
+
+ object2 = Object.new
+ def object2.rewind; ScratchPad << :object2; end
+
+ object3 = Object.new
+ def object3.rewind; ScratchPad << :object3; end
+
+ enum = Enumerator::Product.new(object1, object2, object3)
+ enum.rewind
+
+ ScratchPad.recorded.should == [:object1, :object2, :object3]
+ end
+ end
+end
diff --git a/spec/ruby/core/enumerator/product/size_spec.rb b/spec/ruby/core/enumerator/product/size_spec.rb
new file mode 100644
index 0000000000..46958b1a22
--- /dev/null
+++ b/spec/ruby/core/enumerator/product/size_spec.rb
@@ -0,0 +1,56 @@
+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
+ end
+end
diff --git a/spec/ruby/core/enumerator/product_spec.rb b/spec/ruby/core/enumerator/product_spec.rb
new file mode 100644
index 0000000000..0acca6690e
--- /dev/null
+++ b/spec/ruby/core/enumerator/product_spec.rb
@@ -0,0 +1,93 @@
+require_relative '../../spec_helper'
+
+ruby_version_is "3.2" do
+ describe "Enumerator.product" do
+ it "returns a Cartesian product of enumerators" do
+ enum = Enumerator.product(1..2, ["A", "B"])
+ enum.to_a.should == [[1, "A"], [1, "B"], [2, "A"], [2, "B"]]
+ end
+
+ it "accepts a list of enumerators of any length" do
+ enum = Enumerator.product(1..2)
+ enum.to_a.should == [[1], [2]]
+
+ enum = Enumerator.product(1..2, ["A"])
+ enum.to_a.should == [[1, "A"], [2, "A"]]
+
+ enum = Enumerator.product(1..2, ["A"], ["B"])
+ enum.to_a.should == [[1, "A", "B"], [2, "A", "B"]]
+
+ enum = Enumerator.product(2..3, ["A"], ["B"], ["C"])
+ enum.to_a.should == [[2, "A", "B", "C"], [3, "A", "B", "C"]]
+ end
+
+ it "returns an enumerator with an empty array when no arguments passed" do
+ enum = Enumerator.product
+ enum.to_a.should == [[]]
+ end
+
+ it "returns an instance of Enumerator::Product" do
+ enum = Enumerator.product
+ enum.class.should == Enumerator::Product
+ end
+
+ it "accepts infinite enumerators and returns infinite enumerator" do
+ enum = Enumerator.product(1.., ["A", "B"])
+ enum.take(5).should == [[1, "A"], [1, "B"], [2, "A"], [2, "B"], [3, "A"]]
+ enum.size.should == Float::INFINITY
+ end
+
+ it "accepts a block" do
+ elems = []
+ enum = Enumerator.product(1..2, ["X", "Y"]) { elems << _1 }
+
+ elems.should == [[1, "X"], [1, "Y"], [2, "X"], [2, "Y"]]
+ end
+
+ it "returns nil when a block passed" do
+ Enumerator.product(1..2) {}.should == nil
+ end
+
+ # https://bugs.ruby-lang.org/issues/19829
+ it "reject keyword arguments" do
+ -> {
+ Enumerator.product(1..3, foo: 1, bar: 2)
+ }.should raise_error(ArgumentError, "unknown keywords: :foo, :bar")
+ end
+
+ it "calls only #each_entry method on arguments" do
+ object = Object.new
+ def object.each_entry
+ yield 1
+ yield 2
+ end
+
+ enum = Enumerator.product(object, ["A", "B"])
+ enum.to_a.should == [[1, "A"], [1, "B"], [2, "A"], [2, "B"]]
+ end
+
+ it "raises NoMethodError when argument doesn't respond to #each_entry" do
+ -> {
+ Enumerator.product(Object.new).to_a
+ }.should raise_error(NoMethodError, /undefined method [`']each_entry' for/)
+ end
+
+ it "calls #each_entry lazily" do
+ Enumerator.product(Object.new).should be_kind_of(Enumerator)
+ end
+
+ it "iterates through consuming enumerator elements only once" do
+ a = [1, 2, 3]
+ i = 0
+
+ enum = Enumerator.new do |y|
+ while i < a.size
+ y << a[i]
+ i += 1
+ end
+ end
+
+ Enumerator.product(['a', 'b'], enum).to_a.should == [["a", 1], ["a", 2], ["a", 3]]
+ end
+ end
+end
diff --git a/spec/ruby/core/enumerator/rewind_spec.rb b/spec/ruby/core/enumerator/rewind_spec.rb
index a105f2c619..6ba0edf174 100644
--- a/spec/ruby/core/enumerator/rewind_spec.rb
+++ b/spec/ruby/core/enumerator/rewind_spec.rb
@@ -14,7 +14,7 @@ describe "Enumerator#rewind" do
end
it "returns self" do
- @enum.rewind.should == @enum
+ @enum.rewind.should.equal? @enum
end
it "has no effect on a new enumerator" do
@@ -49,7 +49,7 @@ describe "Enumerator#rewind" do
obj = mock('rewinder')
enum = obj.to_enum
obj.should_receive(:each).at_most(1)
- -> { enum.rewind.should == enum }.should_not raise_error
+ enum.rewind.should == enum
end
end
diff --git a/spec/ruby/core/enumerator/yielder/to_proc_spec.rb b/spec/ruby/core/enumerator/yielder/to_proc_spec.rb
index 0ed1645853..1d3681ab50 100644
--- a/spec/ruby/core/enumerator/yielder/to_proc_spec.rb
+++ b/spec/ruby/core/enumerator/yielder/to_proc_spec.rb
@@ -1,18 +1,16 @@
require_relative '../../../spec_helper'
-ruby_version_is "2.7" do
- describe "Enumerator::Yielder#to_proc" do
- it "returns a Proc object that takes an argument and yields it to the block" do
- ScratchPad.record []
- y = Enumerator::Yielder.new { |*args| ScratchPad << args; "foobar" }
+describe "Enumerator::Yielder#to_proc" do
+ it "returns a Proc object that takes an argument and yields it to the block" do
+ ScratchPad.record []
+ y = Enumerator::Yielder.new { |*args| ScratchPad << args; "foobar" }
- callable = y.to_proc
- callable.class.should == Proc
+ callable = y.to_proc
+ callable.class.should == Proc
- result = callable.call(1, 2)
- ScratchPad.recorded.should == [[1, 2]]
+ result = callable.call(1, 2)
+ ScratchPad.recorded.should == [[1, 2]]
- result.should == "foobar"
- end
+ result.should == "foobar"
end
end
diff --git a/spec/ruby/core/env/clone_spec.rb b/spec/ruby/core/env/clone_spec.rb
new file mode 100644
index 0000000000..991e4e6774
--- /dev/null
+++ b/spec/ruby/core/env/clone_spec.rb
@@ -0,0 +1,23 @@
+require_relative '../../spec_helper'
+
+describe "ENV#clone" do
+ it "raises ArgumentError when keyword argument 'freeze' is neither nil nor boolean" do
+ -> {
+ ENV.clone(freeze: 1)
+ }.should raise_error(ArgumentError)
+ end
+
+ it "raises ArgumentError when keyword argument is not 'freeze'" do
+ -> {
+ ENV.clone(foo: nil)
+ }.should raise_error(ArgumentError)
+ end
+
+ ruby_version_is "3.2" do
+ it "raises TypeError" do
+ -> {
+ ENV.clone
+ }.should raise_error(TypeError, /Cannot clone ENV, use ENV.to_h to get a copy of ENV as a hash/)
+ end
+ end
+end
diff --git a/spec/ruby/core/env/delete_spec.rb b/spec/ruby/core/env/delete_spec.rb
index 5e7891f74d..f28ac97911 100644
--- a/spec/ruby/core/env/delete_spec.rb
+++ b/spec/ruby/core/env/delete_spec.rb
@@ -30,11 +30,9 @@ describe "ENV.delete" do
ScratchPad.recorded.should == "foo"
end
- ruby_version_is "3.0" do
- it "returns the result of given block if the named environment variable does not exist" do
- ENV.delete("foo")
- ENV.delete("foo") { |name| "bar" }.should == "bar"
- end
+ it "returns the result of given block if the named environment variable does not exist" do
+ ENV.delete("foo")
+ ENV.delete("foo") { |name| "bar" }.should == "bar"
end
it "does not evaluate the block if the environment variable exists" do
@@ -43,6 +41,14 @@ describe "ENV.delete" do
ENV["foo"].should == nil
end
+ it "removes the variable coerced with #to_str" do
+ ENV["foo"] = "bar"
+ k = mock('key')
+ k.should_receive(:to_str).and_return("foo")
+ ENV.delete(k)
+ ENV["foo"].should == nil
+ end
+
it "raises TypeError if the argument is not a String and does not respond to #to_str" do
-> { ENV.delete(Object.new) }.should raise_error(TypeError, "no implicit conversion of Object into String")
end
diff --git a/spec/ruby/core/env/dup_spec.rb b/spec/ruby/core/env/dup_spec.rb
new file mode 100644
index 0000000000..46d125aca8
--- /dev/null
+++ b/spec/ruby/core/env/dup_spec.rb
@@ -0,0 +1,11 @@
+require_relative '../../spec_helper'
+
+describe "ENV#dup" do
+ ruby_version_is "3.1" do
+ it "raises TypeError" do
+ -> {
+ ENV.dup
+ }.should raise_error(TypeError, /Cannot dup ENV, use ENV.to_h to get a copy of ENV as a hash/)
+ end
+ end
+end
diff --git a/spec/ruby/core/env/except_spec.rb b/spec/ruby/core/env/except_spec.rb
index cfe5865abe..fb8f3b7536 100644
--- a/spec/ruby/core/env/except_spec.rb
+++ b/spec/ruby/core/env/except_spec.rb
@@ -1,36 +1,34 @@
require_relative 'spec_helper'
require_relative 'shared/to_hash'
-ruby_version_is "3.0" do
- describe "ENV.except" do
- before do
- @orig_hash = ENV.to_hash
- end
+describe "ENV.except" do
+ before do
+ @orig_hash = ENV.to_hash
+ end
- after do
- ENV.replace @orig_hash
- end
+ after do
+ ENV.replace @orig_hash
+ end
- # Testing the method without arguments is covered via
- it_behaves_like :env_to_hash, :except
+ # Testing the method without arguments is covered via
+ it_behaves_like :env_to_hash, :except
- it "returns a hash without the requested subset" do
- ENV.clear
+ it "returns a hash without the requested subset" do
+ ENV.clear
- ENV['one'] = '1'
- ENV['two'] = '2'
- ENV['three'] = '3'
+ ENV['one'] = '1'
+ ENV['two'] = '2'
+ ENV['three'] = '3'
- ENV.except('one', 'three').should == { 'two' => '2' }
- end
+ ENV.except('one', 'three').should == { 'two' => '2' }
+ end
- it "ignores keys not present in the original hash" do
- ENV.clear
+ it "ignores keys not present in the original hash" do
+ ENV.clear
- ENV['one'] = '1'
- ENV['two'] = '2'
+ ENV['one'] = '1'
+ ENV['two'] = '2'
- ENV.except('one', 'three').should == { 'two' => '2' }
- end
+ ENV.except('one', 'three').should == { 'two' => '2' }
end
end
diff --git a/spec/ruby/core/env/index_spec.rb b/spec/ruby/core/env/index_spec.rb
deleted file mode 100644
index 301a66ab4e..0000000000
--- a/spec/ruby/core/env/index_spec.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'shared/key'
-
-ruby_version_is ''...'3.0' do
- describe "ENV.index" do
- it_behaves_like :env_key, :index
-
- it "warns about deprecation" do
- -> do
- ENV.index("foo")
- end.should complain(/warning: ENV.index is deprecated; use ENV.key/)
- end
- end
-end
diff --git a/spec/ruby/core/env/indexes_spec.rb b/spec/ruby/core/env/indexes_spec.rb
deleted file mode 100644
index e724feaa39..0000000000
--- a/spec/ruby/core/env/indexes_spec.rb
+++ /dev/null
@@ -1 +0,0 @@
-require_relative '../../spec_helper'
diff --git a/spec/ruby/core/env/indices_spec.rb b/spec/ruby/core/env/indices_spec.rb
deleted file mode 100644
index e724feaa39..0000000000
--- a/spec/ruby/core/env/indices_spec.rb
+++ /dev/null
@@ -1 +0,0 @@
-require_relative '../../spec_helper'
diff --git a/spec/ruby/core/env/key_spec.rb b/spec/ruby/core/env/key_spec.rb
index 82cfbefa39..cf70286409 100644
--- a/spec/ruby/core/env/key_spec.rb
+++ b/spec/ruby/core/env/key_spec.rb
@@ -1,11 +1,39 @@
require_relative '../../spec_helper'
require_relative 'shared/include'
-require_relative 'shared/key'
describe "ENV.key?" do
it_behaves_like :env_include, :key?
end
describe "ENV.key" do
- it_behaves_like :env_key, :key
+ before :each do
+ @saved_foo = ENV["foo"]
+ end
+
+ after :each do
+ ENV["foo"] = @saved_foo
+ end
+
+ it "returns the index associated with the passed value" do
+ ENV["foo"] = "bar"
+ ENV.key("bar").should == "foo"
+ end
+
+ it "returns nil if the passed value is not found" do
+ ENV.delete("foo")
+ ENV.key("foo").should be_nil
+ end
+
+ it "coerces the key element with #to_str" do
+ ENV["foo"] = "bar"
+ k = mock('key')
+ k.should_receive(:to_str).and_return("bar")
+ ENV.key(k).should == "foo"
+ end
+
+ it "raises TypeError if the argument is not a String and does not respond to #to_str" do
+ -> {
+ ENV.key(Object.new)
+ }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ end
end
diff --git a/spec/ruby/core/env/merge_spec.rb b/spec/ruby/core/env/merge_spec.rb
index b418cd11f4..f10662cf79 100644
--- a/spec/ruby/core/env/merge_spec.rb
+++ b/spec/ruby/core/env/merge_spec.rb
@@ -1,8 +1,6 @@
require_relative '../../spec_helper'
require_relative 'shared/update'
-ruby_version_is "2.7" do
- describe "ENV.merge!" do
- it_behaves_like :env_update, :merge!
- end
+describe "ENV.merge!" do
+ it_behaves_like :env_update, :merge!
end
diff --git a/spec/ruby/core/env/shared/include.rb b/spec/ruby/core/env/shared/include.rb
index 3efcd523d6..70aa555301 100644
--- a/spec/ruby/core/env/shared/include.rb
+++ b/spec/ruby/core/env/shared/include.rb
@@ -17,6 +17,13 @@ describe :env_include, shared: true do
ENV.send(@method, "foo").should == false
end
+ it "coerces the key with #to_str" do
+ ENV["foo"] = "bar"
+ k = mock('key')
+ k.should_receive(:to_str).and_return("foo")
+ ENV.send(@method, k).should == true
+ end
+
it "raises TypeError if the argument is not a String and does not respond to #to_str" do
-> { ENV.send(@method, Object.new) }.should raise_error(TypeError, "no implicit conversion of Object into String")
end
diff --git a/spec/ruby/core/env/shared/key.rb b/spec/ruby/core/env/shared/key.rb
deleted file mode 100644
index 93396d2aca..0000000000
--- a/spec/ruby/core/env/shared/key.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-describe :env_key, shared: true do
- before :each do
- @saved_foo = ENV["foo"]
- end
-
- after :each do
- ENV["foo"] = @saved_foo
- end
-
- it "returns the index associated with the passed value" do
- ENV["foo"] = "bar"
- suppress_warning {
- ENV.send(@method, "bar").should == "foo"
- }
- end
-
- it "returns nil if the passed value is not found" do
- ENV.delete("foo")
- suppress_warning {
- ENV.send(@method, "foo").should be_nil
- }
- end
-
- it "raises TypeError if the argument is not a String and does not respond to #to_str" do
- -> {
- suppress_warning {
- ENV.send(@method, Object.new)
- }
- }.should raise_error(TypeError, "no implicit conversion of Object into String")
- end
-end
diff --git a/spec/ruby/core/env/shared/update.rb b/spec/ruby/core/env/shared/update.rb
index 129a56544c..7d4799955b 100644
--- a/spec/ruby/core/env/shared/update.rb
+++ b/spec/ruby/core/env/shared/update.rb
@@ -15,6 +15,14 @@ describe :env_update, shared: true do
ENV["bar"].should == "1"
end
+ ruby_version_is "3.2" do
+ it "adds the multiple parameter hashes to ENV, returning ENV" do
+ ENV.send(@method, {"foo" => "multi1"}, {"bar" => "multi2"}).should equal(ENV)
+ ENV["foo"].should == "multi1"
+ ENV["bar"].should == "multi2"
+ end
+ end
+
it "returns ENV when no block given" do
ENV.send(@method, {"foo" => "0", "bar" => "1"}).should equal(ENV)
end
@@ -39,23 +47,21 @@ describe :env_update, shared: true do
ENV["bar"].should == "5"
end
- ruby_version_is "2.7" do
- # BUG: https://bugs.ruby-lang.org/issues/16192
- it "does not evaluate the block when the name is new" do
- ENV.delete("bar")
- ENV.send @method, {"foo" => "0"}
- ENV.send(@method, "bar" => "1") { |key, old, new| fail "Should not get here" }
- ENV["bar"].should == "1"
- end
+ # BUG: https://bugs.ruby-lang.org/issues/16192
+ it "does not evaluate the block when the name is new" do
+ ENV.delete("bar")
+ ENV.send @method, {"foo" => "0"}
+ ENV.send(@method, "bar" => "1") { |key, old, new| fail "Should not get here" }
+ ENV["bar"].should == "1"
+ end
- # BUG: https://bugs.ruby-lang.org/issues/16192
- it "does not use the block's return value as the value when the name is new" do
- ENV.delete("bar")
- ENV.send @method, {"foo" => "0"}
- ENV.send(@method, "bar" => "1") { |key, old, new| "Should not use this value" }
- ENV["foo"].should == "0"
- ENV["bar"].should == "1"
- end
+ # BUG: https://bugs.ruby-lang.org/issues/16192
+ it "does not use the block's return value as the value when the name is new" do
+ ENV.delete("bar")
+ ENV.send @method, {"foo" => "0"}
+ ENV.send(@method, "bar" => "1") { |key, old, new| "Should not use this value" }
+ ENV["foo"].should == "0"
+ ENV["bar"].should == "1"
end
it "returns ENV when block given" do
diff --git a/spec/ruby/core/env/shared/value.rb b/spec/ruby/core/env/shared/value.rb
index bef96b5fef..c2b5025465 100644
--- a/spec/ruby/core/env/shared/value.rb
+++ b/spec/ruby/core/env/shared/value.rb
@@ -16,6 +16,13 @@ describe :env_value, shared: true do
ENV.send(@method, "foo").should == false
end
+ it "coerces the value element with #to_str" do
+ ENV["foo"] = "bar"
+ v = mock('value')
+ v.should_receive(:to_str).and_return("bar")
+ ENV.send(@method, v).should == true
+ end
+
it "returns nil if the argument is not a String and does not respond to #to_str" do
ENV.send(@method, Object.new).should == nil
end
diff --git a/spec/ruby/core/env/slice_spec.rb b/spec/ruby/core/env/slice_spec.rb
index e3b6020391..959239d2b2 100644
--- a/spec/ruby/core/env/slice_spec.rb
+++ b/spec/ruby/core/env/slice_spec.rb
@@ -21,6 +21,16 @@ describe "ENV.slice" do
ENV.slice("foo", "boo", "bar").should == {"foo" => "0", "bar" => "1"}
end
+ it "returns the values for the keys coerced with #to_str, but keeps the original objects as result keys" do
+ foo = mock('key 1')
+ foo.should_receive(:to_str).and_return("foo")
+ boo = mock('key 2')
+ boo.should_receive(:to_str).and_return("boo")
+ bar = mock('key 3')
+ bar.should_receive(:to_str).and_return("bar")
+ ENV.slice(foo, boo, bar).should == {foo => "0", bar => "1"}
+ end
+
it "raises TypeError if any argument is not a String and does not respond to #to_str" do
-> { ENV.slice(Object.new) }.should raise_error(TypeError, "no implicit conversion of Object into String")
end
diff --git a/spec/ruby/core/env/to_a_spec.rb b/spec/ruby/core/env/to_a_spec.rb
index 39e3877b48..2b1649281f 100644
--- a/spec/ruby/core/env/to_a_spec.rb
+++ b/spec/ruby/core/env/to_a_spec.rb
@@ -6,7 +6,10 @@ describe "ENV.to_a" do
a = ENV.to_a
a.is_a?(Array).should == true
a.size.should == ENV.size
- ENV.each_pair { |k, v| a.should include([k, v])}
+ a.each { |k,v| ENV[k].should == v }
+
+ a.first.should.is_a?(Array)
+ a.first.size.should == 2
end
it "returns the entries in the locale encoding" do
diff --git a/spec/ruby/core/exception/backtrace_spec.rb b/spec/ruby/core/exception/backtrace_spec.rb
index 3f74c4cefe..9a65ea3820 100644
--- a/spec/ruby/core/exception/backtrace_spec.rb
+++ b/spec/ruby/core/exception/backtrace_spec.rb
@@ -27,7 +27,7 @@ describe "Exception#backtrace" do
end
it "includes the name of the method from where self raised in the first element" do
- @backtrace.first.should =~ /in `backtrace'/
+ @backtrace.first.should =~ /in [`'](?:ExceptionSpecs::Backtrace\.)?backtrace'/
end
it "includes the filename of the location immediately prior to where self raised in the second element" do
@@ -38,12 +38,25 @@ describe "Exception#backtrace" do
@backtrace[1].should =~ /:6(:in )?/
end
- it "contains lines of the same format for each prior position in the stack" do
- @backtrace[2..-1].each do |line|
- # This regexp is deliberately imprecise to account for the need to abstract out
- # the paths of the included mspec files and the desire to avoid specifying in any
- # detail what the in `...' portion looks like.
- line.should =~ /^.+:\d+:in `[^`]+'$/
+ ruby_version_is ""..."3.4" do
+ it "contains lines of the same format for each prior position in the stack" do
+ @backtrace[2..-1].each do |line|
+ # This regexp is deliberately imprecise to account for the need to abstract out
+ # the paths of the included mspec files and the desire to avoid specifying in any
+ # detail what the in `...' portion looks like.
+ line.should =~ /^.+:\d+:in `[^`]+'$/
+ end
+ end
+ end
+
+ ruby_version_is "3.4" do
+ it "contains lines of the same format for each prior position in the stack" do
+ @backtrace[2..-1].each do |line|
+ # This regexp is deliberately imprecise to account for the need to abstract out
+ # the paths of the included mspec files and the desire to avoid specifying in any
+ # detail what the in '...' portion looks like.
+ line.should =~ /^.+:\d+:in '[^`]+'$/
+ end
end
end
diff --git a/spec/ruby/core/exception/case_compare_spec.rb b/spec/ruby/core/exception/case_compare_spec.rb
index 87b9dee3ca..5fd11ae741 100644
--- a/spec/ruby/core/exception/case_compare_spec.rb
+++ b/spec/ruby/core/exception/case_compare_spec.rb
@@ -26,13 +26,11 @@ describe "SystemCallError.===" do
end
it "returns true if receiver is generic and arg is kind of SystemCallError" do
- unknown_error_number = Errno.constants.size
e = SystemCallError.new('foo', @example_errno)
SystemCallError.===(e).should == true
end
it "returns false if receiver is generic and arg is not kind of SystemCallError" do
- unknown_error_number = Errno.constants.size
e = Object.new
SystemCallError.===(e).should == false
end
diff --git a/spec/ruby/core/exception/detailed_message_spec.rb b/spec/ruby/core/exception/detailed_message_spec.rb
new file mode 100644
index 0000000000..fbe4443daa
--- /dev/null
+++ b/spec/ruby/core/exception/detailed_message_spec.rb
@@ -0,0 +1,43 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/common'
+
+describe "Exception#detailed_message" do
+ ruby_version_is "3.2" do
+ it "returns decorated message" do
+ RuntimeError.new("new error").detailed_message.should == "new error (RuntimeError)"
+ end
+
+ it "is called by #full_message to allow message customization" do
+ exception = Exception.new("new error")
+ def exception.detailed_message(**)
+ "<prefix>#{message}<suffix>"
+ end
+ exception.full_message(highlight: false).should.include? "<prefix>new error<suffix>"
+ end
+
+ it "accepts highlight keyword argument and adds escape control sequences" do
+ RuntimeError.new("new error").detailed_message(highlight: true).should == "\e[1mnew error (\e[1;4mRuntimeError\e[m\e[1m)\e[m"
+ end
+
+ it "allows and ignores other keyword arguments" do
+ RuntimeError.new("new error").detailed_message(foo: true).should == "new error (RuntimeError)"
+ end
+
+ it "returns just a message if exception class is anonymous" do
+ Class.new(RuntimeError).new("message").detailed_message.should == "message"
+ end
+
+ it "returns 'unhandled exception' for an instance of RuntimeError with empty message" do
+ RuntimeError.new("").detailed_message.should == "unhandled exception"
+ end
+
+ it "returns just class name for an instance of RuntimeError subclass with empty message" do
+ DetailedMessageSpec::C.new("").detailed_message.should == "DetailedMessageSpec::C"
+ end
+
+ it "returns a generated class name for an instance of RuntimeError anonymous subclass with empty message" do
+ klass = Class.new(RuntimeError)
+ klass.new("").detailed_message.should =~ /\A#<Class:0x\h+>\z/
+ end
+ end
+end
diff --git a/spec/ruby/core/exception/equal_value_spec.rb b/spec/ruby/core/exception/equal_value_spec.rb
index 7f2065511a..e8f3ce0f8d 100644
--- a/spec/ruby/core/exception/equal_value_spec.rb
+++ b/spec/ruby/core/exception/equal_value_spec.rb
@@ -22,18 +22,18 @@ describe "Exception#==" do
it "returns true if both exceptions have the same class, the same message, and the same backtrace" do
one = TypeError.new("message")
- one.set_backtrace [File.dirname(__FILE__)]
+ one.set_backtrace [__dir__]
two = TypeError.new("message")
- two.set_backtrace [File.dirname(__FILE__)]
+ two.set_backtrace [__dir__]
one.should == two
end
it "returns false if the two exceptions inherit from Exception but have different classes" do
one = RuntimeError.new("message")
- one.set_backtrace [File.dirname(__FILE__)]
+ one.set_backtrace [__dir__]
one.should be_kind_of(Exception)
two = TypeError.new("message")
- two.set_backtrace [File.dirname(__FILE__)]
+ two.set_backtrace [__dir__]
two.should be_kind_of(Exception)
one.should_not == two
end
@@ -52,7 +52,7 @@ describe "Exception#==" do
it "returns false if the two exceptions differ only in their backtrace" do
one = RuntimeError.new("message")
- one.set_backtrace [File.dirname(__FILE__)]
+ one.set_backtrace [__dir__]
two = RuntimeError.new("message")
two.set_backtrace nil
one.should_not == two
@@ -60,9 +60,9 @@ describe "Exception#==" do
it "returns false if the two exceptions differ only in their message" do
one = RuntimeError.new("message")
- one.set_backtrace [File.dirname(__FILE__)]
+ one.set_backtrace [__dir__]
two = RuntimeError.new("message2")
- two.set_backtrace [File.dirname(__FILE__)]
+ two.set_backtrace [__dir__]
one.should_not == two
end
end
diff --git a/spec/ruby/core/exception/fixtures/common.rb b/spec/ruby/core/exception/fixtures/common.rb
index 0ffb3ed855..1e243098bd 100644
--- a/spec/ruby/core/exception/fixtures/common.rb
+++ b/spec/ruby/core/exception/fixtures/common.rb
@@ -93,3 +93,7 @@ class NameErrorSpecs
end
end
end
+
+module DetailedMessageSpec
+ C = Class.new(RuntimeError)
+end
diff --git a/spec/ruby/core/exception/fixtures/syntax_error.rb b/spec/ruby/core/exception/fixtures/syntax_error.rb
new file mode 100644
index 0000000000..ccec62f7a1
--- /dev/null
+++ b/spec/ruby/core/exception/fixtures/syntax_error.rb
@@ -0,0 +1,3 @@
+# rubocop:disable Lint/Syntax
+1+1=2
+# rubocop:enable Lint/Syntax
diff --git a/spec/ruby/core/exception/fixtures/thread_fiber_ensure.rb b/spec/ruby/core/exception/fixtures/thread_fiber_ensure.rb
new file mode 100644
index 0000000000..c109ec6247
--- /dev/null
+++ b/spec/ruby/core/exception/fixtures/thread_fiber_ensure.rb
@@ -0,0 +1,22 @@
+ready = false
+t = Thread.new do
+ f = Fiber.new do
+ begin
+ Fiber.yield
+ ensure
+ STDERR.puts "suspended fiber ensure"
+ end
+ end
+ f.resume
+
+ begin
+ ready = true
+ sleep
+ ensure
+ STDERR.puts "current fiber ensure"
+ end
+end
+
+Thread.pass until ready && t.stop?
+
+# let the program end, it's the same as #exit or an exception for this behavior
diff --git a/spec/ruby/core/exception/fixtures/thread_fiber_ensure_non_root_fiber.rb b/spec/ruby/core/exception/fixtures/thread_fiber_ensure_non_root_fiber.rb
new file mode 100644
index 0000000000..3364ed06d0
--- /dev/null
+++ b/spec/ruby/core/exception/fixtures/thread_fiber_ensure_non_root_fiber.rb
@@ -0,0 +1,25 @@
+ready = false
+t = Thread.new do
+ f = Fiber.new do
+ begin
+ Fiber.yield
+ ensure
+ STDERR.puts "suspended fiber ensure"
+ end
+ end
+ f.resume
+
+ f2 = Fiber.new do
+ begin
+ ready = true
+ sleep
+ ensure
+ STDERR.puts "current fiber ensure"
+ end
+ end
+ f2.resume
+end
+
+Thread.pass until ready && t.stop?
+
+# let the program end, it's the same as #exit or an exception for this behavior
diff --git a/spec/ruby/core/exception/frozen_error_spec.rb b/spec/ruby/core/exception/frozen_error_spec.rb
index f27b33295c..979ec2ff98 100644
--- a/spec/ruby/core/exception/frozen_error_spec.rb
+++ b/spec/ruby/core/exception/frozen_error_spec.rb
@@ -1,26 +1,38 @@
require_relative '../../spec_helper'
describe "FrozenError.new" do
- ruby_version_is "2.7" do
- it "should take optional receiver argument" do
- o = Object.new
- FrozenError.new("msg", receiver: o).receiver.should equal(o)
- end
+ it "should take optional receiver argument" do
+ o = Object.new
+ FrozenError.new("msg", receiver: o).receiver.should equal(o)
end
end
describe "FrozenError#receiver" do
- ruby_version_is "2.7" do
- it "should return frozen object that modification was attempted on" do
- o = Object.new.freeze
- begin
- def o.x; end
- rescue => e
- e.should be_kind_of(FrozenError)
- e.receiver.should equal(o)
- else
- raise
- end
+ it "should return frozen object that modification was attempted on" do
+ o = Object.new.freeze
+ begin
+ def o.x; end
+ rescue => e
+ e.should be_kind_of(FrozenError)
+ e.receiver.should equal(o)
+ else
+ raise
+ end
+ end
+end
+
+describe "Modifying a frozen object" do
+ context "#inspect is redefined and modifies the object" do
+ it "returns ... instead of String representation of object" do
+ object = Object.new
+ def object.inspect; @a = 1 end
+ def object.modify; @a = 2 end
+
+ object.freeze
+
+ # CRuby's message contains multiple whitespaces before '...'.
+ # So handle both multiple and single whitespace.
+ -> { object.modify }.should raise_error(FrozenError, /can't modify frozen .*?: \s*.../)
end
end
end
diff --git a/spec/ruby/core/exception/full_message_spec.rb b/spec/ruby/core/exception/full_message_spec.rb
index 4cece9ebf9..5154354555 100644
--- a/spec/ruby/core/exception/full_message_spec.rb
+++ b/spec/ruby/core/exception/full_message_spec.rb
@@ -15,13 +15,19 @@ describe "Exception#full_message" do
it "supports :highlight option and adds escape sequences to highlight some strings" do
e = RuntimeError.new("Some runtime error")
- full_message = e.full_message(highlight: true, order: :bottom)
- full_message.should include "\e[1mTraceback\e[m (most recent call last)"
- full_message.should include "\e[1mSome runtime error (\e[1;4mRuntimeError\e[m\e[1m)"
+ full_message = e.full_message(highlight: true, order: :top).lines
+ full_message[0].should.end_with? "\e[1mSome runtime error (\e[1;4mRuntimeError\e[m\e[1m)\e[m\n"
- full_message = e.full_message(highlight: false, order: :bottom)
- full_message.should include "Traceback (most recent call last)"
- full_message.should include "Some runtime error (RuntimeError)"
+ full_message = e.full_message(highlight: true, order: :bottom).lines
+ full_message[0].should == "\e[1mTraceback\e[m (most recent call last):\n"
+ full_message[-1].should.end_with? "\e[1mSome runtime error (\e[1;4mRuntimeError\e[m\e[1m)\e[m\n"
+
+ full_message = e.full_message(highlight: false, order: :top).lines
+ full_message[0].should.end_with? "Some runtime error (RuntimeError)\n"
+
+ full_message = e.full_message(highlight: false, order: :bottom).lines
+ full_message[0].should == "Traceback (most recent call last):\n"
+ full_message[-1].should.end_with? "Some runtime error (RuntimeError)\n"
end
it "supports :order option and places the error message and the backtrace at the top or the bottom" do
@@ -35,9 +41,52 @@ describe "Exception#full_message" do
it "shows the caller if the exception has no backtrace" do
e = RuntimeError.new("Some runtime error")
e.backtrace.should == nil
- full_message = e.full_message(highlight: false, order: :top)
- full_message.should include("#{__FILE__}:#{__LINE__-1}:in `")
- full_message.should include("': Some runtime error (RuntimeError)\n")
+ full_message = e.full_message(highlight: false, order: :top).lines
+ full_message[0].should.start_with?("#{__FILE__}:#{__LINE__-1}:in ")
+ full_message[0].should.end_with?("': Some runtime error (RuntimeError)\n")
+ end
+
+ describe "includes details about whether an exception was handled" do
+ describe "RuntimeError" do
+ it "should report as unhandled if message is empty" do
+ err = RuntimeError.new("")
+
+ err.full_message.should =~ /unhandled exception/
+ err.full_message(highlight: true).should =~ /unhandled exception/
+ err.full_message(highlight: false).should =~ /unhandled exception/
+ end
+
+ it "should not report as unhandled if the message is not empty" do
+ err = RuntimeError.new("non-empty")
+
+ err.full_message.should !~ /unhandled exception/
+ err.full_message(highlight: true).should !~ /unhandled exception/
+ err.full_message(highlight: false).should !~ /unhandled exception/
+ end
+
+ it "should not report as unhandled if the message is nil" do
+ err = RuntimeError.new(nil)
+
+ err.full_message.should !~ /unhandled exception/
+ err.full_message(highlight: true).should !~ /unhandled exception/
+ err.full_message(highlight: false).should !~ /unhandled exception/
+ end
+
+ it "should not report as unhandled if the message is not specified" do
+ err = RuntimeError.new()
+
+ err.full_message.should !~ /unhandled exception/
+ err.full_message(highlight: true).should !~ /unhandled exception/
+ err.full_message(highlight: false).should !~ /unhandled exception/
+ end
+ end
+
+ describe "generic Error" do
+ it "should not report as unhandled in any event" do
+ StandardError.new("").full_message.should !~ /unhandled exception/
+ StandardError.new("non-empty").full_message.should !~ /unhandled exception/
+ end
+ end
end
it "shows the exception class at the end of the first line of the message when the message contains multiple lines" do
@@ -45,12 +94,24 @@ describe "Exception#full_message" do
line = __LINE__; raise "first line\nsecond line"
rescue => e
full_message = e.full_message(highlight: false, order: :top).lines
- full_message[0].should include("#{__FILE__}:#{line}:in `")
- full_message[0].should include(": first line (RuntimeError)\n")
+ full_message[0].should.start_with?("#{__FILE__}:#{line}:in ")
+ full_message[0].should.end_with?(": first line (RuntimeError)\n")
full_message[1].should == "second line\n"
end
end
+ it "highlights the entire message when the message contains multiple lines" do
+ begin
+ line = __LINE__; raise "first line\nsecond line\nthird line"
+ rescue => e
+ full_message = e.full_message(highlight: true, order: :top).lines
+ full_message[0].should.start_with?("#{__FILE__}:#{line}:in ")
+ full_message[0].should.end_with?(": \e[1mfirst line (\e[1;4mRuntimeError\e[m\e[1m)\e[m\n")
+ full_message[1].should == "\e[1msecond line\e[m\n"
+ full_message[2].should == "\e[1mthird line\e[m\n"
+ end
+ end
+
it "contains cause of exception" do
begin
begin
@@ -85,4 +146,53 @@ describe "Exception#full_message" do
exception.full_message.should include "intermediate exception"
exception.full_message.should include "origin exception"
end
+
+ ruby_version_is "3.2" do
+ it "relies on #detailed_message" do
+ e = RuntimeError.new("new error")
+ e.define_singleton_method(:detailed_message) { |**| "DETAILED MESSAGE" }
+
+ e.full_message.lines.first.should =~ /DETAILED MESSAGE/
+ end
+
+ it "passes all its own keyword arguments (with :highlight default value and without :order default value) to #detailed_message" do
+ e = RuntimeError.new("new error")
+ options_passed = nil
+ e.define_singleton_method(:detailed_message) do |**options|
+ options_passed = options
+ "DETAILED MESSAGE"
+ end
+
+ e.full_message(foo: "bar")
+ options_passed.should == { foo: "bar", highlight: Exception.to_tty? }
+ end
+
+ it "converts #detailed_message returned value to String if it isn't a String" do
+ message = Object.new
+ def message.to_str; "DETAILED MESSAGE"; end
+
+ e = RuntimeError.new("new error")
+ e.define_singleton_method(:detailed_message) { |**| message }
+
+ e.full_message.lines.first.should =~ /DETAILED MESSAGE/
+ end
+
+ it "uses class name if #detailed_message returns nil" do
+ e = RuntimeError.new("new error")
+ e.define_singleton_method(:detailed_message) { |**| nil }
+
+ e.full_message(highlight: false).lines.first.should =~ /RuntimeError/
+ e.full_message(highlight: true).lines.first.should =~ /#{Regexp.escape("\e[1;4mRuntimeError\e[m")}/
+ end
+
+ it "uses class name if exception object doesn't respond to #detailed_message" do
+ e = RuntimeError.new("new error")
+ class << e
+ undef :detailed_message
+ end
+
+ e.full_message(highlight: false).lines.first.should =~ /RuntimeError/
+ e.full_message(highlight: true).lines.first.should =~ /#{Regexp.escape("\e[1;4mRuntimeError\e[m")}/
+ end
+ end
end
diff --git a/spec/ruby/core/exception/interrupt_spec.rb b/spec/ruby/core/exception/interrupt_spec.rb
index a7501efadc..90d261e470 100644
--- a/spec/ruby/core/exception/interrupt_spec.rb
+++ b/spec/ruby/core/exception/interrupt_spec.rb
@@ -48,4 +48,13 @@ describe "Interrupt" do
RUBY
out.should == "Interrupt: #{Signal.list["INT"]}\n"
end
+
+ platform_is_not :windows do
+ it "shows the backtrace and has a signaled exit status" do
+ err = IO.popen([*ruby_exe, '-e', 'Process.kill :INT, Process.pid; sleep'], err: [:child, :out], &:read)
+ $?.termsig.should == Signal.list.fetch('INT')
+ err.should.include? ': Interrupt'
+ err.should =~ /from -e:1:in [`']<main>'/
+ end
+ end
end
diff --git a/spec/ruby/core/exception/no_method_error_spec.rb b/spec/ruby/core/exception/no_method_error_spec.rb
index 8428ba0382..26df3338e9 100644
--- a/spec/ruby/core/exception/no_method_error_spec.rb
+++ b/spec/ruby/core/exception/no_method_error_spec.rb
@@ -62,26 +62,49 @@ describe "NoMethodError#message" do
NoMethodErrorSpecs::NoMethodErrorC.new.a_private_method
rescue Exception => e
e.should be_kind_of(NoMethodError)
- e.message.lines[0].should =~ /private method `a_private_method' called for #<NoMethodErrorSpecs::NoMethodErrorC:0x[\h]+>/
+ e.message.lines[0].should =~ /private method [`']a_private_method' called for /
end
end
- it "calls receiver.inspect only when calling Exception#message" do
- ScratchPad.record []
- test_class = Class.new do
- def inspect
- ScratchPad << :inspect_called
- "<inspect>"
+ ruby_version_is ""..."3.3" do
+ it "calls receiver.inspect only when calling Exception#message" do
+ ScratchPad.record []
+ test_class = Class.new do
+ def inspect
+ ScratchPad << :inspect_called
+ "<inspect>"
+ end
+ end
+ instance = test_class.new
+ begin
+ instance.bar
+ rescue Exception => e
+ e.name.should == :bar
+ ScratchPad.recorded.should == []
+ e.message.should =~ /undefined method.+\bbar\b/
+ ScratchPad.recorded.should == [:inspect_called]
end
end
- instance = test_class.new
- begin
- instance.bar
- rescue Exception => e
- e.name.should == :bar
- ScratchPad.recorded.should == []
- e.message.should =~ /undefined method.+\bbar\b/
- ScratchPad.recorded.should == [:inspect_called]
+ end
+
+ ruby_version_is "3.3" do
+ it "does not call receiver.inspect even when calling Exception#message" do
+ ScratchPad.record []
+ test_class = Class.new do
+ def inspect
+ ScratchPad << :inspect_called
+ "<inspect>"
+ end
+ end
+ instance = test_class.new
+ begin
+ instance.bar
+ rescue Exception => e
+ e.name.should == :bar
+ ScratchPad.recorded.should == []
+ e.message.should =~ /undefined method.+\bbar\b/
+ ScratchPad.recorded.should == []
+ end
end
end
@@ -102,21 +125,19 @@ describe "NoMethodError#message" do
end
end
- ruby_version_is "3.0" do
- it "uses #name to display the receiver if it is a class or a module" do
- klass = Class.new { def self.name; "MyClass"; end }
- begin
- klass.foo
- rescue NoMethodError => error
- error.message.lines.first.chomp.should == "undefined method `foo' for MyClass:Class"
- end
+ 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
- mod = Module.new { def self.name; "MyModule"; end }
- begin
- mod.foo
- rescue NoMethodError => error
- error.message.lines.first.chomp.should == "undefined method `foo' for MyModule:Module"
- end
+ mod = Module.new { def self.name; "MyModule"; end }
+ begin
+ mod.foo
+ rescue NoMethodError => error
+ error.message.lines.first.chomp.should =~ /^undefined method [`']foo' for /
end
end
end
diff --git a/spec/ruby/core/exception/set_backtrace_spec.rb b/spec/ruby/core/exception/set_backtrace_spec.rb
index ba2e1bf7aa..12c1da919c 100644
--- a/spec/ruby/core/exception/set_backtrace_spec.rb
+++ b/spec/ruby/core/exception/set_backtrace_spec.rb
@@ -11,9 +11,37 @@ describe "Exception#set_backtrace" do
it "allows the user to set the backtrace from a rescued exception" do
bt = ExceptionSpecs::Backtrace.backtrace
err = RuntimeError.new
+ err.backtrace.should == nil
+ err.backtrace_locations.should == nil
err.set_backtrace bt
+
err.backtrace.should == bt
+ 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
diff --git a/spec/ruby/core/exception/signal_exception_spec.rb b/spec/ruby/core/exception/signal_exception_spec.rb
index 566bcb4672..1a0940743f 100644
--- a/spec/ruby/core/exception/signal_exception_spec.rb
+++ b/spec/ruby/core/exception/signal_exception_spec.rb
@@ -93,7 +93,7 @@ describe "SignalException" do
platform_is_not :windows do
it "runs after at_exit" do
- output = ruby_exe(<<-RUBY, exit_status: nil)
+ output = ruby_exe(<<-RUBY, exit_status: :SIGKILL)
at_exit do
puts "hello"
$stdout.flush
@@ -107,7 +107,7 @@ describe "SignalException" do
end
it "cannot be trapped with Signal.trap" do
- ruby_exe(<<-RUBY, exit_status: nil)
+ ruby_exe(<<-RUBY, exit_status: :SIGPROF)
Signal.trap("PROF") {}
raise(SignalException, "PROF")
RUBY
@@ -116,7 +116,7 @@ describe "SignalException" do
end
it "self-signals for USR1" do
- ruby_exe("raise(SignalException, 'USR1')", exit_status: nil)
+ ruby_exe("raise(SignalException, 'USR1')", exit_status: :SIGUSR1)
$?.termsig.should == Signal.list.fetch('USR1')
end
end
diff --git a/spec/ruby/core/exception/syntax_error_spec.rb b/spec/ruby/core/exception/syntax_error_spec.rb
new file mode 100644
index 0000000000..6cc8522de3
--- /dev/null
+++ b/spec/ruby/core/exception/syntax_error_spec.rb
@@ -0,0 +1,27 @@
+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"
+
+ -> {
+ 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")
+
+ -> {
+ 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
+ end
+end
diff --git a/spec/ruby/core/exception/system_exit_spec.rb b/spec/ruby/core/exception/system_exit_spec.rb
index eef9faf271..d899844c4e 100644
--- a/spec/ruby/core/exception/system_exit_spec.rb
+++ b/spec/ruby/core/exception/system_exit_spec.rb
@@ -1,6 +1,48 @@
require_relative '../../spec_helper'
describe "SystemExit" do
+ describe "#initialize" do
+ it "accepts a status and message" do
+ exc = SystemExit.new(42, "message")
+ exc.status.should == 42
+ exc.message.should == "message"
+
+ exc = SystemExit.new(true, "message")
+ exc.status.should == 0
+ exc.message.should == "message"
+
+ exc = SystemExit.new(false, "message")
+ exc.status.should == 1
+ exc.message.should == "message"
+ end
+
+ it "accepts a status only" do
+ exc = SystemExit.new(42)
+ exc.status.should == 42
+ exc.message.should == "SystemExit"
+
+ exc = SystemExit.new(true)
+ exc.status.should == 0
+ exc.message.should == "SystemExit"
+
+ exc = SystemExit.new(false)
+ exc.status.should == 1
+ exc.message.should == "SystemExit"
+ end
+
+ it "accepts a message only" do
+ exc = SystemExit.new("message")
+ exc.status.should == 0
+ exc.message.should == "message"
+ end
+
+ it "accepts no arguments" do
+ exc = SystemExit.new
+ exc.status.should == 0
+ exc.message.should == "SystemExit"
+ end
+ end
+
it "sets the exit status and exits silently when raised" do
code = 'raise SystemExit.new(7)'
result = ruby_exe(code, args: "2>&1", exit_status: 7)
diff --git a/spec/ruby/core/exception/to_s_spec.rb b/spec/ruby/core/exception/to_s_spec.rb
index 4c4c7ab432..65c0d73a98 100644
--- a/spec/ruby/core/exception/to_s_spec.rb
+++ b/spec/ruby/core/exception/to_s_spec.rb
@@ -23,7 +23,7 @@ describe "NameError#to_s" do
begin
puts not_defined
rescue => exception
- exception.message.should =~ /undefined local variable or method `not_defined'/
+ exception.message.should =~ /undefined local variable or method [`']not_defined'/
end
end
diff --git a/spec/ruby/core/exception/top_level_spec.rb b/spec/ruby/core/exception/top_level_spec.rb
index b47648425e..cc961d06d5 100644
--- a/spec/ruby/core/exception/top_level_spec.rb
+++ b/spec/ruby/core/exception/top_level_spec.rb
@@ -2,30 +2,38 @@ require_relative '../../spec_helper'
describe "An Exception reaching the top level" do
it "is printed on STDERR" do
- ruby_exe('raise "foo"', args: "2>&1", exit_status: 1).should.include?("in `<main>': foo (RuntimeError)")
+ ruby_exe('raise "foo"', args: "2>&1", exit_status: 1).should =~ /in [`']<main>': foo \(RuntimeError\)/
end
it "the Exception#cause is printed to STDERR with backtraces" do
code = <<-RUBY
def raise_cause
- raise "the cause"
+ raise "the cause" # 2
end
def raise_wrapped
- raise "wrapped"
+ raise "wrapped" # 5
end
begin
- raise_cause
+ raise_cause # 8
rescue
- raise_wrapped
+ raise_wrapped # 10
end
RUBY
lines = ruby_exe(code, args: "2>&1", exit_status: 1).lines
- lines.reject! { |l| l.include?('rescue in') }
- lines.map! { |l| l.chomp[/:(in.+)/, 1] }
- lines.should == ["in `raise_wrapped': wrapped (RuntimeError)",
- "in `<main>'",
- "in `raise_cause': the cause (RuntimeError)",
- "in `<main>'"]
+
+ lines.map! { |l| l.chomp[/:(\d+:in.+)/, 1] }
+ lines[0].should =~ /\A5:in [`'](?:Object#)?raise_wrapped': wrapped \(RuntimeError\)\z/
+ if lines[1].include? 'rescue in'
+ # CRuby < 3.4 has an extra 'rescue in' backtrace entry
+ lines[1].should =~ /\A10:in [`']rescue in <main>'\z/
+ lines.delete_at 1
+ lines[1].should =~ /\A7:in [`']<main>'\z/
+ else
+ lines[1].should =~ /\A10:in [`']<main>'\z/
+ end
+ lines[2].should =~ /\A2:in [`'](?:Object#)?raise_cause': the cause \(RuntimeError\)\z/
+ lines[3].should =~ /\A8:in [`']<main>'\z/
+ lines.size.should == 4
end
describe "with a custom backtrace" do
@@ -42,4 +50,16 @@ describe "An Exception reaching the top level" do
EOS
end
end
+
+ describe "kills all threads and fibers, ensure clauses are only run for threads current fibers, not for suspended fibers" do
+ it "with ensure on the root fiber" do
+ file = fixture(__FILE__, "thread_fiber_ensure.rb")
+ ruby_exe(file, args: "2>&1", exit_status: 0).should == "current fiber ensure\n"
+ end
+
+ it "with ensure on non-root fiber" do
+ file = fixture(__FILE__, "thread_fiber_ensure_non_root_fiber.rb")
+ ruby_exe(file, args: "2>&1", exit_status: 0).should == "current fiber ensure\n"
+ end
+ end
end
diff --git a/spec/ruby/core/false/case_compare_spec.rb b/spec/ruby/core/false/case_compare_spec.rb
new file mode 100644
index 0000000000..0bd0ab44ae
--- /dev/null
+++ b/spec/ruby/core/false/case_compare_spec.rb
@@ -0,0 +1,14 @@
+require_relative '../../spec_helper'
+
+describe "FalseClass#===" do
+ it "returns true for false" do
+ (false === false).should == true
+ end
+
+ it "returns false for non-false object" do
+ (false === 0).should == false
+ (false === "").should == false
+ (false === Object).should == false
+ (false === nil).should == false
+ end
+end
diff --git a/spec/ruby/core/false/singleton_method_spec.rb b/spec/ruby/core/false/singleton_method_spec.rb
new file mode 100644
index 0000000000..738794b46c
--- /dev/null
+++ b/spec/ruby/core/false/singleton_method_spec.rb
@@ -0,0 +1,15 @@
+require_relative '../../spec_helper'
+
+describe "FalseClass#singleton_method" do
+ ruby_version_is '3.3' do
+ it "raises regardless of whether FalseClass defines the method" do
+ -> { false.singleton_method(:foo) }.should raise_error(NameError)
+ begin
+ def (false).foo; end
+ -> { false.singleton_method(:foo) }.should raise_error(NameError)
+ ensure
+ FalseClass.send(:remove_method, :foo)
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/false/to_s_spec.rb b/spec/ruby/core/false/to_s_spec.rb
index 4cae278891..62f67f6f55 100644
--- a/spec/ruby/core/false/to_s_spec.rb
+++ b/spec/ruby/core/false/to_s_spec.rb
@@ -5,13 +5,11 @@ describe "FalseClass#to_s" do
false.to_s.should == "false"
end
- ruby_version_is "2.7" do
- it "returns a frozen string" do
- false.to_s.should.frozen?
- end
+ it "returns a frozen string" do
+ false.to_s.should.frozen?
+ end
- it "always returns the same string" do
- false.to_s.should equal(false.to_s)
- end
+ it "always returns the same string" do
+ false.to_s.should equal(false.to_s)
end
end
diff --git a/spec/ruby/core/fiber/blocking_spec.rb b/spec/ruby/core/fiber/blocking_spec.rb
index 5ae5fbd577..ebefa116af 100644
--- a/spec/ruby/core/fiber/blocking_spec.rb
+++ b/spec/ruby/core/fiber/blocking_spec.rb
@@ -1,61 +1,76 @@
require_relative '../../spec_helper'
require_relative 'shared/blocking'
-ruby_version_is "3.0" do
- require "fiber"
+require "fiber"
- describe "Fiber.blocking?" do
- it_behaves_like :non_blocking_fiber, -> { Fiber.blocking? }
+describe "Fiber.blocking?" do
+ it_behaves_like :non_blocking_fiber, -> { Fiber.blocking? }
- context "when fiber is blocking" do
- context "root Fiber of the main thread" do
- it "returns 1 for blocking: true" do
+ context "when fiber is blocking" do
+ context "root Fiber of the main thread" do
+ it "returns 1 for blocking: true" do
+ fiber = Fiber.new(blocking: true) { Fiber.blocking? }
+ blocking = fiber.resume
+
+ blocking.should == 1
+ end
+ end
+
+ context "root Fiber of a new thread" do
+ it "returns 1 for blocking: true" do
+ thread = Thread.new do
fiber = Fiber.new(blocking: true) { Fiber.blocking? }
blocking = fiber.resume
blocking.should == 1
end
+
+ thread.join
end
+ end
+ end
+end
- context "root Fiber of a new thread" do
- it "returns 1 for blocking: true" do
- thread = Thread.new do
- fiber = Fiber.new(blocking: true) { Fiber.blocking? }
- blocking = fiber.resume
+describe "Fiber#blocking?" do
+ it_behaves_like :non_blocking_fiber, -> { Fiber.current.blocking? }
- blocking.should == 1
- end
+ context "when fiber is blocking" do
+ context "root Fiber of the main thread" do
+ it "returns true for blocking: true" do
+ fiber = Fiber.new(blocking: true) { Fiber.current.blocking? }
+ blocking = fiber.resume
- thread.join
- end
+ blocking.should == true
end
end
- end
-
- describe "Fiber#blocking?" do
- it_behaves_like :non_blocking_fiber, -> { Fiber.current.blocking? }
- context "when fiber is blocking" do
- context "root Fiber of the main thread" do
- it "returns true for blocking: true" do
+ context "root Fiber of a new thread" do
+ it "returns true for blocking: true" do
+ thread = Thread.new do
fiber = Fiber.new(blocking: true) { Fiber.current.blocking? }
blocking = fiber.resume
blocking.should == true
end
- end
- context "root Fiber of a new thread" do
- it "returns true for blocking: true" do
- thread = Thread.new do
- fiber = Fiber.new(blocking: true) { Fiber.current.blocking? }
- blocking = fiber.resume
+ thread.join
+ end
+ end
+ end
+end
- blocking.should == true
+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
-
- thread.join
end
+
+ blocking = fiber.resume
+ blocking.should == :blocking
end
end
end
diff --git a/spec/ruby/core/fiber/inspect_spec.rb b/spec/ruby/core/fiber/inspect_spec.rb
new file mode 100644
index 0000000000..f20a153fc2
--- /dev/null
+++ b/spec/ruby/core/fiber/inspect_spec.rb
@@ -0,0 +1,36 @@
+require_relative '../../spec_helper'
+require 'fiber'
+
+describe "Fiber#inspect" do
+ describe "status" do
+ it "is resumed for the root Fiber of a Thread" do
+ inspected = Thread.new { Fiber.current.inspect }.value
+ inspected.should =~ /\A#<Fiber:0x\h+ .*\(resumed\)>\z/
+ end
+
+ it "is created for a Fiber which did not run yet" do
+ inspected = Fiber.new {}.inspect
+ inspected.should =~ /\A#<Fiber:0x\h+ .+ \(created\)>\z/
+ end
+
+ it "is resumed for a Fiber which was resumed" do
+ inspected = Fiber.new { Fiber.current.inspect }.resume
+ inspected.should =~ /\A#<Fiber:0x\h+ .+ \(resumed\)>\z/
+ end
+
+ it "is resumed for a Fiber which was transferred" do
+ inspected = Fiber.new { Fiber.current.inspect }.transfer
+ inspected.should =~ /\A#<Fiber:0x\h+ .+ \(resumed\)>\z/
+ end
+
+ it "is suspended for a Fiber which was resumed and yielded" do
+ inspected = Fiber.new { Fiber.yield }.tap(&:resume).inspect
+ inspected.should =~ /\A#<Fiber:0x\h+ .+ \(suspended\)>\z/
+ end
+
+ it "is terminated for a Fiber which has terminated" do
+ inspected = Fiber.new {}.tap(&:resume).inspect
+ inspected.should =~ /\A#<Fiber:0x\h+ .+ \(terminated\)>\z/
+ end
+ end
+end
diff --git a/spec/ruby/core/fiber/kill_spec.rb b/spec/ruby/core/fiber/kill_spec.rb
new file mode 100644
index 0000000000..2f4c499280
--- /dev/null
+++ b/spec/ruby/core/fiber/kill_spec.rb
@@ -0,0 +1,90 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative '../../shared/kernel/raise'
+
+ruby_version_is "3.3" do
+ describe "Fiber#kill" do
+ it "kills a non-resumed fiber" do
+ fiber = Fiber.new{}
+
+ fiber.alive?.should == true
+
+ fiber.kill
+ fiber.alive?.should == false
+ end
+
+ it "kills a resumed fiber" do
+ fiber = Fiber.new{while true; Fiber.yield; end}
+ fiber.resume
+
+ fiber.alive?.should == true
+
+ fiber.kill
+ fiber.alive?.should == false
+ end
+
+ it "can kill itself" do
+ fiber = Fiber.new do
+ Fiber.current.kill
+ end
+
+ fiber.alive?.should == true
+
+ fiber.resume
+ fiber.alive?.should == false
+ end
+
+ it "kills a resumed fiber from a child" do
+ parent = Fiber.new do
+ child = Fiber.new do
+ parent.kill
+ parent.alive?.should == true
+ end
+
+ child.resume
+ end
+
+ parent.resume
+ parent.alive?.should == false
+ end
+
+ it "executes the ensure block" do
+ ensure_executed = false
+
+ fiber = Fiber.new do
+ while true; Fiber.yield; end
+ ensure
+ ensure_executed = true
+ end
+
+ fiber.resume
+ fiber.kill
+ ensure_executed.should == true
+ end
+
+ it "does not execute rescue block" do
+ rescue_executed = false
+
+ fiber = Fiber.new do
+ while true; Fiber.yield; end
+ rescue Exception
+ rescue_executed = true
+ end
+
+ fiber.resume
+ fiber.kill
+ rescue_executed.should == false
+ end
+
+ it "repeatedly kills a fiber" do
+ fiber = Fiber.new do
+ while true; Fiber.yield; end
+ ensure
+ while true; Fiber.yield; end
+ end
+
+ fiber.kill
+ fiber.alive?.should == false
+ end
+ end
+end
diff --git a/spec/ruby/core/fiber/raise_spec.rb b/spec/ruby/core/fiber/raise_spec.rb
index 2a465c8bfa..b3e021e636 100644
--- a/spec/ruby/core/fiber/raise_spec.rb
+++ b/spec/ruby/core/fiber/raise_spec.rb
@@ -2,120 +2,138 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
require_relative '../../shared/kernel/raise'
-ruby_version_is "2.7" do
- describe "Fiber#raise" do
- it_behaves_like :kernel_raise, :raise, FiberSpecs::NewFiberToRaise
+describe "Fiber#raise" do
+ it_behaves_like :kernel_raise, :raise, FiberSpecs::NewFiberToRaise
+end
+
+describe "Fiber#raise" do
+ it 'raises RuntimeError by default' do
+ -> { FiberSpecs::NewFiberToRaise.raise }.should raise_error(RuntimeError)
end
- describe "Fiber#raise" do
- it 'raises RuntimeError by default' do
- -> { FiberSpecs::NewFiberToRaise.raise }.should raise_error(RuntimeError)
- end
+ it "raises FiberError if Fiber is not born" do
+ fiber = Fiber.new { true }
+ -> { fiber.raise }.should raise_error(FiberError, "cannot raise exception on unborn fiber")
+ end
- it "raises FiberError if Fiber is not born" do
- fiber = Fiber.new { true }
- -> { fiber.raise }.should raise_error(FiberError, "cannot raise exception on unborn fiber")
- end
+ it "raises FiberError if Fiber is dead" do
+ fiber = Fiber.new { true }
+ fiber.resume
+ -> { fiber.raise }.should raise_error(FiberError, /dead fiber called|attempt to resume a terminated fiber/)
+ end
- it "raises FiberError if Fiber is dead" do
- fiber = Fiber.new { true }
- fiber.resume
- -> { fiber.raise }.should raise_error(FiberError, /dead fiber called|attempt to resume a terminated fiber/)
- end
+ it 'accepts error class' do
+ -> { FiberSpecs::NewFiberToRaise.raise FiberSpecs::CustomError }.should raise_error(FiberSpecs::CustomError)
+ end
- it 'accepts error class' do
- -> { FiberSpecs::NewFiberToRaise.raise FiberSpecs::CustomError }.should raise_error(FiberSpecs::CustomError)
- end
+ it 'accepts error message' do
+ -> { FiberSpecs::NewFiberToRaise.raise "error message" }.should raise_error(RuntimeError, "error message")
+ end
- it 'accepts error message' do
- -> { FiberSpecs::NewFiberToRaise.raise "error message" }.should raise_error(RuntimeError, "error message")
- end
+ it 'does not accept array of backtrace information only' do
+ -> { FiberSpecs::NewFiberToRaise.raise ['foo'] }.should raise_error(TypeError)
+ end
- it 'does not accept array of backtrace information only' do
- -> { FiberSpecs::NewFiberToRaise.raise ['foo'] }.should raise_error(TypeError)
- end
+ it 'does not accept integer' do
+ -> { FiberSpecs::NewFiberToRaise.raise 100 }.should raise_error(TypeError)
+ end
- it 'does not accept integer' do
- -> { FiberSpecs::NewFiberToRaise.raise 100 }.should raise_error(TypeError)
- end
+ it 'accepts error class with error message' do
+ -> { FiberSpecs::NewFiberToRaise.raise FiberSpecs::CustomError, 'test error' }.should raise_error(FiberSpecs::CustomError, 'test error')
+ end
- it 'accepts error class with error message' do
- -> { FiberSpecs::NewFiberToRaise.raise FiberSpecs::CustomError, 'test error' }.should raise_error(FiberSpecs::CustomError, 'test error')
- end
+ it 'accepts error class with with error message and backtrace information' do
+ -> {
+ FiberSpecs::NewFiberToRaise.raise FiberSpecs::CustomError, 'test error', ['foo', 'boo']
+ }.should raise_error(FiberSpecs::CustomError) { |e|
+ e.message.should == 'test error'
+ e.backtrace.should == ['foo', 'boo']
+ }
+ end
+
+ it 'does not accept only error message and backtrace information' do
+ -> { FiberSpecs::NewFiberToRaise.raise 'test error', ['foo', 'boo'] }.should raise_error(TypeError)
+ end
- it 'accepts error class with with error message and backtrace information' do
+ it "raises a FiberError if invoked from a different Thread" do
+ fiber = Fiber.new { Fiber.yield }
+ fiber.resume
+ Thread.new do
-> {
- FiberSpecs::NewFiberToRaise.raise FiberSpecs::CustomError, 'test error', ['foo', 'boo']
- }.should raise_error(FiberSpecs::CustomError) { |e|
- e.message.should == 'test error'
- e.backtrace.should == ['foo', 'boo']
- }
+ fiber.raise
+ }.should raise_error(FiberError, "fiber called across threads")
+ end.join
+ end
+
+ it "kills Fiber" do
+ fiber = Fiber.new { Fiber.yield :first; :second }
+ fiber.resume
+ -> { fiber.raise }.should raise_error
+ -> { fiber.resume }.should raise_error(FiberError, /dead fiber called|attempt to resume a terminated fiber/)
+ end
+
+ it "returns to calling fiber after raise" do
+ fiber_one = Fiber.new do
+ Fiber.yield :yield_one
+ :unreachable
end
- it 'does not accept only error message and backtrace information' do
- -> { FiberSpecs::NewFiberToRaise.raise 'test error', ['foo', 'boo'] }.should raise_error(TypeError)
+ fiber_two = Fiber.new do
+ results = []
+ results << fiber_one.resume
+ begin
+ fiber_one.raise
+ rescue
+ results << :rescued
+ end
+ results
end
- it "raises a FiberError if invoked from a different Thread" do
- fiber = Fiber.new { Fiber.yield }
- fiber.resume
- Thread.new do
- -> {
- fiber.raise
- }.should raise_error(FiberError, "fiber called across threads")
- end.join
+ fiber_two.resume.should == [:yield_one, :rescued]
+ end
+
+ ruby_version_is "3.4" do
+ it "raises on the resumed fiber" do
+ root_fiber = Fiber.current
+ f1 = Fiber.new { root_fiber.transfer }
+ f2 = Fiber.new { f1.resume }
+ f2.transfer
+
+ -> do
+ f2.raise(RuntimeError, "Expected error")
+ end.should raise_error(RuntimeError, "Expected error")
end
- it "kills Fiber" do
- fiber = Fiber.new { Fiber.yield :first; :second }
- fiber.resume
- -> { fiber.raise }.should raise_error
- -> { fiber.resume }.should raise_error(FiberError, /dead fiber called|attempt to resume a terminated fiber/)
+ it "raises on itself" do
+ -> do
+ Fiber.current.raise(RuntimeError, "Expected error")
+ end.should raise_error(RuntimeError, "Expected error")
end
- it "returns to calling fiber after raise" do
- fiber_one = Fiber.new do
- Fiber.yield :yield_one
- :unreachable
+ it "should raise on parent fiber" do
+ f2 = nil
+ f1 = Fiber.new do
+ # This is equivalent to Kernel#raise:
+ f2.raise(RuntimeError, "Expected error")
end
-
- fiber_two = Fiber.new do
- results = []
- results << fiber_one.resume
- begin
- fiber_one.raise
- rescue
- results << :rescued
- end
- results
+ f2 = Fiber.new do
+ f1.resume
end
- fiber_two.resume.should == [:yield_one, :rescued]
+ -> do
+ f2.resume
+ end.should raise_error(RuntimeError, "Expected error")
end
end
-
end
-ruby_version_is "2.7"..."3.0" do
- describe "Fiber#raise" do
- it "raises a FiberError if invoked on a transferring Fiber" do
- require "fiber"
- root = Fiber.current
- fiber = Fiber.new { root.transfer }
- fiber.transfer
- -> { fiber.raise }.should raise_error(FiberError, "cannot resume transferred Fiber")
- end
- end
-end
-ruby_version_is "3.0" do
- describe "Fiber#raise" do
- it "transfers and raises on a transferring fiber" do
- require "fiber"
- root = Fiber.current
- fiber = Fiber.new { root.transfer }
- fiber.transfer
- -> { fiber.raise "msg" }.should raise_error(RuntimeError, "msg")
- end
+describe "Fiber#raise" do
+ it "transfers and raises on a transferring fiber" do
+ require "fiber"
+ root = Fiber.current
+ fiber = Fiber.new { root.transfer }
+ fiber.transfer
+ -> { fiber.raise "msg" }.should raise_error(RuntimeError, "msg")
end
end
diff --git a/spec/ruby/core/fiber/resume_spec.rb b/spec/ruby/core/fiber/resume_spec.rb
index 273bc866af..ab9a6799ab 100644
--- a/spec/ruby/core/fiber/resume_spec.rb
+++ b/spec/ruby/core/fiber/resume_spec.rb
@@ -28,18 +28,9 @@ describe "Fiber#resume" do
fiber.resume :second
end
- ruby_version_is '3.0' do
- it "raises a FiberError if the Fiber tries to resume itself" do
- fiber = Fiber.new { fiber.resume }
- -> { fiber.resume }.should raise_error(FiberError, /current fiber/)
- end
- end
-
- ruby_version_is '' ... '3.0' do
- it "raises a FiberError if the Fiber tries to resume itself" do
- fiber = Fiber.new { fiber.resume }
- -> { fiber.resume }.should raise_error(FiberError, /double resume/)
- end
+ it "raises a FiberError if the Fiber tries to resume itself" do
+ fiber = Fiber.new { fiber.resume }
+ -> { fiber.resume }.should raise_error(FiberError, /current fiber/)
end
it "returns control to the calling Fiber if called from one" do
diff --git a/spec/ruby/core/fiber/storage_spec.rb b/spec/ruby/core/fiber/storage_spec.rb
new file mode 100644
index 0000000000..5c87ed5d41
--- /dev/null
+++ b/spec/ruby/core/fiber/storage_spec.rb
@@ -0,0 +1,158 @@
+require_relative '../../spec_helper'
+
+ruby_version_is "3.2" do
+ describe "Fiber.new(storage:)" do
+ it "creates a Fiber with the given storage" do
+ storage = {life: 42}
+ fiber = Fiber.new(storage: storage) { Fiber.current.storage }
+ fiber.resume.should == storage
+ end
+
+ it "creates a fiber with lazily initialized storage" do
+ Fiber.new(storage: nil) { Fiber[:x] = 10; Fiber.current.storage }.resume.should == {x: 10}
+ end
+
+ it "creates a fiber by inheriting the storage of the parent fiber" do
+ fiber = Fiber.new(storage: {life: 42}) do
+ Fiber.new { Fiber.current.storage }.resume
+ end
+ fiber.resume.should == {life: 42}
+ end
+
+ it "cannot create a fiber with non-hash storage" do
+ -> { Fiber.new(storage: 42) {} }.should raise_error(TypeError)
+ end
+
+ it "cannot create a fiber with a frozen hash as storage" do
+ -> { Fiber.new(storage: {life: 43}.freeze) {} }.should raise_error(FrozenError)
+ end
+
+ it "cannot create a fiber with a storage hash with non-symbol keys" do
+ -> { Fiber.new(storage: {life: 43, Object.new => 44}) {} }.should raise_error(TypeError)
+ end
+ end
+
+ describe "Fiber#storage" do
+ it "cannot be accessed from a different fiber" do
+ f = Fiber.new(storage: {life: 42}) { nil }
+ -> {
+ f.storage
+ }.should raise_error(ArgumentError, /Fiber storage can only be accessed from the Fiber it belongs to/)
+ end
+ end
+
+ describe "Fiber#storage=" do
+ it "can clear the storage of the fiber" do
+ fiber = Fiber.new(storage: {life: 42}) do
+ Fiber.current.storage = nil
+ Fiber[:x] = 10
+ Fiber.current.storage
+ end
+ fiber.resume.should == {x: 10}
+ end
+
+ it "can set the storage of the fiber" do
+ fiber = Fiber.new(storage: {life: 42}) do
+ Fiber.current.storage = {life: 43}
+ Fiber.current.storage
+ end
+ fiber.resume.should == {life: 43}
+ end
+
+ it "can't set the storage of the fiber to non-hash" do
+ -> { Fiber.current.storage = 42 }.should raise_error(TypeError)
+ end
+
+ it "can't set the storage of the fiber to a frozen hash" do
+ -> { Fiber.current.storage = {life: 43}.freeze }.should raise_error(FrozenError)
+ end
+
+ it "can't set the storage of the fiber to a hash with non-symbol keys" do
+ -> { Fiber.current.storage = {life: 43, Object.new => 44} }.should raise_error(TypeError)
+ end
+ end
+
+ describe "Fiber.[]" do
+ it "returns the value of the given key in the storage of the current fiber" do
+ Fiber.new(storage: {life: 42}) { Fiber[:life] }.resume.should == 42
+ end
+
+ it "returns nil if the key is not present in the storage of the current fiber" do
+ Fiber.new(storage: {life: 42}) { Fiber[:death] }.resume.should be_nil
+ end
+
+ it "returns nil if the current fiber has no storage" do
+ Fiber.new { Fiber[:life] }.resume.should be_nil
+ end
+
+ ruby_version_is "3.2.3" do
+ it "can use dynamically defined keys" do
+ key = :"#{self.class.name}#.#{self.object_id}"
+ Fiber.new { Fiber[key] = 42; Fiber[key] }.resume.should == 42
+ end
+
+ it "can't use invalid keys" do
+ invalid_keys = [Object.new, "Foo", 12]
+ invalid_keys.each do |key|
+ -> { Fiber[key] }.should raise_error(TypeError)
+ end
+ end
+ end
+
+ it "can access the storage of the parent fiber" do
+ f = Fiber.new(storage: {life: 42}) do
+ Fiber.new { Fiber[:life] }.resume
+ end
+ f.resume.should == 42
+ end
+
+ it "can't access the storage of the fiber with non-symbol keys" do
+ -> { Fiber[Object.new] }.should raise_error(TypeError)
+ end
+ end
+
+ describe "Fiber.[]=" do
+ it "sets the value of the given key in the storage of the current fiber" do
+ Fiber.new(storage: {life: 42}) { Fiber[:life] = 43; Fiber[:life] }.resume.should == 43
+ end
+
+ it "sets the value of the given key in the storage of the current fiber" do
+ Fiber.new(storage: {life: 42}) { Fiber[:death] = 43; Fiber[:death] }.resume.should == 43
+ end
+
+ it "sets the value of the given key in the storage of the current fiber" do
+ Fiber.new { Fiber[:life] = 43; Fiber[:life] }.resume.should == 43
+ end
+
+ it "does not overwrite the storage of the parent fiber" do
+ f = Fiber.new(storage: {life: 42}) do
+ Fiber.yield Fiber.new { Fiber[:life] = 43; Fiber[:life] }.resume
+ Fiber[:life]
+ end
+ f.resume.should == 43 # Value of the inner fiber
+ f.resume.should == 42 # Value of the outer fiber
+ end
+
+ it "can't access the storage of the fiber with non-symbol keys" do
+ -> { Fiber[Object.new] = 44 }.should raise_error(TypeError)
+ end
+
+ ruby_version_is "3.3" do
+ it "deletes the fiber storage key when assigning nil" do
+ Fiber.new(storage: {life: 42}) {
+ Fiber[:life] = nil
+ Fiber.current.storage
+ }.resume.should == {}
+ end
+ end
+ end
+
+ describe "Thread.new" do
+ it "creates a thread with the storage of the current fiber" do
+ fiber = Fiber.new(storage: {life: 42}) do
+ Thread.new { Fiber.current.storage }.value
+ end
+ fiber.resume.should == {life: 42}
+ end
+ end
+end
diff --git a/spec/ruby/core/file/absolute_path_spec.rb b/spec/ruby/core/file/absolute_path_spec.rb
index 9f39923472..315eead34f 100644
--- a/spec/ruby/core/file/absolute_path_spec.rb
+++ b/spec/ruby/core/file/absolute_path_spec.rb
@@ -1,54 +1,52 @@
require_relative '../../spec_helper'
-ruby_version_is "2.7" do
- describe "File.absolute_path?" do
- before :each do
- @abs = File.expand_path(__FILE__)
- end
+describe "File.absolute_path?" do
+ before :each do
+ @abs = File.expand_path(__FILE__)
+ end
- it "returns true if it's an absolute pathname" do
- File.absolute_path?(@abs).should be_true
- end
+ it "returns true if it's an absolute pathname" do
+ File.absolute_path?(@abs).should be_true
+ end
- it "returns false if it's a relative path" do
- File.absolute_path?(File.basename(__FILE__)).should be_false
- end
+ it "returns false if it's a relative path" do
+ File.absolute_path?(File.basename(__FILE__)).should be_false
+ end
- it "returns false if it's a tricky relative path" do
- File.absolute_path?("C:foo\\bar").should be_false
- end
+ it "returns false if it's a tricky relative path" do
+ File.absolute_path?("C:foo\\bar").should be_false
+ end
- it "does not expand '~' to a home directory." do
- File.absolute_path?('~').should be_false
- end
+ it "does not expand '~' to a home directory." do
+ File.absolute_path?('~').should be_false
+ end
- it "does not expand '~user' to a home directory." do
- path = File.dirname(@abs)
- Dir.chdir(path) do
- File.absolute_path?('~user').should be_false
- end
+ it "does not expand '~user' to a home directory." do
+ path = File.dirname(@abs)
+ Dir.chdir(path) do
+ File.absolute_path?('~user').should be_false
end
+ end
- it "calls #to_path on its argument" do
- mock = mock_to_path(File.expand_path(__FILE__))
+ it "calls #to_path on its argument" do
+ mock = mock_to_path(File.expand_path(__FILE__))
- File.absolute_path?(mock).should be_true
- end
+ File.absolute_path?(mock).should be_true
+ end
- platform_is_not :windows do
- it "takes into consideration the platform's root" do
- File.absolute_path?("C:\\foo\\bar").should be_false
- File.absolute_path?("C:/foo/bar").should be_false
- File.absolute_path?("/foo/bar\\baz").should be_true
- end
+ platform_is_not :windows do
+ it "takes into consideration the platform's root" do
+ File.absolute_path?("C:\\foo\\bar").should be_false
+ File.absolute_path?("C:/foo/bar").should be_false
+ File.absolute_path?("/foo/bar\\baz").should be_true
end
+ end
- platform_is :windows do
- it "takes into consideration the platform path separator(s)" do
- File.absolute_path?("C:\\foo\\bar").should be_true
- File.absolute_path?("C:/foo/bar").should be_true
- File.absolute_path?("/foo/bar\\baz").should be_false
- end
+ platform_is :windows do
+ it "takes into consideration the platform path separator(s)" do
+ File.absolute_path?("C:\\foo\\bar").should be_true
+ File.absolute_path?("C:/foo/bar").should be_true
+ File.absolute_path?("/foo/bar\\baz").should be_false
end
end
end
@@ -87,7 +85,7 @@ describe "File.absolute_path" do
end
it "accepts a second argument of a directory from which to resolve the path" do
- File.absolute_path(__FILE__, File.dirname(__FILE__)).should == @abs
+ File.absolute_path(__FILE__, __dir__).should == @abs
end
it "calls #to_path on its argument" do
diff --git a/spec/ruby/core/file/atime_spec.rb b/spec/ruby/core/file/atime_spec.rb
index cef07ba010..e47e70e5ac 100644
--- a/spec/ruby/core/file/atime_spec.rb
+++ b/spec/ruby/core/file/atime_spec.rb
@@ -16,10 +16,10 @@ describe "File.atime" do
end
platform_is :linux, :windows do
- platform_is_not :"powerpc64le-linux" do # https://bugs.ruby-lang.org/issues/17926
+ unless ENV.key?('TRAVIS') # https://bugs.ruby-lang.org/issues/17926
## NOTE also that some Linux systems disable atime (e.g. via mount params) for better filesystem speed.
it "returns the last access time for the named file with microseconds" do
- supports_subseconds = Integer(`stat -c%x '#{__FILE__}'`[/\.(\d+)/, 1], 10)
+ supports_subseconds = Integer(`stat -c%x '#{__FILE__}'`[/\.(\d{1,6})/, 1], 10)
if supports_subseconds != 0
expected_time = Time.at(Time.now.to_i + 0.123456)
File.utime expected_time, 0, @file
@@ -27,6 +27,9 @@ describe "File.atime" do
else
File.atime(__FILE__).usec.should == 0
end
+ rescue Errno::ENOENT => e
+ # Native Windows don't have stat command.
+ skip e.message
end
end
end
diff --git a/spec/ruby/core/file/ctime_spec.rb b/spec/ruby/core/file/ctime_spec.rb
index b16eb13c1e..718f26d5cc 100644
--- a/spec/ruby/core/file/ctime_spec.rb
+++ b/spec/ruby/core/file/ctime_spec.rb
@@ -16,12 +16,15 @@ describe "File.ctime" do
platform_is :linux, :windows do
it "returns the change time for the named file (the time at which directory information about the file was changed, not the file itself) with microseconds." do
- supports_subseconds = Integer(`stat -c%z '#{__FILE__}'`[/\.(\d+)/, 1], 10)
+ supports_subseconds = Integer(`stat -c%z '#{__FILE__}'`[/\.(\d{1,6})/, 1], 10)
if supports_subseconds != 0
File.ctime(__FILE__).usec.should > 0
else
File.ctime(__FILE__).usec.should == 0
end
+ rescue Errno::ENOENT => e
+ # Windows don't have stat command.
+ skip e.message
end
end
diff --git a/spec/ruby/core/file/dirname_spec.rb b/spec/ruby/core/file/dirname_spec.rb
index cf0f909f59..8dd6c4ca88 100644
--- a/spec/ruby/core/file/dirname_spec.rb
+++ b/spec/ruby/core/file/dirname_spec.rb
@@ -12,18 +12,33 @@ describe "File.dirname" do
end
ruby_version_is '3.1' 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)
+ 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
end
diff --git a/spec/ruby/core/file/exist_spec.rb b/spec/ruby/core/file/exist_spec.rb
index ddb5febcba..2633376880 100644
--- a/spec/ruby/core/file/exist_spec.rb
+++ b/spec/ruby/core/file/exist_spec.rb
@@ -4,3 +4,11 @@ require_relative '../../shared/file/exist'
describe "File.exist?" do
it_behaves_like :file_exist, :exist?, File
end
+
+ruby_version_is "3.2" do
+ describe "File.exists?" do
+ it "has been removed" do
+ File.should_not.respond_to?(:exists?)
+ end
+ end
+end
diff --git a/spec/ruby/core/file/expand_path_spec.rb b/spec/ruby/core/file/expand_path_spec.rb
index c31f885b92..1abcf93900 100644
--- a/spec/ruby/core/file/expand_path_spec.rb
+++ b/spec/ruby/core/file/expand_path_spec.rb
@@ -137,7 +137,7 @@ describe "File.expand_path" do
it "returns a String in the same encoding as the argument" do
Encoding.default_external = Encoding::SHIFT_JIS
- path = "./a".force_encoding Encoding::CP1251
+ path = "./a".dup.force_encoding Encoding::CP1251
File.expand_path(path).encoding.should equal(Encoding::CP1251)
weird_path = [222, 173, 190, 175].pack('C*')
diff --git a/spec/ruby/core/file/extname_spec.rb b/spec/ruby/core/file/extname_spec.rb
index e182ed44f2..d20cf813d9 100644
--- a/spec/ruby/core/file/extname_spec.rb
+++ b/spec/ruby/core/file/extname_spec.rb
@@ -33,14 +33,14 @@ describe "File.extname" do
end
describe "for a filename ending with a dot" do
- guard -> { platform_is :windows or ruby_version_is ""..."2.7" } do
+ platform_is :windows do
it "returns ''" do
File.extname(".foo.").should == ""
File.extname("foo.").should == ""
end
end
- guard -> { platform_is_not :windows and ruby_version_is "2.7" } do
+ platform_is_not :windows do
it "returns '.'" do
File.extname(".foo.").should == "."
File.extname("foo.").should == "."
diff --git a/spec/ruby/core/file/flock_spec.rb b/spec/ruby/core/file/flock_spec.rb
index 751e99d994..070d830bc4 100644
--- a/spec/ruby/core/file/flock_spec.rb
+++ b/spec/ruby/core/file/flock_spec.rb
@@ -30,7 +30,7 @@ describe "File#flock" do
it "returns false if trying to lock an exclusively locked file" do
@file.flock File::LOCK_EX
- ruby_exe(<<-END_OF_CODE, escape: true).should == "false"
+ ruby_exe(<<-END_OF_CODE).should == "false"
File.open('#{@name}', "w") do |f2|
print f2.flock(File::LOCK_EX | File::LOCK_NB).to_s
end
@@ -40,7 +40,7 @@ describe "File#flock" do
it "blocks if trying to lock an exclusively locked file" do
@file.flock File::LOCK_EX
- out = ruby_exe(<<-END_OF_CODE, escape: true)
+ out = ruby_exe(<<-END_OF_CODE)
running = false
t = Thread.new do
diff --git a/spec/ruby/core/file/lutime_spec.rb b/spec/ruby/core/file/lutime_spec.rb
index 1f0625f61e..0f6df42ea3 100644
--- a/spec/ruby/core/file/lutime_spec.rb
+++ b/spec/ruby/core/file/lutime_spec.rb
@@ -1,7 +1,12 @@
require_relative '../../spec_helper'
+require_relative 'shared/update_time'
-describe "File.lutime" do
- platform_is_not :windows do
+platform_is_not :windows do
+ describe "File.lutime" do
+ it_behaves_like :update_time, :lutime
+ end
+
+ describe "File.lutime" do
before :each do
@atime = Time.utc(2000)
@mtime = Time.utc(2001)
diff --git a/spec/ruby/core/file/mtime_spec.rb b/spec/ruby/core/file/mtime_spec.rb
index 8d47d3021a..0e9c95caee 100644
--- a/spec/ruby/core/file/mtime_spec.rb
+++ b/spec/ruby/core/file/mtime_spec.rb
@@ -16,14 +16,19 @@ describe "File.mtime" do
end
platform_is :linux, :windows do
- it "returns the modification Time of the file with microseconds" do
- supports_subseconds = Integer(`stat -c%y '#{__FILE__}'`[/\.(\d+)/, 1], 10)
- if supports_subseconds != 0
- expected_time = Time.at(Time.now.to_i + 0.123456)
- File.utime 0, expected_time, @filename
- File.mtime(@filename).usec.should == expected_time.usec
- else
- File.mtime(__FILE__).usec.should == 0
+ unless ENV.key?('TRAVIS') # https://bugs.ruby-lang.org/issues/17926
+ it "returns the modification Time of the file with microseconds" do
+ supports_subseconds = Integer(`stat -c%y '#{__FILE__}'`[/\.(\d{1,6})/, 1], 10)
+ if supports_subseconds != 0
+ expected_time = Time.at(Time.now.to_i + 0.123456)
+ File.utime 0, expected_time, @filename
+ File.mtime(@filename).usec.should == expected_time.usec
+ else
+ File.mtime(__FILE__).usec.should == 0
+ end
+ rescue Errno::ENOENT => e
+ # Windows don't have stat command.
+ skip e.message
end
end
end
diff --git a/spec/ruby/core/file/new_spec.rb b/spec/ruby/core/file/new_spec.rb
index 004f78503a..1e82a070b1 100644
--- a/spec/ruby/core/file/new_spec.rb
+++ b/spec/ruby/core/file/new_spec.rb
@@ -78,13 +78,29 @@ describe "File.new" do
File.should.exist?(@file)
end
+ it "returns a new read-only File when mode is not specified" do
+ @fh = File.new(@file)
+
+ -> { @fh.puts("test") }.should raise_error(IOError)
+ @fh.read.should == ""
+ File.should.exist?(@file)
+ end
+
+ it "returns a new read-only File when mode is not specified but flags option is present" do
+ @fh = File.new(@file, flags: File::CREAT)
+
+ -> { @fh.puts("test") }.should raise_error(IOError)
+ @fh.read.should == ""
+ File.should.exist?(@file)
+ end
+
it "creates a new file when use File::EXCL mode" do
@fh = File.new(@file, File::EXCL)
@fh.should be_kind_of(File)
File.should.exist?(@file)
end
- it "raises an Errorno::EEXIST if the file exists when create a new file with File::CREAT|File::EXCL" do
+ it "raises an Errno::EEXIST if the file exists when create a new file with File::CREAT|File::EXCL" do
-> { @fh = File.new(@file, File::CREAT|File::EXCL) }.should raise_error(Errno::EEXIST)
end
@@ -112,13 +128,32 @@ describe "File.new" do
File.should.exist?(@file)
end
-
it "creates a new file when use File::WRONLY|File::TRUNC mode" do
@fh = File.new(@file, File::WRONLY|File::TRUNC)
@fh.should be_kind_of(File)
File.should.exist?(@file)
end
+ it "returns a new read-only File when use File::RDONLY|File::CREAT mode" do
+ @fh = File.new(@file, File::RDONLY|File::CREAT)
+ @fh.should be_kind_of(File)
+ File.should.exist?(@file)
+
+ # it's read-only
+ -> { @fh.puts("test") }.should raise_error(IOError)
+ @fh.read.should == ""
+ end
+
+ it "returns a new read-only File when use File::CREAT mode" do
+ @fh = File.new(@file, File::CREAT)
+ @fh.should be_kind_of(File)
+ File.should.exist?(@file)
+
+ # it's read-only
+ -> { @fh.puts("test") }.should raise_error(IOError)
+ @fh.read.should == ""
+ end
+
it "coerces filename using to_str" do
name = mock("file")
name.should_receive(:to_str).and_return(@file)
@@ -133,6 +168,32 @@ describe "File.new" do
File.should.exist?(@file)
end
+ it "accepts options as a keyword argument" do
+ @fh = File.new(@file, 'w', 0755, flags: @flags)
+ @fh.should be_kind_of(File)
+ @fh.close
+
+ -> {
+ @fh = File.new(@file, 'w', 0755, {flags: @flags})
+ }.should raise_error(ArgumentError, "wrong number of arguments (given 4, expected 1..3)")
+ end
+
+ it "bitwise-ORs mode and flags option" do
+ -> {
+ @fh = File.new(@file, 'w', flags: File::EXCL)
+ }.should raise_error(Errno::EEXIST, /File exists/)
+
+ -> {
+ @fh = File.new(@file, mode: 'w', flags: File::EXCL)
+ }.should raise_error(Errno::EEXIST, /File exists/)
+ end
+
+ it "does not use the given block and warns to use File::open" do
+ -> {
+ @fh = File.new(@file) { raise }
+ }.should complain(/warning: File::new\(\) does not take block; use File::open\(\) instead/)
+ end
+
it "raises a TypeError if the first parameter can't be coerced to a string" do
-> { File.new(true) }.should raise_error(TypeError)
-> { File.new(false) }.should raise_error(TypeError)
diff --git a/spec/ruby/core/file/open_spec.rb b/spec/ruby/core/file/open_spec.rb
index c7dd34d5c6..6bfc16bbf9 100644
--- a/spec/ruby/core/file/open_spec.rb
+++ b/spec/ruby/core/file/open_spec.rb
@@ -314,7 +314,7 @@ describe "File.open" do
end
end
- it "raises an IOError when read in a block opened with File::RDONLY|File::APPEND mode" do
+ it "raises an IOError when write in a block opened with File::RDONLY|File::APPEND mode" do
-> {
File.open(@file, File::RDONLY|File::APPEND ) do |f|
f.puts("writing")
@@ -354,7 +354,7 @@ describe "File.open" do
end
end
- it "raises an Errorno::EEXIST if the file exists when open with File::CREAT|File::EXCL" do
+ it "raises an Errno::EEXIST if the file exists when open with File::CREAT|File::EXCL" do
-> {
File.open(@file, File::CREAT|File::EXCL) do |f|
f.puts("writing")
@@ -423,7 +423,7 @@ describe "File.open" do
}.should raise_error(IOError)
end
- it "raises an Errorno::EEXIST if the file exists when open with File::RDONLY|File::TRUNC" do
+ it "raises an Errno::EEXIST if the file exists when open with File::RDONLY|File::TRUNC" do
-> {
File.open(@file, File::RDONLY|File::TRUNC) do |f|
f.puts("writing").should == nil
@@ -441,7 +441,7 @@ describe "File.open" do
}.should raise_error(Errno::EINVAL)
end
- it "raises an Errorno::EEXIST if the file exists when open with File::RDONLY|File::TRUNC" do
+ it "raises an Errno::EEXIST if the file exists when open with File::RDONLY|File::TRUNC" do
-> {
File.open(@file, File::RDONLY|File::TRUNC) do |f|
f.puts("writing").should == nil
@@ -494,6 +494,14 @@ describe "File.open" do
File.open(@file, "w") { |f| f.puts "testing" }
File.size(@file).should > 0
File.open(@file, "rb+") do |f|
+ f.binmode?.should == true
+ f.external_encoding.should == Encoding::ASCII_8BIT
+ f.pos.should == 0
+ f.should_not.eof?
+ end
+ File.open(@file, "r+b") do |f|
+ f.binmode?.should == true
+ f.external_encoding.should == Encoding::ASCII_8BIT
f.pos.should == 0
f.should_not.eof?
end
@@ -557,6 +565,15 @@ describe "File.open" do
File.open(@file, 'wb+') {|f| f.external_encoding.should == Encoding::BINARY}
end
+ it "accepts options as a keyword argument" do
+ @fh = File.open(@file, 'w', 0755, flags: File::CREAT)
+ @fh.should be_an_instance_of(File)
+
+ -> {
+ File.open(@file, 'w', 0755, {flags: File::CREAT})
+ }.should raise_error(ArgumentError, "wrong number of arguments (given 4, expected 1..3)")
+ end
+
it "uses the second argument as an options Hash" do
@fh = File.open(@file, mode: "r")
@fh.should be_an_instance_of(File)
diff --git a/spec/ruby/core/file/realpath_spec.rb b/spec/ruby/core/file/realpath_spec.rb
index bd27e09da6..bd25bfdecf 100644
--- a/spec/ruby/core/file/realpath_spec.rb
+++ b/spec/ruby/core/file/realpath_spec.rb
@@ -54,6 +54,10 @@ platform_is_not :windows do
File.realpath(@relative_symlink).should == @file
end
+ it "removes the file element when going one level up" do
+ File.realpath('../', @file).should == @real_dir
+ end
+
it "raises an Errno::ELOOP if the symlink points to itself" do
File.unlink @link
File.symlink(@link, @link)
diff --git a/spec/ruby/core/file/shared/fnmatch.rb b/spec/ruby/core/file/shared/fnmatch.rb
index 00682bb64c..db4b5c5d8c 100644
--- a/spec/ruby/core/file/shared/fnmatch.rb
+++ b/spec/ruby/core/file/shared/fnmatch.rb
@@ -102,6 +102,7 @@ describe :file_fnmatch, shared: true do
it "matches ranges of characters using exclusive bracket expression (e.g. [^t] or [!t])" do
File.send(@method, 'ca[^t]', 'cat').should == false
+ File.send(@method, 'ca[^t]', 'cas').should == true
File.send(@method, 'ca[!t]', 'cat').should == false
end
@@ -125,6 +126,13 @@ describe :file_fnmatch, shared: true do
end
end
+ it "matches wildcard with characters when flags includes FNM_PATHNAME" do
+ File.send(@method, '*a', 'aa', File::FNM_PATHNAME).should == true
+ File.send(@method, 'a*', 'aa', File::FNM_PATHNAME).should == true
+ File.send(@method, 'a*', 'aaa', File::FNM_PATHNAME).should == true
+ File.send(@method, '*a', 'aaa', File::FNM_PATHNAME).should == true
+ end
+
it "does not match '/' characters with ? or * when flags includes FNM_PATHNAME" do
File.send(@method, '?', '/', File::FNM_PATHNAME).should == false
File.send(@method, '*', '/', File::FNM_PATHNAME).should == false
@@ -159,15 +167,25 @@ describe :file_fnmatch, shared: true do
end
it "does not match leading periods in filenames with wildcards by default" do
- File.send(@method, '*', '.profile').should == false
- File.send(@method, '*', 'home/.profile').should == true
- File.send(@method, '*/*', 'home/.profile').should == true
- File.send(@method, '*/*', 'dave/.profile', File::FNM_PATHNAME).should == false
+ File.should_not.send(@method, '*', '.profile')
+ File.should.send(@method, '*', 'home/.profile')
+ File.should.send(@method, '*/*', 'home/.profile')
+ File.should_not.send(@method, '*/*', 'dave/.profile', File::FNM_PATHNAME)
end
- it "matches patterns with leading periods to dotfiles by default" do
+ it "matches patterns with leading periods to dotfiles" do
File.send(@method, '.*', '.profile').should == true
+ File.send(@method, '.*', '.profile', File::FNM_PATHNAME).should == true
File.send(@method, ".*file", "nondotfile").should == false
+ File.send(@method, ".*file", "nondotfile", File::FNM_PATHNAME).should == false
+ end
+
+ it "does not match directories with leading periods by default with FNM_PATHNAME" do
+ File.send(@method, '.*', '.directory/nondotfile', File::FNM_PATHNAME).should == false
+ File.send(@method, '.*', '.directory/.profile', File::FNM_PATHNAME).should == false
+ File.send(@method, '.*', 'foo/.directory/nondotfile', File::FNM_PATHNAME).should == false
+ File.send(@method, '.*', 'foo/.directory/.profile', File::FNM_PATHNAME).should == false
+ File.send(@method, '**/.dotfile', '.dotsubdir/.dotfile', File::FNM_PATHNAME).should == false
end
it "matches leading periods in filenames when flags includes FNM_DOTMATCH" do
@@ -221,6 +239,33 @@ describe :file_fnmatch, shared: true do
File.send(@method, pattern, 'a/.b/c/foo', File::FNM_PATHNAME | File::FNM_DOTMATCH).should be_true
end
+ it "has special handling for ./ when using * and FNM_PATHNAME" do
+ File.send(@method, './*', '.', File::FNM_PATHNAME).should be_false
+ File.send(@method, './*', './', File::FNM_PATHNAME).should be_true
+ File.send(@method, './*/', './', File::FNM_PATHNAME).should be_false
+ File.send(@method, './**', './', File::FNM_PATHNAME).should be_true
+ File.send(@method, './**/', './', File::FNM_PATHNAME).should be_true
+ File.send(@method, './*', '.', File::FNM_PATHNAME | File::FNM_DOTMATCH).should be_false
+ File.send(@method, './*', './', File::FNM_PATHNAME | File::FNM_DOTMATCH).should be_true
+ File.send(@method, './*/', './', File::FNM_PATHNAME | File::FNM_DOTMATCH).should be_false
+ File.send(@method, './**', './', File::FNM_PATHNAME | File::FNM_DOTMATCH).should be_true
+ File.send(@method, './**/', './', File::FNM_PATHNAME | File::FNM_DOTMATCH).should be_true
+ end
+
+ it "matches **/* with FNM_PATHNAME to recurse directories" do
+ File.send(@method, 'nested/**/*', 'nested/subdir', File::FNM_PATHNAME).should be_true
+ File.send(@method, 'nested/**/*', 'nested/subdir/file', File::FNM_PATHNAME).should be_true
+ File.send(@method, 'nested/**/*', 'nested/.dotsubdir', File::FNM_PATHNAME | File::FNM_DOTMATCH).should be_true
+ File.send(@method, 'nested/**/*', 'nested/.dotsubir/.dotfile', File::FNM_PATHNAME | File::FNM_DOTMATCH).should be_true
+ end
+
+ it "matches ** with FNM_PATHNAME only in current directory" do
+ File.send(@method, 'nested/**', 'nested/subdir', File::FNM_PATHNAME).should be_true
+ File.send(@method, 'nested/**', 'nested/subdir/file', File::FNM_PATHNAME).should be_false
+ File.send(@method, 'nested/**', 'nested/.dotsubdir', File::FNM_PATHNAME | File::FNM_DOTMATCH).should be_true
+ File.send(@method, 'nested/**', 'nested/.dotsubir/.dotfile', File::FNM_PATHNAME | File::FNM_DOTMATCH).should be_false
+ end
+
it "accepts an object that has a #to_path method" do
File.send(@method, '\*', mock_to_path('a')).should == false
end
diff --git a/spec/ruby/core/file/shared/path.rb b/spec/ruby/core/file/shared/path.rb
index 0a5abe33f0..aa2a64cf25 100644
--- a/spec/ruby/core/file/shared/path.rb
+++ b/spec/ruby/core/file/shared/path.rb
@@ -1,7 +1,7 @@
describe :file_path, shared: true do
before :each do
- @name = "file_to_path"
- @path = tmp(@name)
+ @path = tmp("file_to_path")
+ @name = File.basename(@path)
touch @path
end
@@ -78,13 +78,15 @@ describe :file_path, shared: true do
rm_r @dir
end
- 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)
+ 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
- rescue Errno::EOPNOTSUPP, Errno::EINVAL, Errno::EISDIR
- skip "no support from the filesystem"
end
end
end
diff --git a/spec/ruby/core/file/shared/update_time.rb b/spec/ruby/core/file/shared/update_time.rb
new file mode 100644
index 0000000000..9c063a8e93
--- /dev/null
+++ b/spec/ruby/core/file/shared/update_time.rb
@@ -0,0 +1,105 @@
+describe :update_time, shared: true do
+ before :all do
+ @time_is_float = platform_is :windows
+ end
+
+ before :each do
+ @atime = Time.now
+ @mtime = Time.now
+ @file1 = tmp("specs_file_utime1")
+ @file2 = tmp("specs_file_utime2")
+ touch @file1
+ touch @file2
+ end
+
+ after :each do
+ rm_r @file1, @file2
+ end
+
+ it "sets the access and modification time of each file" do
+ File.send(@method, @atime, @mtime, @file1, @file2)
+
+ if @time_is_float
+ File.atime(@file1).should be_close(@atime, 0.0001)
+ File.mtime(@file1).should be_close(@mtime, 0.0001)
+ File.atime(@file2).should be_close(@atime, 0.0001)
+ File.mtime(@file2).should be_close(@mtime, 0.0001)
+ else
+ File.atime(@file1).to_i.should be_close(@atime.to_i, TIME_TOLERANCE)
+ File.mtime(@file1).to_i.should be_close(@mtime.to_i, TIME_TOLERANCE)
+ File.atime(@file2).to_i.should be_close(@atime.to_i, TIME_TOLERANCE)
+ File.mtime(@file2).to_i.should be_close(@mtime.to_i, TIME_TOLERANCE)
+ end
+ end
+
+ it "uses the current times if two nil values are passed" do
+ tn = Time.now
+ File.send(@method, nil, nil, @file1, @file2)
+
+ if @time_is_float
+ File.atime(@file1).should be_close(tn, 0.050)
+ File.mtime(@file1).should be_close(tn, 0.050)
+ File.atime(@file2).should be_close(tn, 0.050)
+ File.mtime(@file2).should be_close(tn, 0.050)
+ else
+ File.atime(@file1).to_i.should be_close(Time.now.to_i, TIME_TOLERANCE)
+ File.mtime(@file1).to_i.should be_close(Time.now.to_i, TIME_TOLERANCE)
+ File.atime(@file2).to_i.should be_close(Time.now.to_i, TIME_TOLERANCE)
+ File.mtime(@file2).to_i.should be_close(Time.now.to_i, TIME_TOLERANCE)
+ end
+ end
+
+ it "accepts an object that has a #to_path method" do
+ File.send(@method, @atime, @mtime, mock_to_path(@file1), mock_to_path(@file2))
+ end
+
+ it "accepts numeric atime and mtime arguments" do
+ if @time_is_float
+ File.send(@method, @atime.to_f, @mtime.to_f, @file1, @file2)
+
+ File.atime(@file1).should be_close(@atime, 0.0001)
+ File.mtime(@file1).should be_close(@mtime, 0.0001)
+ File.atime(@file2).should be_close(@atime, 0.0001)
+ File.mtime(@file2).should be_close(@mtime, 0.0001)
+ else
+ File.send(@method, @atime.to_i, @mtime.to_i, @file1, @file2)
+
+ File.atime(@file1).to_i.should be_close(@atime.to_i, TIME_TOLERANCE)
+ File.mtime(@file1).to_i.should be_close(@mtime.to_i, TIME_TOLERANCE)
+ File.atime(@file2).to_i.should be_close(@atime.to_i, TIME_TOLERANCE)
+ File.mtime(@file2).to_i.should be_close(@mtime.to_i, TIME_TOLERANCE)
+ end
+ end
+
+ it "may set nanosecond precision" do
+ t = Time.utc(2007, 11, 1, 15, 25, 0, 123456.789r)
+ File.send(@method, t, t, @file1)
+
+ File.atime(@file1).nsec.should.between?(0, 123500000)
+ File.mtime(@file1).nsec.should.between?(0, 123500000)
+ end
+
+ it "returns the number of filenames in the arguments" do
+ File.send(@method, @atime.to_f, @mtime.to_f, @file1, @file2).should == 2
+ end
+
+ platform_is :linux do
+ platform_is wordsize: 64 do
+ it "allows Time instances in the far future to set mtime and atime (but some filesystems limit it up to 2446-05-10 or 2038-01-19 or 2486-07-02)" do
+ # https://ext4.wiki.kernel.org/index.php/Ext4_Disk_Layout#Inode_Timestamps
+ # "Therefore, timestamps should not overflow until May 2446."
+ # https://lwn.net/Articles/804382/
+ # "On-disk timestamps hitting the y2038 limit..."
+ # The problem seems to be being improved, but currently it actually fails on XFS on RHEL8
+ # https://rubyci.org/logs/rubyci.s3.amazonaws.com/rhel8/ruby-master/log/20201112T123004Z.fail.html.gz
+ # Amazon Linux 2023 returns 2486-07-02 in this example
+ # http://rubyci.s3.amazonaws.com/amazon2023/ruby-master/log/20230322T063004Z.fail.html.gz
+ time = Time.at(1<<44)
+ File.send(@method, time, time, @file1)
+
+ [559444, 2486, 2446, 2038].should.include? File.atime(@file1).year
+ [559444, 2486, 2446, 2038].should.include? File.mtime(@file1).year
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/file/utime_spec.rb b/spec/ruby/core/file/utime_spec.rb
index 59eef20c66..d87626be50 100644
--- a/spec/ruby/core/file/utime_spec.rb
+++ b/spec/ruby/core/file/utime_spec.rb
@@ -1,96 +1,6 @@
require_relative '../../spec_helper'
+require_relative 'shared/update_time'
describe "File.utime" do
-
- before :all do
- @time_is_float = platform_is :windows
- end
-
- before :each do
- @atime = Time.now
- @mtime = Time.now
- @file1 = tmp("specs_file_utime1")
- @file2 = tmp("specs_file_utime2")
- touch @file1
- touch @file2
- end
-
- after :each do
- rm_r @file1, @file2
- end
-
- it "sets the access and modification time of each file" do
- File.utime(@atime, @mtime, @file1, @file2)
- if @time_is_float
- File.atime(@file1).should be_close(@atime, 0.0001)
- File.mtime(@file1).should be_close(@mtime, 0.0001)
- File.atime(@file2).should be_close(@atime, 0.0001)
- File.mtime(@file2).should be_close(@mtime, 0.0001)
- else
- File.atime(@file1).to_i.should be_close(@atime.to_i, TIME_TOLERANCE)
- File.mtime(@file1).to_i.should be_close(@mtime.to_i, TIME_TOLERANCE)
- File.atime(@file2).to_i.should be_close(@atime.to_i, TIME_TOLERANCE)
- File.mtime(@file2).to_i.should be_close(@mtime.to_i, TIME_TOLERANCE)
- end
- end
-
- it "uses the current times if two nil values are passed" do
- tn = Time.now
- File.utime(nil, nil, @file1, @file2)
- if @time_is_float
- File.atime(@file1).should be_close(tn, 0.050)
- File.mtime(@file1).should be_close(tn, 0.050)
- File.atime(@file2).should be_close(tn, 0.050)
- File.mtime(@file2).should be_close(tn, 0.050)
- else
- File.atime(@file1).to_i.should be_close(Time.now.to_i, TIME_TOLERANCE)
- File.mtime(@file1).to_i.should be_close(Time.now.to_i, TIME_TOLERANCE)
- File.atime(@file2).to_i.should be_close(Time.now.to_i, TIME_TOLERANCE)
- File.mtime(@file2).to_i.should be_close(Time.now.to_i, TIME_TOLERANCE)
- end
- end
-
- it "accepts an object that has a #to_path method" do
- File.utime(@atime, @mtime, mock_to_path(@file1), mock_to_path(@file2))
- end
-
- it "accepts numeric atime and mtime arguments" do
- if @time_is_float
- File.utime(@atime.to_f, @mtime.to_f, @file1, @file2)
- File.atime(@file1).should be_close(@atime, 0.0001)
- File.mtime(@file1).should be_close(@mtime, 0.0001)
- File.atime(@file2).should be_close(@atime, 0.0001)
- File.mtime(@file2).should be_close(@mtime, 0.0001)
- else
- File.utime(@atime.to_i, @mtime.to_i, @file1, @file2)
- File.atime(@file1).to_i.should be_close(@atime.to_i, TIME_TOLERANCE)
- File.mtime(@file1).to_i.should be_close(@mtime.to_i, TIME_TOLERANCE)
- File.atime(@file2).to_i.should be_close(@atime.to_i, TIME_TOLERANCE)
- File.mtime(@file2).to_i.should be_close(@mtime.to_i, TIME_TOLERANCE)
- end
- end
-
- it "may set nanosecond precision" do
- t = Time.utc(2007, 11, 1, 15, 25, 0, 123456.789r)
- File.utime(t, t, @file1)
- File.atime(@file1).nsec.should.between?(0, 123500000)
- File.mtime(@file1).nsec.should.between?(0, 123500000)
- end
-
- platform_is :linux do
- platform_is wordsize: 64 do
- it "allows Time instances in the far future to set mtime and atime (but some filesystems limit it up to 2446-05-10 or 2038-01-19)" do
- # https://ext4.wiki.kernel.org/index.php/Ext4_Disk_Layout#Inode_Timestamps
- # "Therefore, timestamps should not overflow until May 2446."
- # https://lwn.net/Articles/804382/
- # "On-disk timestamps hitting the y2038 limit..."
- # The problem seems to be being improved, but currently it actually fails on XFS on RHEL8
- # https://rubyci.org/logs/rubyci.s3.amazonaws.com/rhel8/ruby-master/log/20201112T123004Z.fail.html.gz
- time = Time.at(1<<44)
- File.utime(time, time, @file1)
- [559444, 2446, 2038].should.include? File.atime(@file1).year
- [559444, 2446, 2038].should.include? File.mtime(@file1).year
- end
- end
- end
+ it_behaves_like :update_time, :utime
end
diff --git a/spec/ruby/core/filetest/exist_spec.rb b/spec/ruby/core/filetest/exist_spec.rb
index 4d14bea231..a95d3f91a1 100644
--- a/spec/ruby/core/filetest/exist_spec.rb
+++ b/spec/ruby/core/filetest/exist_spec.rb
@@ -4,3 +4,11 @@ require_relative '../../shared/file/exist'
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
+ end
+end
diff --git a/spec/ruby/core/float/coerce_spec.rb b/spec/ruby/core/float/coerce_spec.rb
index ea108f3303..baa831dcf6 100644
--- a/spec/ruby/core/float/coerce_spec.rb
+++ b/spec/ruby/core/float/coerce_spec.rb
@@ -9,10 +9,10 @@ describe "Float#coerce" do
1.0.coerce(3.14).should == [3.14, 1.0]
a, b = -0.0.coerce(bignum_value)
- a.should be_close(9223372036854775808.0, TOLERANCE)
+ a.should be_close(18446744073709551616.0, TOLERANCE)
b.should be_close(-0.0, TOLERANCE)
a, b = 1.0.coerce(bignum_value)
- a.should be_close(9223372036854775808.0, TOLERANCE)
+ a.should be_close(18446744073709551616.0, TOLERANCE)
b.should be_close(1.0, TOLERANCE)
end
end
diff --git a/spec/ruby/core/float/comparison_spec.rb b/spec/ruby/core/float/comparison_spec.rb
index 53e7ec332a..1373b3a1fb 100644
--- a/spec/ruby/core/float/comparison_spec.rb
+++ b/spec/ruby/core/float/comparison_spec.rb
@@ -7,9 +7,25 @@ describe "Float#<=>" do
((bignum_value*1.1) <=> bignum_value).should == 1
end
- it "returns nil when either argument is NaN" do
- (nan_value <=> 71.2).should be_nil
- (1771.176 <=> nan_value).should be_nil
+ it "returns nil if one side is NaN" do
+ [1.0, 42, bignum_value].each { |n|
+ (nan_value <=> n).should == nil
+ (n <=> nan_value).should == nil
+ }
+ end
+
+ it "handles positive infinity" do
+ [1.0, 42, bignum_value].each { |n|
+ (infinity_value <=> n).should == 1
+ (n <=> infinity_value).should == -1
+ }
+ end
+
+ it "handles negative infinity" do
+ [1.0, 42, bignum_value].each { |n|
+ (-infinity_value <=> n).should == -1
+ (n <=> -infinity_value).should == 1
+ }
end
it "returns nil when the given argument is not a Float" do
@@ -49,21 +65,10 @@ describe "Float#<=>" do
}.should raise_error(TypeError, "coerce must return [x, y]")
end
- # The 4 tests below are taken from matz's revision 23730 for Ruby trunk
- #
- it "returns 1 when self is Infinity and other is an Integer" do
+ it "returns the correct result when one side is infinite" do
(infinity_value <=> Float::MAX.to_i*2).should == 1
- end
-
- it "returns -1 when self is negative and other is Infinity" do
(-Float::MAX.to_i*2 <=> infinity_value).should == -1
- end
-
- it "returns -1 when self is -Infinity and other is negative" do
(-infinity_value <=> -Float::MAX.to_i*2).should == -1
- end
-
- it "returns 1 when self is negative and other is -Infinity" do
(-Float::MAX.to_i*2 <=> -infinity_value).should == 1
end
diff --git a/spec/ruby/core/float/divide_spec.rb b/spec/ruby/core/float/divide_spec.rb
index d8f71a6b98..72ab7527bd 100644
--- a/spec/ruby/core/float/divide_spec.rb
+++ b/spec/ruby/core/float/divide_spec.rb
@@ -36,4 +36,8 @@ describe "Float#/" do
-> { 13.0 / "10" }.should raise_error(TypeError)
-> { 13.0 / :symbol }.should raise_error(TypeError)
end
+
+ it "divides correctly by Rational numbers" do
+ (1.2345678901234567 / Rational(1, 10000000000000000000)).should == 1.2345678901234567e+19
+ end
end
diff --git a/spec/ruby/core/float/divmod_spec.rb b/spec/ruby/core/float/divmod_spec.rb
index ec55dd3681..dad45a9b89 100644
--- a/spec/ruby/core/float/divmod_spec.rb
+++ b/spec/ruby/core/float/divmod_spec.rb
@@ -10,7 +10,7 @@ describe "Float#divmod" do
values[1].should be_close(2.8284, TOLERANCE)
values = -1.0.divmod(bignum_value)
values[0].should eql(-1)
- values[1].should be_close(9223372036854775808.000, TOLERANCE)
+ values[1].should be_close(18446744073709551616.0, TOLERANCE)
values = -1.0.divmod(1)
values[0].should eql(-1)
values[1].should eql(0.0)
@@ -23,7 +23,7 @@ describe "Float#divmod" do
# Behaviour established as correct in r23953
it "raises a FloatDomainError if other is NaN" do
- -> { 1.divmod(nan_value) }.should raise_error(FloatDomainError)
+ -> { 1.0.divmod(nan_value) }.should raise_error(FloatDomainError)
end
# Behaviour established as correct in r23953
diff --git a/spec/ruby/core/float/gt_spec.rb b/spec/ruby/core/float/gt_spec.rb
index 0d73f1c3df..33078e07ce 100644
--- a/spec/ruby/core/float/gt_spec.rb
+++ b/spec/ruby/core/float/gt_spec.rb
@@ -14,4 +14,25 @@ describe "Float#>" do
-> { 5.0 > "4" }.should raise_error(ArgumentError)
-> { 5.0 > mock('x') }.should raise_error(ArgumentError)
end
+
+ it "returns false if one side is NaN" do
+ [1.0, 42, bignum_value].each { |n|
+ (nan_value > n).should == false
+ (n > nan_value).should == false
+ }
+ end
+
+ it "handles positive infinity" do
+ [1.0, 42, bignum_value].each { |n|
+ (infinity_value > n).should == true
+ (n > infinity_value).should == false
+ }
+ end
+
+ it "handles negative infinity" do
+ [1.0, 42, bignum_value].each { |n|
+ (-infinity_value > n).should == false
+ (n > -infinity_value).should == true
+ }
+ end
end
diff --git a/spec/ruby/core/float/gte_spec.rb b/spec/ruby/core/float/gte_spec.rb
index 98ec60b70b..44c0a81b43 100644
--- a/spec/ruby/core/float/gte_spec.rb
+++ b/spec/ruby/core/float/gte_spec.rb
@@ -14,4 +14,25 @@ describe "Float#>=" do
-> { 5.0 >= "4" }.should raise_error(ArgumentError)
-> { 5.0 >= mock('x') }.should raise_error(ArgumentError)
end
+
+ it "returns false if one side is NaN" do
+ [1.0, 42, bignum_value].each { |n|
+ (nan_value >= n).should == false
+ (n >= nan_value).should == false
+ }
+ end
+
+ it "handles positive infinity" do
+ [1.0, 42, bignum_value].each { |n|
+ (infinity_value >= n).should == true
+ (n >= infinity_value).should == false
+ }
+ end
+
+ it "handles negative infinity" do
+ [1.0, 42, bignum_value].each { |n|
+ (-infinity_value >= n).should == false
+ (n >= -infinity_value).should == true
+ }
+ end
end
diff --git a/spec/ruby/core/float/lt_spec.rb b/spec/ruby/core/float/lt_spec.rb
index c01b6e0e02..94dcfc42f8 100644
--- a/spec/ruby/core/float/lt_spec.rb
+++ b/spec/ruby/core/float/lt_spec.rb
@@ -14,4 +14,25 @@ describe "Float#<" do
-> { 5.0 < "4" }.should raise_error(ArgumentError)
-> { 5.0 < mock('x') }.should raise_error(ArgumentError)
end
+
+ it "returns false if one side is NaN" do
+ [1.0, 42, bignum_value].each { |n|
+ (nan_value < n).should == false
+ (n < nan_value).should == false
+ }
+ end
+
+ it "handles positive infinity" do
+ [1.0, 42, bignum_value].each { |n|
+ (infinity_value < n).should == false
+ (n < infinity_value).should == true
+ }
+ end
+
+ it "handles negative infinity" do
+ [1.0, 42, bignum_value].each { |n|
+ (-infinity_value < n).should == true
+ (n < -infinity_value).should == false
+ }
+ end
end
diff --git a/spec/ruby/core/float/lte_spec.rb b/spec/ruby/core/float/lte_spec.rb
index 66f2ddc2c7..7b5a86ee76 100644
--- a/spec/ruby/core/float/lte_spec.rb
+++ b/spec/ruby/core/float/lte_spec.rb
@@ -15,4 +15,25 @@ describe "Float#<=" do
-> { 5.0 <= "4" }.should raise_error(ArgumentError)
-> { 5.0 <= mock('x') }.should raise_error(ArgumentError)
end
+
+ it "returns false if one side is NaN" do
+ [1.0, 42, bignum_value].each { |n|
+ (nan_value <= n).should == false
+ (n <= nan_value).should == false
+ }
+ end
+
+ it "handles positive infinity" do
+ [1.0, 42, bignum_value].each { |n|
+ (infinity_value <= n).should == false
+ (n <= infinity_value).should == true
+ }
+ end
+
+ it "handles negative infinity" do
+ [1.0, 42, bignum_value].each { |n|
+ (-infinity_value <= n).should == true
+ (n <= -infinity_value).should == false
+ }
+ end
end
diff --git a/spec/ruby/core/float/magnitude_spec.rb b/spec/ruby/core/float/magnitude_spec.rb
index db577c15c5..7cdd8ef28a 100644
--- a/spec/ruby/core/float/magnitude_spec.rb
+++ b/spec/ruby/core/float/magnitude_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../spec_helper"
require_relative 'shared/abs'
describe "Float#magnitude" do
diff --git a/spec/ruby/core/float/minus_spec.rb b/spec/ruby/core/float/minus_spec.rb
index 5626cbdac2..a4281a397b 100644
--- a/spec/ruby/core/float/minus_spec.rb
+++ b/spec/ruby/core/float/minus_spec.rb
@@ -6,7 +6,7 @@ describe "Float#-" do
it "returns self minus other" do
(9_237_212.5280 - 5_280).should be_close(9231932.528, TOLERANCE)
- (2_560_496.1691 - bignum_value).should be_close(-9223372036852215808.000, TOLERANCE)
+ (2_560_496.1691 - bignum_value).should be_close(-18446744073706991616.0, TOLERANCE)
(5.5 - 5.5).should be_close(0.0,TOLERANCE)
end
end
diff --git a/spec/ruby/core/float/multiply_spec.rb b/spec/ruby/core/float/multiply_spec.rb
index eca0b52c4f..2adb8796cd 100644
--- a/spec/ruby/core/float/multiply_spec.rb
+++ b/spec/ruby/core/float/multiply_spec.rb
@@ -7,7 +7,7 @@ describe "Float#*" do
it "returns self multiplied by other" do
(4923.98221 * 2).should be_close(9847.96442, TOLERANCE)
(6712.5 * 0.25).should be_close(1678.125, TOLERANCE)
- (256.4096 * bignum_value).should be_close(2364961134621118431232.000, TOLERANCE)
+ (256.4096 * bignum_value).should be_close(4729922269242236862464.0, TOLERANCE)
end
it "raises a TypeError when given a non-Numeric" do
diff --git a/spec/ruby/core/float/plus_spec.rb b/spec/ruby/core/float/plus_spec.rb
index 06b136a06b..e3e19d7f39 100644
--- a/spec/ruby/core/float/plus_spec.rb
+++ b/spec/ruby/core/float/plus_spec.rb
@@ -6,7 +6,7 @@ describe "Float#+" do
it "returns self plus other" do
(491.213 + 2).should be_close(493.213, TOLERANCE)
- (9.99 + bignum_value).should be_close(9223372036854775808.000, TOLERANCE)
+ (9.99 + bignum_value).should be_close(18446744073709551616.0, TOLERANCE)
(1001.99 + 5.219).should be_close(1007.209, TOLERANCE)
end
end
diff --git a/spec/ruby/core/float/round_spec.rb b/spec/ruby/core/float/round_spec.rb
index 4bd2dc460c..9b4c307f9d 100644
--- a/spec/ruby/core/float/round_spec.rb
+++ b/spec/ruby/core/float/round_spec.rb
@@ -103,6 +103,70 @@ describe "Float#round" do
5.55.round(1, half: :up).should eql(5.6)
5.55.round(1, half: :down).should eql(5.5)
5.55.round(1, half: :even).should eql(5.6)
+ -5.55.round(1, half: nil).should eql(-5.6)
+ -5.55.round(1, half: :up).should eql(-5.6)
+ -5.55.round(1, half: :down).should eql(-5.5)
+ -5.55.round(1, half: :even).should eql(-5.6)
+ end
+
+ it "preserves cases where neighbouring floating pointer number increase the decimal places" do
+ 4.8100000000000005.round(5, half: nil).should eql(4.81)
+ 4.8100000000000005.round(5, half: :up).should eql(4.81)
+ 4.8100000000000005.round(5, half: :down).should eql(4.81)
+ 4.8100000000000005.round(5, half: :even).should eql(4.81)
+ -4.8100000000000005.round(5, half: nil).should eql(-4.81)
+ -4.8100000000000005.round(5, half: :up).should eql(-4.81)
+ -4.8100000000000005.round(5, half: :down).should eql(-4.81)
+ -4.8100000000000005.round(5, half: :even).should eql(-4.81)
+ 4.81.round(5, half: nil).should eql(4.81)
+ 4.81.round(5, half: :up).should eql(4.81)
+ 4.81.round(5, half: :down).should eql(4.81)
+ 4.81.round(5, half: :even).should eql(4.81)
+ -4.81.round(5, half: nil).should eql(-4.81)
+ -4.81.round(5, half: :up).should eql(-4.81)
+ -4.81.round(5, half: :down).should eql(-4.81)
+ -4.81.round(5, half: :even).should eql(-4.81)
+ 4.809999999999999.round(5, half: nil).should eql(4.81)
+ 4.809999999999999.round(5, half: :up).should eql(4.81)
+ 4.809999999999999.round(5, half: :down).should eql(4.81)
+ 4.809999999999999.round(5, half: :even).should eql(4.81)
+ -4.809999999999999.round(5, half: nil).should eql(-4.81)
+ -4.809999999999999.round(5, half: :up).should eql(-4.81)
+ -4.809999999999999.round(5, half: :down).should eql(-4.81)
+ -4.809999999999999.round(5, half: :even).should eql(-4.81)
+ end
+
+ ruby_bug "#19318", ""..."3.3" do
+ # These numbers are neighbouring floating point numbers round a
+ # precise value. They test that the rounding modes work correctly
+ # round that value and precision is not lost which might cause
+ # incorrect results.
+ it "does not lose precision during the rounding process" do
+ 767573.1875850001.round(5, half: nil).should eql(767573.18759)
+ 767573.1875850001.round(5, half: :up).should eql(767573.18759)
+ 767573.1875850001.round(5, half: :down).should eql(767573.18759)
+ 767573.1875850001.round(5, half: :even).should eql(767573.18759)
+ -767573.1875850001.round(5, half: nil).should eql(-767573.18759)
+ -767573.1875850001.round(5, half: :up).should eql(-767573.18759)
+ -767573.1875850001.round(5, half: :down).should eql(-767573.18759)
+ -767573.1875850001.round(5, half: :even).should eql(-767573.18759)
+ 767573.187585.round(5, half: nil).should eql(767573.18759)
+ 767573.187585.round(5, half: :up).should eql(767573.18759)
+ 767573.187585.round(5, half: :down).should eql(767573.18758)
+ 767573.187585.round(5, half: :even).should eql(767573.18758)
+ -767573.187585.round(5, half: nil).should eql(-767573.18759)
+ -767573.187585.round(5, half: :up).should eql(-767573.18759)
+ -767573.187585.round(5, half: :down).should eql(-767573.18758)
+ -767573.187585.round(5, half: :even).should eql(-767573.18758)
+ 767573.1875849998.round(5, half: nil).should eql(767573.18758)
+ 767573.1875849998.round(5, half: :up).should eql(767573.18758)
+ 767573.1875849998.round(5, half: :down).should eql(767573.18758)
+ 767573.1875849998.round(5, half: :even).should eql(767573.18758)
+ -767573.1875849998.round(5, half: nil).should eql(-767573.18758)
+ -767573.1875849998.round(5, half: :up).should eql(-767573.18758)
+ -767573.1875849998.round(5, half: :down).should eql(-767573.18758)
+ -767573.1875849998.round(5, half: :even).should eql(-767573.18758)
+ end
end
it "raises FloatDomainError for exceptional values with a half option" do
diff --git a/spec/ruby/core/float/shared/equal.rb b/spec/ruby/core/float/shared/equal.rb
index 668aa069b5..4d524e1cf2 100644
--- a/spec/ruby/core/float/shared/equal.rb
+++ b/spec/ruby/core/float/shared/equal.rb
@@ -14,4 +14,25 @@ describe :float_equal, shared: true do
1.0.send(@method, x).should == false
2.0.send(@method, x).should == true
end
+
+ it "returns false if one side is NaN" do
+ [1.0, 42, bignum_value].each { |n|
+ (nan_value.send(@method, n)).should == false
+ (n.send(@method, nan_value)).should == false
+ }
+ end
+
+ it "handles positive infinity" do
+ [1.0, 42, bignum_value].each { |n|
+ (infinity_value.send(@method, n)).should == false
+ (n.send(@method, infinity_value)).should == false
+ }
+ end
+
+ it "handles negative infinity" do
+ [1.0, 42, bignum_value].each { |n|
+ ((-infinity_value).send(@method, n)).should == false
+ (n.send(@method, -infinity_value)).should == false
+ }
+ end
end
diff --git a/spec/ruby/core/float/shared/to_i.rb b/spec/ruby/core/float/shared/to_i.rb
index 960295f095..33b32ca533 100644
--- a/spec/ruby/core/float/shared/to_i.rb
+++ b/spec/ruby/core/float/shared/to_i.rb
@@ -7,4 +7,8 @@ describe :float_to_i, shared: true do
-9223372036854775808.1.send(@method).should eql(-9223372036854775808)
9223372036854775808.1.send(@method).should eql(9223372036854775808)
end
+
+ it "raises a FloatDomainError for NaN" do
+ -> { nan_value.send(@method) }.should raise_error(FloatDomainError)
+ end
end
diff --git a/spec/ruby/core/gc/auto_compact_spec.rb b/spec/ruby/core/gc/auto_compact_spec.rb
index 4f9d043171..33ad1cb56c 100644
--- a/spec/ruby/core/gc/auto_compact_spec.rb
+++ b/spec/ruby/core/gc/auto_compact_spec.rb
@@ -1,26 +1,24 @@
require_relative '../../spec_helper'
-ruby_version_is "3.0" do
- describe "GC.auto_compact" do
- it "can set and get a boolean value" do
- begin
- GC.auto_compact = GC.auto_compact
- rescue NotImplementedError # platform does not support autocompact
- skip
- end
+describe "GC.auto_compact" do
+ it "can set and get a boolean value" do
+ begin
+ GC.auto_compact = GC.auto_compact
+ rescue NotImplementedError # platform does not support autocompact
+ skip
+ end
- original = GC.auto_compact
- begin
- GC.auto_compact = !original
- rescue NotImplementedError # platform does not support autocompact
- skip
- end
+ original = GC.auto_compact
+ begin
+ GC.auto_compact = !original
+ rescue NotImplementedError # platform does not support autocompact
+ skip
+ end
- begin
- GC.auto_compact.should == !original
- ensure
- GC.auto_compact = original
- end
+ begin
+ GC.auto_compact.should == !original
+ ensure
+ GC.auto_compact = original
end
end
end
diff --git a/spec/ruby/core/hash/assoc_spec.rb b/spec/ruby/core/hash/assoc_spec.rb
index 64442918d1..62b2a11b30 100644
--- a/spec/ruby/core/hash/assoc_spec.rb
+++ b/spec/ruby/core/hash/assoc_spec.rb
@@ -22,11 +22,11 @@ describe "Hash#assoc" do
end
it "only returns the first matching key-value pair for identity hashes" do
- # Avoid literal String keys in Hash#[]= due to https://bugs.ruby-lang.org/issues/12855
+ # Avoid literal String keys since string literals can be frozen and interned e.g. with --enable-frozen-string-literal
h = {}.compare_by_identity
- k1 = 'pear'
+ k1 = 'pear'.dup
h[k1] = :red
- k2 = 'pear'
+ k2 = 'pear'.dup
h[k2] = :green
h.size.should == 2
h.keys.grep(/pear/).size.should == 2
diff --git a/spec/ruby/core/hash/compact_spec.rb b/spec/ruby/core/hash/compact_spec.rb
index 2989afc8b7..76aa43949d 100644
--- a/spec/ruby/core/hash/compact_spec.rb
+++ b/spec/ruby/core/hash/compact_spec.rb
@@ -18,6 +18,30 @@ describe "Hash#compact" do
@hash.compact
@hash.should == @initial_pairs
end
+
+ ruby_version_is '3.3' do
+ it "retains the default value" do
+ hash = Hash.new(1)
+ hash.compact.default.should == 1
+ hash[:a] = 1
+ hash.compact.default.should == 1
+ end
+
+ it "retains the default_proc" do
+ pr = proc { |h, k| h[k] = [] }
+ hash = Hash.new(&pr)
+ hash.compact.default_proc.should == pr
+ hash[:a] = 1
+ hash.compact.default_proc.should == pr
+ end
+
+ it "retains compare_by_identity_flag" do
+ hash = {}.compare_by_identity
+ hash.compact.compare_by_identity?.should == true
+ hash[:a] = 1
+ hash.compact.compare_by_identity?.should == true
+ end
+ end
end
describe "Hash#compact!" do
diff --git a/spec/ruby/core/hash/compare_by_identity_spec.rb b/spec/ruby/core/hash/compare_by_identity_spec.rb
index 874cd46eb7..2975526a97 100644
--- a/spec/ruby/core/hash/compare_by_identity_spec.rb
+++ b/spec/ruby/core/hash/compare_by_identity_spec.rb
@@ -85,19 +85,21 @@ describe "Hash#compare_by_identity" do
-> { @h.compare_by_identity }.should raise_error(FrozenError)
end
- # Behaviour confirmed in bug #1871
+ # Behaviour confirmed in https://bugs.ruby-lang.org/issues/1871
it "persists over #dups" do
- @idh['foo'] = :bar
- @idh['foo'] = :glark
+ @idh['foo'.dup] = :bar
+ @idh['foo'.dup] = :glark
@idh.dup.should == @idh
@idh.dup.size.should == @idh.size
+ @idh.dup.should.compare_by_identity?
end
it "persists over #clones" do
- @idh['foo'] = :bar
- @idh['foo'] = :glark
+ @idh['foo'.dup] = :bar
+ @idh['foo'.dup] = :glark
@idh.clone.should == @idh
@idh.clone.size.should == @idh.size
+ @idh.dup.should.compare_by_identity?
end
it "does not copy string keys" do
@@ -108,9 +110,16 @@ describe "Hash#compare_by_identity" do
@idh.keys.first.should equal foo
end
+ # Check `#[]=` call with a String literal.
+ # Don't use `#+` because with `#+` it's no longer a String literal.
+ #
+ # See https://bugs.ruby-lang.org/issues/12855
it "gives different identity for string literals" do
+ eval <<~RUBY
+ # frozen_string_literal: false
@idh['foo'] = 1
@idh['foo'] = 2
+ RUBY
@idh.values.should == [1, 2]
@idh.size.should == 2
end
diff --git a/spec/ruby/core/hash/constructor_spec.rb b/spec/ruby/core/hash/constructor_spec.rb
index ad67274802..8d29773909 100644
--- a/spec/ruby/core/hash/constructor_spec.rb
+++ b/spec/ruby/core/hash/constructor_spec.rb
@@ -42,26 +42,13 @@ describe "Hash.[]" do
Hash[ary].should == { a: :b }
end
- ruby_version_is "" ... "2.7" do
- it "ignores elements that are not arrays" do
- -> {
- Hash[[:a]].should == {}
- }.should complain(/ignoring wrong elements/)
- -> {
- Hash[[:nil]].should == {}
- }.should complain(/ignoring wrong elements/)
- end
- end
-
- ruby_version_is "2.7" do
- it "raises for elements that are not arrays" do
- -> {
- Hash[[:a]].should == {}
- }.should raise_error(ArgumentError)
- -> {
- Hash[[:nil]].should == {}
- }.should raise_error(ArgumentError)
- end
+ it "raises for elements that are not arrays" do
+ -> {
+ Hash[[:a]].should == {}
+ }.should raise_error(ArgumentError)
+ -> {
+ Hash[[:nil]].should == {}
+ }.should raise_error(ArgumentError)
end
it "raises an ArgumentError for arrays of more than 2 elements" do
@@ -116,8 +103,26 @@ describe "Hash.[]" do
HashSpecs::MyInitializerHash[Hash[1, 2]].should be_an_instance_of(HashSpecs::MyInitializerHash)
end
+ it "removes the default value" do
+ hash = Hash.new(1)
+ Hash[hash].default.should be_nil
+ hash[:a] = 1
+ Hash[hash].default.should be_nil
+ end
+
it "removes the default_proc" do
hash = Hash.new { |h, k| h[k] = [] }
Hash[hash].default_proc.should be_nil
+ hash[:a] = 1
+ Hash[hash].default_proc.should be_nil
+ end
+
+ ruby_version_is '3.3' do
+ it "does not retain compare_by_identity_flag" do
+ hash = {}.compare_by_identity
+ Hash[hash].compare_by_identity?.should == false
+ hash[:a] = 1
+ Hash[hash].compare_by_identity?.should == false
+ end
end
end
diff --git a/spec/ruby/core/hash/deconstruct_keys_spec.rb b/spec/ruby/core/hash/deconstruct_keys_spec.rb
index b265732616..bbcd8932e5 100644
--- a/spec/ruby/core/hash/deconstruct_keys_spec.rb
+++ b/spec/ruby/core/hash/deconstruct_keys_spec.rb
@@ -1,25 +1,23 @@
require_relative '../../spec_helper'
-ruby_version_is "2.7" do
- describe "Hash#deconstruct_keys" do
- it "returns self" do
- hash = {a: 1, b: 2}
+describe "Hash#deconstruct_keys" do
+ it "returns self" do
+ hash = {a: 1, b: 2}
- hash.deconstruct_keys([:a, :b]).should equal hash
- end
+ hash.deconstruct_keys([:a, :b]).should equal hash
+ end
- it "requires one argument" do
- -> {
- {a: 1}.deconstruct_keys
- }.should raise_error(ArgumentError, /wrong number of arguments \(given 0, expected 1\)/)
- end
+ it "requires one argument" do
+ -> {
+ {a: 1}.deconstruct_keys
+ }.should raise_error(ArgumentError, /wrong number of arguments \(given 0, expected 1\)/)
+ end
- it "ignores argument" do
- hash = {a: 1, b: 2}
+ it "ignores argument" do
+ hash = {a: 1, b: 2}
- hash.deconstruct_keys([:a]).should == {a: 1, b: 2}
- hash.deconstruct_keys(0 ).should == {a: 1, b: 2}
- hash.deconstruct_keys('' ).should == {a: 1, b: 2}
- end
+ hash.deconstruct_keys([:a]).should == {a: 1, b: 2}
+ hash.deconstruct_keys(0 ).should == {a: 1, b: 2}
+ hash.deconstruct_keys('' ).should == {a: 1, b: 2}
end
end
diff --git a/spec/ruby/core/hash/delete_spec.rb b/spec/ruby/core/hash/delete_spec.rb
index b262e8846b..3e3479c69c 100644
--- a/spec/ruby/core/hash/delete_spec.rb
+++ b/spec/ruby/core/hash/delete_spec.rb
@@ -24,7 +24,7 @@ describe "Hash#delete" do
it "allows removing a key while iterating" do
h = { a: 1, b: 2 }
visited = []
- h.each_pair { |k,v|
+ h.each_pair { |k, v|
visited << k
h.delete(k)
}
@@ -32,13 +32,27 @@ describe "Hash#delete" do
h.should == {}
end
+ it "allows removing a key while iterating for big hashes" do
+ h = { a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8, i: 9, j: 10,
+ k: 11, l: 12, m: 13, n: 14, o: 15, p: 16, q: 17, r: 18, s: 19, t: 20,
+ u: 21, v: 22, w: 23, x: 24, y: 25, z: 26 }
+ visited = []
+ h.each_pair { |k, v|
+ visited << k
+ h.delete(k)
+ }
+ visited.should == [:a, :b, :c, :d, :e, :f, :g, :h, :i, :j, :k, :l, :m,
+ :n, :o, :p, :q, :r, :s, :t, :u, :v, :w, :x, :y, :z]
+ h.should == {}
+ end
+
it "accepts keys with private #hash method" do
key = HashSpecs::KeyWithPrivateHash.new
{ key => 5 }.delete(key).should == 5
end
it "raises a FrozenError if called on a frozen instance" do
- -> { HashSpecs.frozen_hash.delete("foo") }.should raise_error(FrozenError)
+ -> { HashSpecs.frozen_hash.delete("foo") }.should raise_error(FrozenError)
-> { HashSpecs.empty_frozen_hash.delete("foo") }.should raise_error(FrozenError)
end
end
diff --git a/spec/ruby/core/hash/element_reference_spec.rb b/spec/ruby/core/hash/element_reference_spec.rb
index e271f37ea6..94e8237839 100644
--- a/spec/ruby/core/hash/element_reference_spec.rb
+++ b/spec/ruby/core/hash/element_reference_spec.rb
@@ -30,7 +30,7 @@ describe "Hash#[]" do
end
it "does not create copies of the immediate default value" do
- str = "foo"
+ str = +"foo"
h = Hash.new(str)
a = h[:a]
b = h[:b]
diff --git a/spec/ruby/core/hash/except_spec.rb b/spec/ruby/core/hash/except_spec.rb
index 82cfced72f..ac84f9975c 100644
--- a/spec/ruby/core/hash/except_spec.rb
+++ b/spec/ruby/core/hash/except_spec.rb
@@ -1,34 +1,32 @@
require_relative '../../spec_helper'
-ruby_version_is "3.0" do
- describe "Hash#except" do
- before :each do
- @hash = { a: 1, b: 2, c: 3 }
- end
+describe "Hash#except" do
+ before :each do
+ @hash = { a: 1, b: 2, c: 3 }
+ end
- it "returns a new duplicate hash without arguments" do
- ret = @hash.except
- ret.should_not equal(@hash)
- ret.should == @hash
- end
+ it "returns a new duplicate hash without arguments" do
+ ret = @hash.except
+ ret.should_not equal(@hash)
+ ret.should == @hash
+ end
- it "returns a hash without the requested subset" do
- @hash.except(:c, :a).should == { b: 2 }
- end
+ it "returns a hash without the requested subset" do
+ @hash.except(:c, :a).should == { b: 2 }
+ end
- it "ignores keys not present in the original hash" do
- @hash.except(:a, :chunky_bacon).should == { b: 2, c: 3 }
- end
+ it "ignores keys not present in the original hash" do
+ @hash.except(:a, :chunky_bacon).should == { b: 2, c: 3 }
+ end
- it "always returns a Hash without a default" do
- klass = Class.new(Hash)
- h = klass.new(:default)
- h[:bar] = 12
- h[:foo] = 42
- r = h.except(:foo)
- r.should == {bar: 12}
- r.class.should == Hash
- r.default.should == nil
- 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
end
end
diff --git a/spec/ruby/core/hash/fetch_spec.rb b/spec/ruby/core/hash/fetch_spec.rb
index 753167f709..6e0d207224 100644
--- a/spec/ruby/core/hash/fetch_spec.rb
+++ b/spec/ruby/core/hash/fetch_spec.rb
@@ -4,7 +4,7 @@ require_relative '../../shared/hash/key_error'
describe "Hash#fetch" do
context "when the key is not found" do
- it_behaves_like :key_error, -> obj, key { obj.fetch(key) }, Hash.new(a: 5)
+ it_behaves_like :key_error, -> obj, key { obj.fetch(key) }, Hash.new({ a: 5 })
it_behaves_like :key_error, -> obj, key { obj.fetch(key) }, {}
it_behaves_like :key_error, -> obj, key { obj.fetch(key) }, Hash.new { 5 }
it_behaves_like :key_error, -> obj, key { obj.fetch(key) }, Hash.new(5)
diff --git a/spec/ruby/core/hash/fetch_values_spec.rb b/spec/ruby/core/hash/fetch_values_spec.rb
index af3673f6ef..0cd48565af 100644
--- a/spec/ruby/core/hash/fetch_values_spec.rb
+++ b/spec/ruby/core/hash/fetch_values_spec.rb
@@ -19,7 +19,7 @@ describe "Hash#fetch_values" do
end
describe "with unmatched keys" do
- it_behaves_like :key_error, -> obj, key { obj.fetch_values(key) }, Hash.new(a: 5)
+ it_behaves_like :key_error, -> obj, key { obj.fetch_values(key) }, Hash.new({ a: 5 })
it "returns the default value from block" do
@hash.fetch_values(:z) { |key| "`#{key}' is not found" }.should == ["`z' is not found"]
diff --git a/spec/ruby/core/hash/hash_spec.rb b/spec/ruby/core/hash/hash_spec.rb
index 3649d4d8de..19eb806dc4 100644
--- a/spec/ruby/core/hash/hash_spec.rb
+++ b/spec/ruby/core/hash/hash_spec.rb
@@ -41,4 +41,13 @@ describe "Hash#hash" do
h.hash.should == {x: [h]}.hash
# Like above, because h.eql?(x: [h])
end
+
+ ruby_version_is "3.1" do
+ it "allows omitting values" do
+ a = 1
+ b = 2
+
+ eval('{a:, b:}.should == { a: 1, b: 2 }')
+ end
+ end
end
diff --git a/spec/ruby/core/hash/index_spec.rb b/spec/ruby/core/hash/index_spec.rb
deleted file mode 100644
index be4e2cc6ab..0000000000
--- a/spec/ruby/core/hash/index_spec.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/index'
-
-ruby_version_is ''...'3.0' do
- describe "Hash#index" do
- it_behaves_like :hash_index, :index
- end
-end
diff --git a/spec/ruby/core/hash/new_spec.rb b/spec/ruby/core/hash/new_spec.rb
index 6054b69bdd..6279815fd6 100644
--- a/spec/ruby/core/hash/new_spec.rb
+++ b/spec/ruby/core/hash/new_spec.rb
@@ -33,4 +33,17 @@ describe "Hash.new" do
-> { Hash.new(5) { 0 } }.should raise_error(ArgumentError)
-> { Hash.new(nil) { 0 } }.should raise_error(ArgumentError)
end
+
+ ruby_version_is "3.3" do
+ it "emits a deprecation warning if keyword arguments are passed" do
+ -> { Hash.new(unknown: true) }.should complain(
+ Regexp.new(Regexp.escape("Calling Hash.new with keyword arguments is deprecated and will be removed in Ruby 3.4; use Hash.new({ key: value }) instead"))
+ )
+
+ -> { Hash.new(1, unknown: true) }.should raise_error(ArgumentError)
+ -> { Hash.new(unknown: true) { 0 } }.should raise_error(ArgumentError)
+
+ Hash.new({ unknown: true }).default.should == { unknown: true }
+ end
+ end
end
diff --git a/spec/ruby/core/hash/rehash_spec.rb b/spec/ruby/core/hash/rehash_spec.rb
index 0049080456..db3e91b166 100644
--- a/spec/ruby/core/hash/rehash_spec.rb
+++ b/spec/ruby/core/hash/rehash_spec.rb
@@ -77,6 +77,36 @@ describe "Hash#rehash" do
h.keys.should_not.include? [1]
end
+ it "iterates keys in insertion order" do
+ key = Class.new do
+ attr_reader :name
+
+ def initialize(name)
+ @name = name
+ end
+
+ def hash
+ 123
+ end
+ end
+
+ a, b, c, d = key.new('a'), key.new('b'), key.new('c'), key.new('d')
+ h = { a => 1, b => 2, c => 3, d => 4 }
+ h.size.should == 4
+
+ key.class_exec do
+ def eql?(other)
+ true
+ end
+ end
+
+ h.rehash
+ h.size.should == 1
+ k, v = h.first
+ k.name.should == 'a'
+ v.should == 4
+ end
+
it "raises a FrozenError if called on a frozen instance" do
-> { HashSpecs.frozen_hash.rehash }.should raise_error(FrozenError)
-> { HashSpecs.empty_frozen_hash.rehash }.should raise_error(FrozenError)
diff --git a/spec/ruby/core/hash/reject_spec.rb b/spec/ruby/core/hash/reject_spec.rb
index 397000ab67..dd8e817237 100644
--- a/spec/ruby/core/hash/reject_spec.rb
+++ b/spec/ruby/core/hash/reject_spec.rb
@@ -31,13 +31,6 @@ describe "Hash#reject" do
HashSpecs::MyHash[1 => 2, 3 => 4].reject { false }.should be_kind_of(Hash)
HashSpecs::MyHash[1 => 2, 3 => 4].reject { true }.should be_kind_of(Hash)
end
-
- ruby_version_is ''...'2.7' do
- it "does not taint the resulting hash" do
- h = { a: 1 }.taint
- h.reject {false}.should_not.tainted?
- end
- end
end
it "processes entries with the same order as reject!" do
diff --git a/spec/ruby/core/hash/ruby2_keywords_hash_spec.rb b/spec/ruby/core/hash/ruby2_keywords_hash_spec.rb
index 005886a482..7dbb9c0a98 100644
--- a/spec/ruby/core/hash/ruby2_keywords_hash_spec.rb
+++ b/spec/ruby/core/hash/ruby2_keywords_hash_spec.rb
@@ -1,47 +1,83 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-ruby_version_is "2.7" do
- describe "Hash.ruby2_keywords_hash?" do
- it "returns false if the Hash is not a keywords Hash" do
- Hash.ruby2_keywords_hash?({}).should == false
- end
+describe "Hash.ruby2_keywords_hash?" do
+ it "returns false if the Hash is not a keywords Hash" do
+ Hash.ruby2_keywords_hash?({}).should == false
+ end
- it "returns true if the Hash is a keywords Hash marked by Module#ruby2_keywords" do
- obj = Class.new {
- ruby2_keywords def m(*args)
- args.last
- end
- }.new
- Hash.ruby2_keywords_hash?(obj.m(a: 1)).should == true
- end
+ it "returns true if the Hash is a keywords Hash marked by Module#ruby2_keywords" do
+ obj = Class.new {
+ ruby2_keywords def m(*args)
+ args.last
+ end
+ }.new
+ Hash.ruby2_keywords_hash?(obj.m(a: 1)).should == true
+ end
- it "raises TypeError for non-Hash" do
- -> { Hash.ruby2_keywords_hash?(nil) }.should raise_error(TypeError)
- end
+ it "raises TypeError for non-Hash" do
+ -> { Hash.ruby2_keywords_hash?(nil) }.should raise_error(TypeError)
end
+end
- describe "Hash.ruby2_keywords_hash" do
- it "returns a copy of a Hash and marks the copy as a keywords Hash" do
- h = {a: 1}.freeze
- kw = Hash.ruby2_keywords_hash(h)
- Hash.ruby2_keywords_hash?(h).should == false
- Hash.ruby2_keywords_hash?(kw).should == true
- kw.should == h
- end
+describe "Hash.ruby2_keywords_hash" do
+ it "returns a copy of a Hash and marks the copy as a keywords Hash" do
+ h = {a: 1}.freeze
+ kw = Hash.ruby2_keywords_hash(h)
+ Hash.ruby2_keywords_hash?(h).should == false
+ Hash.ruby2_keywords_hash?(kw).should == true
+ kw.should == h
+ end
- it "returns an instance of the subclass if called on an instance of a subclass of Hash" do
- h = HashSpecs::MyHash.new
- h[:a] = 1
- kw = Hash.ruby2_keywords_hash(h)
- kw.class.should == HashSpecs::MyHash
- Hash.ruby2_keywords_hash?(h).should == false
- Hash.ruby2_keywords_hash?(kw).should == true
- kw.should == h
- end
+ it "returns an instance of the subclass if called on an instance of a subclass of Hash" do
+ h = HashSpecs::MyHash.new
+ h[:a] = 1
+ kw = Hash.ruby2_keywords_hash(h)
+ kw.class.should == HashSpecs::MyHash
+ Hash.ruby2_keywords_hash?(h).should == false
+ Hash.ruby2_keywords_hash?(kw).should == true
+ kw.should == h
+ end
+
+ it "copies instance variables" do
+ h = {a: 1}
+ h.instance_variable_set(:@foo, 42)
+ kw = Hash.ruby2_keywords_hash(h)
+ kw.instance_variable_get(:@foo).should == 42
+ end
+
+ it "copies the hash internals" do
+ h = {a: 1}
+ kw = Hash.ruby2_keywords_hash(h)
+ h[:a] = 2
+ kw[:a].should == 1
+ end
+
+ it "raises TypeError for non-Hash" do
+ -> { Hash.ruby2_keywords_hash(nil) }.should raise_error(TypeError)
+ end
+
+ it "retains the default value" do
+ hash = Hash.new(1)
+ Hash.ruby2_keywords_hash(hash).default.should == 1
+ hash[:a] = 1
+ Hash.ruby2_keywords_hash(hash).default.should == 1
+ end
+
+ it "retains the default_proc" do
+ pr = proc { |h, k| h[k] = [] }
+ hash = Hash.new(&pr)
+ Hash.ruby2_keywords_hash(hash).default_proc.should == pr
+ hash[:a] = 1
+ Hash.ruby2_keywords_hash(hash).default_proc.should == pr
+ end
- it "raises TypeError for non-Hash" do
- -> { Hash.ruby2_keywords_hash(nil) }.should raise_error(TypeError)
+ ruby_version_is '3.3' do
+ it "retains compare_by_identity_flag" do
+ hash = {}.compare_by_identity
+ Hash.ruby2_keywords_hash(hash).compare_by_identity?.should == true
+ hash[:a] = 1
+ Hash.ruby2_keywords_hash(hash).compare_by_identity?.should == true
end
end
end
diff --git a/spec/ruby/core/hash/shared/each.rb b/spec/ruby/core/hash/shared/each.rb
index b2483c8116..f9839ff58f 100644
--- a/spec/ruby/core/hash/shared/each.rb
+++ b/spec/ruby/core/hash/shared/each.rb
@@ -21,37 +21,18 @@ describe :hash_each, shared: true do
ary.sort.should == ["a", "b", "c"]
end
- ruby_version_is ""..."3.0" do
- it "yields 2 values and not an Array of 2 elements when given a callable of arity 2" do
- obj = Object.new
- def obj.foo(key, value)
- ScratchPad << key << value
- end
-
- ScratchPad.record([])
- { "a" => 1 }.send(@method, &obj.method(:foo))
- ScratchPad.recorded.should == ["a", 1]
-
- ScratchPad.record([])
- { "a" => 1 }.send(@method, &-> key, value { ScratchPad << key << value })
- ScratchPad.recorded.should == ["a", 1]
+ it "always yields an Array of 2 elements, even when given a callable of arity 2" do
+ obj = Object.new
+ def obj.foo(key, value)
end
- end
-
- ruby_version_is "3.0" do
- it "always yields an Array of 2 elements, even when given a callable of arity 2" do
- obj = Object.new
- def obj.foo(key, value)
- end
- -> {
- { "a" => 1 }.send(@method, &obj.method(:foo))
- }.should raise_error(ArgumentError)
+ -> {
+ { "a" => 1 }.send(@method, &obj.method(:foo))
+ }.should raise_error(ArgumentError)
- -> {
- { "a" => 1 }.send(@method, &-> key, value { })
- }.should raise_error(ArgumentError)
- end
+ -> {
+ { "a" => 1 }.send(@method, &-> key, value { })
+ }.should raise_error(ArgumentError)
end
it "yields an Array of 2 elements when given a callable of arity 1" do
diff --git a/spec/ruby/core/hash/shared/eql.rb b/spec/ruby/core/hash/shared/eql.rb
index e294edd764..68db49f76d 100644
--- a/spec/ruby/core/hash/shared/eql.rb
+++ b/spec/ruby/core/hash/shared/eql.rb
@@ -149,80 +149,34 @@ describe :hash_eql_additional, shared: true do
h.send(@method, HashSpecs::MyHash[h]).should be_true
end
- ruby_version_is '2.7' do
- # Why isn't this true of eql? too ?
- it "compares keys with matching hash codes via eql?" do
- a = Array.new(2) do
- obj = mock('0')
- obj.should_receive(:hash).at_least(1).and_return(0)
-
- def obj.eql?(o)
- return true if self.equal?(o)
- false
- end
-
- obj
+ # Why isn't this true of eql? too ?
+ it "compares keys with matching hash codes via eql?" do
+ a = Array.new(2) do
+ obj = mock('0')
+ obj.should_receive(:hash).at_least(1).and_return(0)
+
+ def obj.eql?(o)
+ return true if self.equal?(o)
+ false
end
- { a[0] => 1 }.send(@method, { a[1] => 1 }).should be_false
-
- a = Array.new(2) do
- obj = mock('0')
- obj.should_receive(:hash).at_least(1).and_return(0)
-
- def obj.eql?(o)
- true
- end
-
- obj
- end
-
- { a[0] => 1 }.send(@method, { a[1] => 1 }).should be_true
+ obj
end
- end
- ruby_version_is ''...'2.7' do
- # Why isn't this true of eql? too ?
- it "compares keys with matching hash codes via eql?" do
- a = Array.new(2) do
- obj = mock('0')
- obj.should_receive(:hash).at_least(1).and_return(0)
+ { a[0] => 1 }.send(@method, { a[1] => 1 }).should be_false
- # It's undefined whether the impl does a[0].eql?(a[1]) or
- # a[1].eql?(a[0]) so we taint both.
- def obj.eql?(o)
- return true if self.equal?(o)
- taint
- o.taint
- false
- end
+ a = Array.new(2) do
+ obj = mock('0')
+ obj.should_receive(:hash).at_least(1).and_return(0)
- obj
+ def obj.eql?(o)
+ true
end
- { a[0] => 1 }.send(@method, { a[1] => 1 }).should be_false
- a[0].tainted?.should be_true
- a[1].tainted?.should be_true
-
- a = Array.new(2) do
- obj = mock('0')
- obj.should_receive(:hash).at_least(1).and_return(0)
-
- def obj.eql?(o)
- # It's undefined whether the impl does a[0].send(@method, a[1]) or
- # a[1].send(@method, a[0]) so we taint both.
- taint
- o.taint
- true
- end
-
- obj
- end
-
- { a[0] => 1 }.send(@method, { a[1] => 1 }).should be_true
- a[0].tainted?.should be_true
- a[1].tainted?.should be_true
+ obj
end
+
+ { a[0] => 1 }.send(@method, { a[1] => 1 }).should be_true
end
it "compares the values in self to values in other hash" do
diff --git a/spec/ruby/core/hash/shared/equal.rb b/spec/ruby/core/hash/shared/equal.rb
deleted file mode 100644
index 43606437fe..0000000000
--- a/spec/ruby/core/hash/shared/equal.rb
+++ /dev/null
@@ -1,90 +0,0 @@
-describe :hash_equal, shared: true do
- it "does not compare values when keys don't match" do
- value = mock('x')
- value.should_not_receive(:==)
- value.should_not_receive(:eql?)
- { 1 => value }.send(@method, { 2 => value }).should be_false
- end
-
- it "returns false when the numbers of keys differ without comparing any elements" do
- obj = mock('x')
- h = { obj => obj }
-
- obj.should_not_receive(:==)
- obj.should_not_receive(:eql?)
-
- {}.send(@method, h).should be_false
- h.send(@method, {}).should be_false
- end
-
- it "first compares keys via hash" do
- x = mock('x')
- x.should_receive(:hash).and_return(0)
- y = mock('y')
- y.should_receive(:hash).and_return(0)
-
- { x => 1 }.send(@method, { y => 1 }).should be_false
- end
-
- it "does not compare keys with different hash codes via eql?" do
- x = mock('x')
- y = mock('y')
- x.should_not_receive(:eql?)
- y.should_not_receive(:eql?)
-
- x.should_receive(:hash).and_return(0)
- y.should_receive(:hash).and_return(1)
-
- def x.hash() 0 end
- def y.hash() 1 end
-
- { x => 1 }.send(@method, { y => 1 }).should be_false
- end
-
- it "computes equality for recursive hashes" do
- h = {}
- h[:a] = h
- h.send(@method, h[:a]).should be_true
- (h == h[:a]).should be_true
- end
-
- it "computes equality for complex recursive hashes" do
- a, b = {}, {}
- a.merge! self: a, other: b
- b.merge! self: b, other: a
- a.send(@method, b).should be_true # they both have the same structure!
-
- c = {}
- c.merge! other: c, self: c
- c.send(@method, a).should be_true # subtle, but they both have the same structure!
- a[:delta] = c[:delta] = a
- c.send(@method, a).should be_false # not quite the same structure, as a[:other][:delta] = nil
- c[:delta] = 42
- c.send(@method, a).should be_false
- a[:delta] = 42
- c.send(@method, a).should be_false
- b[:delta] = 42
- c.send(@method, a).should be_true
- end
-
- it "computes equality for recursive hashes & arrays" do
- x, y, z = [], [], []
- a, b, c = {foo: x, bar: 42}, {foo: y, bar: 42}, {foo: z, bar: 42}
- x << a
- y << c
- z << b
- b.send(@method, c).should be_true # they clearly have the same structure!
- y.send(@method, z).should be_true
- a.send(@method, b).should be_true # subtle, but they both have the same structure!
- x.send(@method, y).should be_true
- y << x
- y.send(@method, z).should be_false
- z << x
- y.send(@method, z).should be_true
-
- a[:foo], a[:bar] = a[:bar], a[:foo]
- a.send(@method, b).should be_false
- b[:bar] = b[:foo]
- b.send(@method, c).should be_false
- end
-end
diff --git a/spec/ruby/core/hash/shared/store.rb b/spec/ruby/core/hash/shared/store.rb
index b823ea45ca..dd1bb52bac 100644
--- a/spec/ruby/core/hash/shared/store.rb
+++ b/spec/ruby/core/hash/shared/store.rb
@@ -9,7 +9,7 @@ describe :hash_store, shared: true do
it "duplicates string keys using dup semantics" do
# dup doesn't copy singleton methods
- key = "foo"
+ key = +"foo"
def key.reverse() "bar" end
h = {}
h.send(@method, key, 0)
@@ -44,7 +44,7 @@ describe :hash_store, shared: true do
end
it "duplicates and freezes string keys" do
- key = "foo"
+ key = +"foo"
h = {}
h.send(@method, key, 0)
key << "bar"
@@ -75,8 +75,8 @@ describe :hash_store, shared: true do
it "keeps the existing String key in the hash if there is a matching one" do
h = { "a" => 1, "b" => 2, "c" => 3, "d" => 4 }
- key1 = "foo"
- key2 = "foo"
+ key1 = "foo".dup
+ key2 = "foo".dup
key1.should_not equal(key2)
h[key1] = 41
frozen_key = h.keys.last
diff --git a/spec/ruby/core/hash/shared/to_s.rb b/spec/ruby/core/hash/shared/to_s.rb
index b0e3705d01..7864d7cd4c 100644
--- a/spec/ruby/core/hash/shared/to_s.rb
+++ b/spec/ruby/core/hash/shared/to_s.rb
@@ -2,7 +2,6 @@ require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
describe :hash_to_s, shared: true do
-
it "returns a string representation with same order as each()" do
h = { a: [1, 2], b: -2, d: -6, nil => nil }
@@ -25,7 +24,7 @@ describe :hash_to_s, shared: true do
end
it "does not call #to_s on a String returned from #inspect" do
- str = "abc"
+ str = +"abc"
str.should_not_receive(:to_s)
{ a: str }.send(@method).should == '{:a=>"abc"}'
@@ -77,22 +76,14 @@ describe :hash_to_s, shared: true do
y.send(@method).should == "{1=>{0=>{...}}}"
end
- ruby_version_is ''...'2.7' do
- it "returns a tainted string if self is tainted and not empty" do
- {}.taint.send(@method).tainted?.should be_false
- { nil => nil }.taint.send(@method).tainted?.should be_true
- end
-
- it "returns an untrusted string if self is untrusted and not empty" do
- {}.untrust.send(@method).untrusted?.should be_false
- { nil => nil }.untrust.send(@method).untrusted?.should be_true
- end
- end
-
it "does not raise if inspected result is not default external encoding" do
utf_16be = mock("utf_16be")
- utf_16be.should_receive(:inspect).and_return(%<"utf_16be \u3042">.encode!(Encoding::UTF_16BE))
+ utf_16be.should_receive(:inspect).and_return(%<"utf_16be \u3042">.encode(Encoding::UTF_16BE))
{a: utf_16be}.send(@method).should == '{:a=>"utf_16be \u3042"}'
end
+
+ it "works for keys and values whose #inspect return a frozen String" do
+ { true => false }.to_s.should == "{true=>false}"
+ end
end
diff --git a/spec/ruby/core/hash/to_a_spec.rb b/spec/ruby/core/hash/to_a_spec.rb
index 6f6f74f73b..5baf677929 100644
--- a/spec/ruby/core/hash/to_a_spec.rb
+++ b/spec/ruby/core/hash/to_a_spec.rb
@@ -26,24 +26,4 @@ describe "Hash#to_a" do
ent.should be_kind_of(Array)
ent.should == pairs
end
-
- ruby_version_is ''...'2.7' do
- it "returns a tainted array if self is tainted" do
- {}.taint.to_a.tainted?.should be_true
- end
-
- it "returns an untrusted array if self is untrusted" do
- {}.untrust.to_a.untrusted?.should be_true
- end
- end
-
- ruby_version_is '2.7'...'3.0' do
- it "returns a not tainted array if self is tainted" do
- {}.taint.to_a.tainted?.should be_false
- end
-
- it "returns a trusted array if self is untrusted" do
- {}.untrust.to_a.untrusted?.should be_false
- end
- end
end
diff --git a/spec/ruby/core/hash/to_proc_spec.rb b/spec/ruby/core/hash/to_proc_spec.rb
index 8f5d21beb5..9dbc79e5eb 100644
--- a/spec/ruby/core/hash/to_proc_spec.rb
+++ b/spec/ruby/core/hash/to_proc_spec.rb
@@ -19,20 +19,12 @@ describe "Hash#to_proc" do
@proc = @hash.to_proc
end
- ruby_version_is ""..."3.0" do
- it "is not a lambda" do
- @proc.should_not.lambda?
- end
+ it "is a lambda" do
+ @proc.should.lambda?
end
- ruby_version_is "3.0" do
- it "is a lambda" do
- @proc.should.lambda?
- end
-
- it "has an arity of 1" do
- @proc.arity.should == 1
- end
+ it "has an arity of 1" do
+ @proc.arity.should == 1
end
it "raises ArgumentError if not passed exactly one argument" do
diff --git a/spec/ruby/core/hash/transform_keys_spec.rb b/spec/ruby/core/hash/transform_keys_spec.rb
index 1e82ff6547..2fbb17a8e2 100644
--- a/spec/ruby/core/hash/transform_keys_spec.rb
+++ b/spec/ruby/core/hash/transform_keys_spec.rb
@@ -43,18 +43,16 @@ describe "Hash#transform_keys" do
r.class.should == Hash
end
- ruby_version_is "3.0" do
- it "allows a hash argument" do
- @hash.transform_keys({ a: :A, b: :B, c: :C }).should == { A: 1, B: 2, C: 3 }
- end
+ it "allows a hash argument" do
+ @hash.transform_keys({ a: :A, b: :B, c: :C }).should == { A: 1, B: 2, C: 3 }
+ end
- it "allows a partial transformation of keys when using a hash argument" do
- @hash.transform_keys({ a: :A, c: :C }).should == { A: 1, b: 2, C: 3 }
- end
+ it "allows a partial transformation of keys when using a hash argument" do
+ @hash.transform_keys({ a: :A, c: :C }).should == { A: 1, b: 2, C: 3 }
+ end
- it "allows a combination of hash and block argument" do
- @hash.transform_keys({ a: :A }, &:to_s).should == { A: 1, 'b' => 2, 'c' => 3 }
- end
+ it "allows a combination of hash and block argument" do
+ @hash.transform_keys({ a: :A }, &:to_s).should == { A: 1, 'b' => 2, 'c' => 3 }
end
end
@@ -73,7 +71,6 @@ describe "Hash#transform_keys!" do
@hash.should == { 'a' => 1, 'b' => 2, 'c' => 3, 'd' => 4 }
end
- # https://bugs.ruby-lang.org/issues/14380
it "prevents conflicts between new keys and old ones" do
@hash.transform_keys!(&:succ)
@hash.should == { b: 1, c: 2, d: 3, e: 4 }
@@ -112,11 +109,9 @@ describe "Hash#transform_keys!" do
end
end
- ruby_version_is "3.0" do
- it "allows a hash argument" do
- @hash.transform_keys!({ a: :A, b: :B, c: :C, d: :D })
- @hash.should == { A: 1, B: 2, C: 3, D: 4 }
- end
+ it "allows a hash argument" do
+ @hash.transform_keys!({ a: :A, b: :B, c: :C, d: :D })
+ @hash.should == { A: 1, B: 2, C: 3, D: 4 }
end
describe "on frozen instance" do
@@ -133,10 +128,8 @@ describe "Hash#transform_keys!" do
@hash.should == @initial_pairs
end
- ruby_version_is "3.0" do
- it "raises a FrozenError on hash argument" do
- ->{ @hash.transform_keys!({ a: :A, b: :B, c: :C }) }.should raise_error(FrozenError)
- end
+ it "raises a FrozenError on hash argument" do
+ ->{ @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/try_convert_spec.rb b/spec/ruby/core/hash/try_convert_spec.rb
index 44195c5010..d359ae49d8 100644
--- a/spec/ruby/core/hash/try_convert_spec.rb
+++ b/spec/ruby/core/hash/try_convert_spec.rb
@@ -39,7 +39,7 @@ describe "Hash.try_convert" do
it "sends #to_hash to the argument and raises TypeError if it's not a kind of Hash" do
obj = mock("to_hash")
obj.should_receive(:to_hash).and_return(Object.new)
- -> { Hash.try_convert obj }.should raise_error(TypeError)
+ -> { Hash.try_convert obj }.should raise_error(TypeError, "can't convert MockObject to Hash (MockObject#to_hash gives Object)")
end
it "does not rescue exceptions raised by #to_hash" do
diff --git a/spec/ruby/core/integer/bit_and_spec.rb b/spec/ruby/core/integer/bit_and_spec.rb
index 15a8026855..e7face39ac 100644
--- a/spec/ruby/core/integer/bit_and_spec.rb
+++ b/spec/ruby/core/integer/bit_and_spec.rb
@@ -30,7 +30,7 @@ describe "Integer#&" do
it "coerces the rhs and calls #coerce" do
obj = mock("fixnum bit and")
- obj.should_receive(:coerce).with(6).and_return([3, 6])
+ obj.should_receive(:coerce).with(6).and_return([6, 3])
(6 & obj).should == 2
end
@@ -55,24 +55,24 @@ describe "Integer#&" do
@bignum = bignum_value(5)
(@bignum & 3).should == 1
(@bignum & 52).should == 4
- (@bignum & bignum_value(9921)).should == 9223372036854775809
+ (@bignum & bignum_value(9921)).should == 18446744073709551617
((2*bignum_value) & 1).should == 0
- ((2*bignum_value) & (2*bignum_value)).should == 18446744073709551616
+ ((2*bignum_value) & (2*bignum_value)).should == 36893488147419103232
end
it "returns self bitwise AND other when one operand is negative" do
((2*bignum_value) & -1).should == (2*bignum_value)
((4*bignum_value) & -1).should == (4*bignum_value)
- (@bignum & -0xffffffffffffff5).should == 9223372036854775809
+ (@bignum & -0xffffffffffffff5).should == 18446744073709551617
(@bignum & -@bignum).should == 1
- (@bignum & -0x8000000000000000).should == 9223372036854775808
+ (@bignum & -0x8000000000000000).should == 18446744073709551616
end
it "returns self bitwise AND other when both operands are negative" do
- (-@bignum & -0x4000000000000005).should == -13835058055282163717
- (-@bignum & -@bignum).should == -9223372036854775813
- (-@bignum & -0x4000000000000000).should == -13835058055282163712
+ (-@bignum & -0x4000000000000005).should == -23058430092136939525
+ (-@bignum & -@bignum).should == -18446744073709551621
+ (-@bignum & -0x4000000000000000).should == -23058430092136939520
end
it "returns self bitwise AND other when both are negative and a multiple in bitsize of Fixnum::MIN" do
diff --git a/spec/ruby/core/integer/bit_or_spec.rb b/spec/ruby/core/integer/bit_or_spec.rb
index e486eeec10..fdf8a191e5 100644
--- a/spec/ruby/core/integer/bit_or_spec.rb
+++ b/spec/ruby/core/integer/bit_or_spec.rb
@@ -7,13 +7,34 @@ describe "Integer#|" do
(5 | 4).should == 5
(5 | 6).should == 7
(248 | 4096).should == 4344
- (0xffff | bignum_value + 0xf0f0).should == 0x8000_0000_0000_ffff
+ (0xffff | bignum_value + 0xf0f0).should == 0x1_0000_0000_0000_ffff
+ end
+
+ it "returns self bitwise OR other when one operand is negative" do
+ ((1 << 33) | -1).should == -1
+ (-1 | (1 << 33)).should == -1
+
+ ((-(1<<33)-1) | 5).should == -8589934593
+ (5 | (-(1<<33)-1)).should == -8589934593
+ end
+
+ it "returns self bitwise OR other when both operands are negative" do
+ (-5 | -1).should == -1
+ (-3 | -4).should == -3
+ (-12 | -13).should == -9
+ (-13 | -12).should == -9
end
it "returns self bitwise OR a bignum" do
(-1 | 2**64).should == -1
end
+ it "coerces the rhs and calls #coerce" do
+ obj = mock("fixnum bit or")
+ obj.should_receive(:coerce).with(6).and_return([6, 3])
+ (6 | obj).should == 7
+ end
+
it "raises a TypeError when passed a Float" do
-> { (3 | 3.4) }.should raise_error(TypeError)
end
@@ -32,20 +53,20 @@ describe "Integer#|" do
end
it "returns self bitwise OR other" do
- (@bignum | 2).should == 9223372036854775819
- (@bignum | 9).should == 9223372036854775819
- (@bignum | bignum_value).should == 9223372036854775819
+ (@bignum | 2).should == 18446744073709551627
+ (@bignum | 9).should == 18446744073709551627
+ (@bignum | bignum_value).should == 18446744073709551627
end
it "returns self bitwise OR other when one operand is negative" do
- (@bignum | -0x40000000000000000).should == -64563604257983430645
+ (@bignum | -0x40000000000000000).should == -55340232221128654837
(@bignum | -@bignum).should == -1
(@bignum | -0x8000000000000000).should == -9223372036854775797
end
it "returns self bitwise OR other when both operands are negative" do
(-@bignum | -0x4000000000000005).should == -1
- (-@bignum | -@bignum).should == -9223372036854775819
+ (-@bignum | -@bignum).should == -18446744073709551627
(-@bignum | -0x4000000000000000).should == -11
end
diff --git a/spec/ruby/core/integer/bit_xor_spec.rb b/spec/ruby/core/integer/bit_xor_spec.rb
index ac8826a52f..1f46bc52f3 100644
--- a/spec/ruby/core/integer/bit_xor_spec.rb
+++ b/spec/ruby/core/integer/bit_xor_spec.rb
@@ -5,13 +5,34 @@ describe "Integer#^" do
it "returns self bitwise EXCLUSIVE OR other" do
(3 ^ 5).should == 6
(-2 ^ -255).should == 255
- (5 ^ bignum_value + 0xffff_ffff).should == 0x8000_0000_ffff_fffa
+ (5 ^ bignum_value + 0xffff_ffff).should == 0x1_0000_0000_ffff_fffa
+ end
+
+ it "returns self bitwise XOR other when one operand is negative" do
+ ((1 << 33) ^ -1).should == -8589934593
+ (-1 ^ (1 << 33)).should == -8589934593
+
+ ((-(1<<33)-1) ^ 5).should == -8589934598
+ (5 ^ (-(1<<33)-1)).should == -8589934598
+ end
+
+ it "returns self bitwise XOR other when both operands are negative" do
+ (-5 ^ -1).should == 4
+ (-3 ^ -4).should == 1
+ (-12 ^ -13).should == 7
+ (-13 ^ -12).should == 7
end
it "returns self bitwise EXCLUSIVE OR a bignum" do
(-1 ^ 2**64).should == -18446744073709551617
end
+ it "coerces the rhs and calls #coerce" do
+ obj = mock("fixnum bit xor")
+ obj.should_receive(:coerce).with(6).and_return([6, 3])
+ (6 ^ obj).should == 5
+ end
+
it "raises a TypeError when passed a Float" do
-> { (3 ^ 3.4) }.should raise_error(TypeError)
end
@@ -30,21 +51,21 @@ describe "Integer#^" do
end
it "returns self bitwise EXCLUSIVE OR other" do
- (@bignum ^ 2).should == 9223372036854775824
+ (@bignum ^ 2).should == 18446744073709551632
(@bignum ^ @bignum).should == 0
- (@bignum ^ 14).should == 9223372036854775836
+ (@bignum ^ 14).should == 18446744073709551644
end
it "returns self bitwise EXCLUSIVE OR other when one operand is negative" do
- (@bignum ^ -0x40000000000000000).should == -64563604257983430638
+ (@bignum ^ -0x40000000000000000).should == -55340232221128654830
(@bignum ^ -@bignum).should == -4
- (@bignum ^ -0x8000000000000000).should == -18446744073709551598
+ (@bignum ^ -0x8000000000000000).should == -27670116110564327406
end
it "returns self bitwise EXCLUSIVE OR other when both operands are negative" do
- (-@bignum ^ -0x40000000000000000).should == 64563604257983430638
+ (-@bignum ^ -0x40000000000000000).should == 55340232221128654830
(-@bignum ^ -@bignum).should == 0
- (-@bignum ^ -0x4000000000000000).should == 13835058055282163694
+ (-@bignum ^ -0x4000000000000000).should == 23058430092136939502
end
it "returns self bitwise EXCLUSIVE OR other when all bits are 1 and other value is negative" do
diff --git a/spec/ruby/core/integer/ceildiv_spec.rb b/spec/ruby/core/integer/ceildiv_spec.rb
new file mode 100644
index 0000000000..18d07c66d0
--- /dev/null
+++ b/spec/ruby/core/integer/ceildiv_spec.rb
@@ -0,0 +1,22 @@
+require_relative '../../spec_helper'
+
+describe "Integer#ceildiv" do
+ ruby_version_is '3.2' do
+ it "returns a quotient of division which is rounded up to the nearest integer" do
+ 0.ceildiv(3).should eql(0)
+ 1.ceildiv(3).should eql(1)
+ 3.ceildiv(3).should eql(1)
+ 4.ceildiv(3).should eql(2)
+
+ 4.ceildiv(-3).should eql(-1)
+ -4.ceildiv(3).should eql(-1)
+ -4.ceildiv(-3).should eql(2)
+
+ 3.ceildiv(1.2).should eql(3)
+ 3.ceildiv(6/5r).should eql(3)
+
+ (10**100-11).ceildiv(10**99-1).should eql(10)
+ (10**100-9).ceildiv(10**99-1).should eql(11)
+ end
+ end
+end
diff --git a/spec/ruby/core/integer/chr_spec.rb b/spec/ruby/core/integer/chr_spec.rb
index 9f105e4241..8fe20ff812 100644
--- a/spec/ruby/core/integer/chr_spec.rb
+++ b/spec/ruby/core/integer/chr_spec.rb
@@ -11,7 +11,11 @@ describe "Integer#chr without argument" do
it "raises a RangeError is self is less than 0" do
-> { -1.chr }.should raise_error(RangeError)
- -> { -bignum_value.chr }.should raise_error(RangeError)
+ -> { (-bignum_value).chr }.should raise_error(RangeError)
+ end
+
+ it "raises a RangeError if self is too large" do
+ -> { 2206368128.chr(Encoding::UTF_8) }.should raise_error(RangeError)
end
describe "when Encoding.default_internal is nil" do
@@ -162,7 +166,7 @@ describe "Integer#chr with an encoding argument" do
# http://redmine.ruby-lang.org/issues/4869
it "raises a RangeError is self is less than 0" do
-> { -1.chr(Encoding::UTF_8) }.should raise_error(RangeError)
- -> { -bignum_value.chr(Encoding::EUC_JP) }.should raise_error(RangeError)
+ -> { (-bignum_value).chr(Encoding::EUC_JP) }.should raise_error(RangeError)
end
it "raises a RangeError if self is too large" do
@@ -219,38 +223,35 @@ describe "Integer#chr with an encoding argument" do
# #5864
it "raises RangeError if self is invalid as a codepoint in the specified encoding" do
- [ [0x80, "US-ASCII"],
- [0x0100, "BINARY"],
- [0x0100, "EUC-JP"],
- [0xA1A0, "EUC-JP"],
- [0xA1, "EUC-JP"],
- [0x80, "SHIFT_JIS"],
- [0xE0, "SHIFT_JIS"],
- [0x0100, "ISO-8859-9"],
- [620, "TIS-620"],
- [0xD800, "UTF-8"],
- [0xDBFF, "UTF-8"],
- [0xDC00, "UTF-8"],
- [0xDFFF, "UTF-8"],
- [0xD800, "UTF-16"],
- [0xDBFF, "UTF-16"],
- [0xDC00, "UTF-16"],
- [0xDFFF, "UTF-16"],
- ].each do |integer, encoding_name|
- -> { integer.chr(encoding_name) }.should raise_error(RangeError)
- end
+ -> { 0x80.chr("US-ASCII") }.should raise_error(RangeError)
+ -> { 0x0100.chr("BINARY") }.should raise_error(RangeError)
+ -> { 0x0100.chr("EUC-JP") }.should raise_error(RangeError)
+ -> { 0xA1A0.chr("EUC-JP") }.should raise_error(RangeError)
+ -> { 0xA1.chr("EUC-JP") }.should raise_error(RangeError)
+ -> { 0x80.chr("SHIFT_JIS") }.should raise_error(RangeError)
+ -> { 0xE0.chr("SHIFT_JIS") }.should raise_error(RangeError)
+ -> { 0x0100.chr("ISO-8859-9") }.should raise_error(RangeError)
+ -> { 620.chr("TIS-620") }.should raise_error(RangeError)
+ # UTF-16 surrogate range
+ -> { 0xD800.chr("UTF-8") }.should raise_error(RangeError)
+ -> { 0xDBFF.chr("UTF-8") }.should raise_error(RangeError)
+ -> { 0xDC00.chr("UTF-8") }.should raise_error(RangeError)
+ -> { 0xDFFF.chr("UTF-8") }.should raise_error(RangeError)
+ # UTF-16 surrogate range
+ -> { 0xD800.chr("UTF-16") }.should raise_error(RangeError)
+ -> { 0xDBFF.chr("UTF-16") }.should raise_error(RangeError)
+ -> { 0xDC00.chr("UTF-16") }.should raise_error(RangeError)
+ -> { 0xDFFF.chr("UTF-16") }.should raise_error(RangeError)
end
- ruby_version_is "2.7" do
- it 'returns a String encoding self interpreted as a codepoint in the CESU-8 encoding' do
- # see more details here https://en.wikipedia.org/wiki/CESU-8
- # code points from U+0000 to U+FFFF is encoded in the same way as in UTF-8
- 0x0045.chr(Encoding::CESU_8).bytes.should == 0x0045.chr(Encoding::UTF_8).bytes
+ it 'returns a String encoding self interpreted as a codepoint in the CESU-8 encoding' do
+ # see more details here https://en.wikipedia.org/wiki/CESU-8
+ # code points from U+0000 to U+FFFF is encoded in the same way as in UTF-8
+ 0x0045.chr(Encoding::CESU_8).bytes.should == 0x0045.chr(Encoding::UTF_8).bytes
- # code points in range from U+10000 to U+10FFFF is CESU-8 data containing a 6-byte surrogate pair,
- # which decodes to a 4-byte UTF-8 string
- 0x10400.chr(Encoding::CESU_8).bytes.should != 0x10400.chr(Encoding::UTF_8).bytes
- 0x10400.chr(Encoding::CESU_8).bytes.to_a.should == [0xED, 0xA0, 0x81, 0xED, 0xB0, 0x80]
- end
+ # code points in range from U+10000 to U+10FFFF is CESU-8 data containing a 6-byte surrogate pair,
+ # which decodes to a 4-byte UTF-8 string
+ 0x10400.chr(Encoding::CESU_8).bytes.should != 0x10400.chr(Encoding::UTF_8).bytes
+ 0x10400.chr(Encoding::CESU_8).bytes.to_a.should == [0xED, 0xA0, 0x81, 0xED, 0xB0, 0x80]
end
end
diff --git a/spec/ruby/core/integer/coerce_spec.rb b/spec/ruby/core/integer/coerce_spec.rb
index f1f3256032..1d6dc9713f 100644
--- a/spec/ruby/core/integer/coerce_spec.rb
+++ b/spec/ruby/core/integer/coerce_spec.rb
@@ -1,7 +1,5 @@
require_relative '../../spec_helper'
-require 'bigdecimal'
-
describe "Integer#coerce" do
context "fixnum" do
describe "when given a Fixnum" do
@@ -90,15 +88,4 @@ describe "Integer#coerce" do
ary.should == [1.2, a.to_f]
end
end
-
- context "bigdecimal" do
- it "produces Floats" do
- x, y = 3.coerce(BigDecimal("3.4"))
- x.class.should == Float
- x.should == 3.4
- y.class.should == Float
- y.should == 3.0
- end
- end
-
end
diff --git a/spec/ruby/core/integer/complement_spec.rb b/spec/ruby/core/integer/complement_spec.rb
index eafa5c263f..baf5e6c457 100644
--- a/spec/ruby/core/integer/complement_spec.rb
+++ b/spec/ruby/core/integer/complement_spec.rb
@@ -12,9 +12,9 @@ describe "Integer#~" do
context "bignum" do
it "returns self with each bit flipped" do
- (~bignum_value(48)).should == -9223372036854775857
- (~(-bignum_value(21))).should == 9223372036854775828
- (~bignum_value(1)).should == -9223372036854775810
+ (~bignum_value(48)).should == -18446744073709551665
+ (~(-bignum_value(21))).should == 18446744073709551636
+ (~bignum_value(1)).should == -18446744073709551618
end
end
end
diff --git a/spec/ruby/core/integer/div_spec.rb b/spec/ruby/core/integer/div_spec.rb
index bc1c4363d4..2eb9c0623b 100644
--- a/spec/ruby/core/integer/div_spec.rb
+++ b/spec/ruby/core/integer/div_spec.rb
@@ -70,8 +70,8 @@ describe "Integer#div" do
end
it "returns self divided by other" do
- @bignum.div(4).should == 2305843009213693974
- @bignum.div(Rational(4, 1)).should == 2305843009213693974
+ @bignum.div(4).should == 4611686018427387926
+ @bignum.div(Rational(4, 1)).should == 4611686018427387926
@bignum.div(bignum_value(2)).should == 1
(-(10**50)).div(-(10**40 + 1)).should == 9999999999
@@ -124,11 +124,11 @@ describe "Integer#div" do
end
it "returns a result of integer division of self by a float argument" do
- @bignum.div(4294967295.5).should eql(2147483648)
+ @bignum.div(4294967295.5).should eql(4294967296)
not_supported_on :opal do
- @bignum.div(4294967295.0).should eql(2147483648)
+ @bignum.div(4294967295.0).should eql(4294967297)
@bignum.div(bignum_value(88).to_f).should eql(1)
- @bignum.div(-bignum_value(88).to_f).should eql(-1)
+ @bignum.div((-bignum_value(88)).to_f).should eql(-1)
end
end
@@ -143,4 +143,12 @@ describe "Integer#div" do
-> { @bignum.div(-0) }.should raise_error(ZeroDivisionError)
end
end
+
+ context "rational" do
+ it "returns self divided by the given argument as an Integer" do
+ 2.div(6/5r).should == 1
+ 1.div(6/5r).should == 0
+ 5.div(6/5r).should == 4
+ end
+ end
end
diff --git a/spec/ruby/core/integer/divide_spec.rb b/spec/ruby/core/integer/divide_spec.rb
index 5ac2dc538d..a878c4668c 100644
--- a/spec/ruby/core/integer/divide_spec.rb
+++ b/spec/ruby/core/integer/divide_spec.rb
@@ -47,7 +47,7 @@ describe "Integer#/" do
end
it "returns self divided by other" do
- (@bignum / 4).should == 2305843009213693974
+ (@bignum / 4).should == 4611686018427387926
(@bignum / bignum_value(2)).should == 1
@@ -60,15 +60,15 @@ describe "Integer#/" do
it "returns self divided by Float" do
not_supported_on :opal do
- (bignum_value(88) / 4294967295.0).should be_close(2147483648.5, TOLERANCE)
+ (bignum_value(88) / 4294967295.0).should be_close(4294967297.0, TOLERANCE)
end
- (bignum_value(88) / 4294967295.5).should be_close(2147483648.25, TOLERANCE)
+ (bignum_value(88) / 4294967295.5).should be_close(4294967296.5, TOLERANCE)
end
it "returns result the same class as the argument" do
- (@bignum / 4).should == 2305843009213693974
- (@bignum / 4.0).should be_close(2305843009213693974, TOLERANCE)
- (@bignum / Rational(4, 1)).should == Rational(2305843009213693974, 1)
+ (@bignum / 4).should == 4611686018427387926
+ (@bignum / 4.0).should be_close(4611686018427387926, TOLERANCE)
+ (@bignum / Rational(4, 1)).should == Rational(4611686018427387926, 1)
end
it "does NOT raise ZeroDivisionError if other is zero and is a Float" do
diff --git a/spec/ruby/core/integer/divmod_spec.rb b/spec/ruby/core/integer/divmod_spec.rb
index d88925caad..7a489e9344 100644
--- a/spec/ruby/core/integer/divmod_spec.rb
+++ b/spec/ruby/core/integer/divmod_spec.rb
@@ -46,16 +46,16 @@ describe "Integer#divmod" do
# assert(0 < b ? (0 <= r && r < b) : (b < r && r <= 0))
# So, r is always between 0 and b.
it "returns an Array containing quotient and modulus obtained from dividing self by the given argument" do
- @bignum.divmod(4).should == [2305843009213693965, 3]
- @bignum.divmod(13).should == [709490156681136604, 11]
+ @bignum.divmod(4).should == [4611686018427387917, 3]
+ @bignum.divmod(13).should == [1418980313362273205, 6]
- @bignum.divmod(4.5).should == [2049638230412172288, 3.5]
+ @bignum.divmod(4.5).should == [4099276460824344576, 2.5]
not_supported_on :opal do
- @bignum.divmod(4.0).should == [2305843009213693952, 0.0]
- @bignum.divmod(13.0).should == [709490156681136640, 8.0]
+ @bignum.divmod(4.0).should == [4611686018427387904, 0.0]
+ @bignum.divmod(13.0).should == [1418980313362273280, 3.0]
- @bignum.divmod(2.0).should == [4611686018427387904, 0.0]
+ @bignum.divmod(2.0).should == [9223372036854775808, 0.0]
end
@bignum.divmod(bignum_value).should == [1, 55]
diff --git a/spec/ruby/core/integer/element_reference_spec.rb b/spec/ruby/core/integer/element_reference_spec.rb
index 7197ecdc03..cb7e0dc9b0 100644
--- a/spec/ruby/core/integer/element_reference_spec.rb
+++ b/spec/ruby/core/integer/element_reference_spec.rb
@@ -79,81 +79,79 @@ describe "Integer#[]" do
3[bignum_value.to_f].should == 0
end
- ruby_version_is "2.7" do
- context "when index and length passed" do
- it "returns specified number of bits from specified position" do
- 0b101001101[2, 4].should == 0b0011
- 0b101001101[2, 5].should == 0b10011
- 0b101001101[2, 7].should == 0b1010011
- end
+ context "when index and length passed" do
+ it "returns specified number of bits from specified position" do
+ 0b101001101[2, 4].should == 0b0011
+ 0b101001101[2, 5].should == 0b10011
+ 0b101001101[2, 7].should == 0b1010011
+ end
- it "ensures n[i, len] equals to (n >> i) & ((1 << len) - 1)" do
- n = 0b101001101; i = 2; len = 4
- n[i, len].should == (n >> i) & ((1 << len) - 1)
- end
+ it "ensures n[i, len] equals to (n >> i) & ((1 << len) - 1)" do
+ n = 0b101001101; i = 2; len = 4
+ n[i, len].should == (n >> i) & ((1 << len) - 1)
+ end
- it "moves start position to the most significant bits when negative index passed" do
- 0b000001[-1, 4].should == 0b10
- 0b000001[-2, 4].should == 0b100
- 0b000001[-3, 4].should == 0b1000
- end
+ it "moves start position to the most significant bits when negative index passed" do
+ 0b000001[-1, 4].should == 0b10
+ 0b000001[-2, 4].should == 0b100
+ 0b000001[-3, 4].should == 0b1000
+ end
- it "ignores negative length" do
- 0b101001101[1, -1].should == 0b10100110
- 0b101001101[2, -1].should == 0b1010011
- 0b101001101[3, -1].should == 0b101001
+ it "ignores negative length" do
+ 0b101001101[1, -1].should == 0b10100110
+ 0b101001101[2, -1].should == 0b1010011
+ 0b101001101[3, -1].should == 0b101001
- 0b101001101[3, -5].should == 0b101001
- 0b101001101[3, -15].should == 0b101001
- 0b101001101[3, -125].should == 0b101001
- end
+ 0b101001101[3, -5].should == 0b101001
+ 0b101001101[3, -15].should == 0b101001
+ 0b101001101[3, -125].should == 0b101001
end
+ end
- context "when range passed" do
- it "returns bits specified by range" do
- 0b101001101[2..5].should == 0b0011
- 0b101001101[2..6].should == 0b10011
- 0b101001101[2..8].should == 0b1010011
- end
+ context "when range passed" do
+ it "returns bits specified by range" do
+ 0b101001101[2..5].should == 0b0011
+ 0b101001101[2..6].should == 0b10011
+ 0b101001101[2..8].should == 0b1010011
+ end
- it "ensures n[i..j] equals to (n >> i) & ((1 << (j - i + 1)) - 1)" do
- n = 0b101001101; i = 2; j = 5
- n[i..j].should == (n >> i) & ((1 << (j - i + 1)) - 1)
- end
+ it "ensures n[i..j] equals to (n >> i) & ((1 << (j - i + 1)) - 1)" do
+ n = 0b101001101; i = 2; j = 5
+ n[i..j].should == (n >> i) & ((1 << (j - i + 1)) - 1)
+ end
- it "ensures n[i..] equals to (n >> i)" do
- eval("0b101001101[3..]").should == 0b101001101 >> 3
- end
+ it "ensures n[i..] equals to (n >> i)" do
+ eval("0b101001101[3..]").should == 0b101001101 >> 3
+ end
- it "moves lower boundary to the most significant bits when negative value passed" do
- 0b000001[-1, 4].should == 0b10
- 0b000001[-2, 4].should == 0b100
- 0b000001[-3, 4].should == 0b1000
- end
+ it "moves lower boundary to the most significant bits when negative value passed" do
+ 0b000001[-1, 4].should == 0b10
+ 0b000001[-2, 4].should == 0b100
+ 0b000001[-3, 4].should == 0b1000
+ end
- it "ignores upper boundary smaller than lower boundary" do
- 0b101001101[4..1].should == 0b10100
- 0b101001101[4..2].should == 0b10100
- 0b101001101[-4..-5].should == 0b1010011010000
- end
+ it "ignores upper boundary smaller than lower boundary" do
+ 0b101001101[4..1].should == 0b10100
+ 0b101001101[4..2].should == 0b10100
+ 0b101001101[-4..-5].should == 0b1010011010000
+ end
+
+ it "raises FloatDomainError if any boundary is infinity" do
+ -> { 0x0001[3..Float::INFINITY] }.should raise_error(FloatDomainError, /Infinity/)
+ -> { 0x0001[-Float::INFINITY..3] }.should raise_error(FloatDomainError, /-Infinity/)
+ end
- it "raises FloatDomainError if any boundary is infinity" do
- -> { 0x0001[3..Float::INFINITY] }.should raise_error(FloatDomainError, /Infinity/)
- -> { 0x0001[-Float::INFINITY..3] }.should raise_error(FloatDomainError, /-Infinity/)
+ context "when passed (..i)" do
+ it "returns 0 if all i bits equal 0" do
+ eval("0b10000[..1]").should == 0
+ eval("0b10000[..2]").should == 0
+ eval("0b10000[..3]").should == 0
end
- context "when passed (..i)" do
- it "returns 0 if all i bits equal 0" do
- eval("0b10000[..1]").should == 0
- eval("0b10000[..2]").should == 0
- eval("0b10000[..3]").should == 0
- end
-
- it "raises ArgumentError if any of i bit equals 1" do
- -> {
- eval("0b111110[..3]")
- }.should raise_error(ArgumentError, /The beginless range for Integer#\[\] results in infinity/)
- end
+ it "raises ArgumentError if any of i bit equals 1" do
+ -> {
+ eval("0b111110[..3]")
+ }.should raise_error(ArgumentError, /The beginless range for Integer#\[\] results in infinity/)
end
end
end
diff --git a/spec/ruby/core/integer/fdiv_spec.rb b/spec/ruby/core/integer/fdiv_spec.rb
index 6de170278f..d9ea2fdf8d 100644
--- a/spec/ruby/core/integer/fdiv_spec.rb
+++ b/spec/ruby/core/integer/fdiv_spec.rb
@@ -9,6 +9,57 @@ describe "Integer#fdiv" do
8.fdiv(bignum_value).should be_close(8.673617379884035e-19, TOLERANCE)
end
+ it "performs floating-point division between self bignum and a bignum" do
+ num = 1000000000000000000000000000000000048148248609680896326399448564623182963452541226153892315137780403285956264146010000000000000000000000000000000000048148248609680896326399448564623182963452541226153892315137780403285956264146010000000000000000000000000000000000048148248609680896326399448564623182963452541226153892315137780403285956264146009
+ den = 2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+ num.fdiv(den).should == 500.0
+ end
+
+ it "rounds to the correct value for bignums" do
+ den = 9 * 10**342
+
+ num = 1 * 10**344
+ num.fdiv(den).should == 11.11111111111111
+
+ num = 1 * 10**343
+ num.fdiv(den).should == 1.1111111111111112
+
+ num = 1 * 10**342
+ num.fdiv(den).should == 0.1111111111111111
+
+ num = 2 * 10**342
+ num.fdiv(den).should == 0.2222222222222222
+
+ num = 3 * 10**342
+ num.fdiv(den).should == 0.3333333333333333
+
+ num = 4 * 10**342
+ num.fdiv(den).should == 0.4444444444444444
+
+ num = 5 * 10**342
+ num.fdiv(den).should == 0.5555555555555556
+
+ num = 6 * 10**342
+ num.fdiv(den).should == 0.6666666666666666
+
+ num = 7 * 10**342
+ num.fdiv(den).should == 0.7777777777777778
+
+ num = 8 * 10**342
+ num.fdiv(den).should == 0.8888888888888888
+
+ num = 9 * 10**342
+ num.fdiv(den).should == 1.0
+
+ num = -5 * 10**342
+ num.fdiv(den).should == -0.5555555555555556
+ end
+
+ it "rounds to the correct float for bignum denominators" do
+ 1.fdiv(10**324).should == 0.0
+ 1.fdiv(10**323).should == 1.0e-323
+ end
+
it "performs floating-point division between self and a Float" do
8.fdiv(9.0).should be_close(0.888888888888889, TOLERANCE)
end
diff --git a/spec/ruby/core/integer/left_shift_spec.rb b/spec/ruby/core/integer/left_shift_spec.rb
index 2b8c26223b..0781371d93 100644
--- a/spec/ruby/core/integer/left_shift_spec.rb
+++ b/spec/ruby/core/integer/left_shift_spec.rb
@@ -96,7 +96,7 @@ describe "Integer#<< (with n << m)" do
context "bignum" do
before :each do
- @bignum = bignum_value * 16
+ @bignum = bignum_value * 8 # 2 ** 67
end
it "returns n shifted left m bits when n > 0, m > 0" do
@@ -127,10 +127,6 @@ describe "Integer#<< (with n << m)" do
(@bignum << -68).should == 0
end
- it "returns 0 when m < 0 and m is a Bignum" do
- (@bignum << -bignum_value).should == 0
- end
-
it "returns a Fixnum == fixnum_max when (fixnum_max * 2) << -1 and n > 0" do
result = (fixnum_max * 2) << -1
result.should be_an_instance_of(Integer)
@@ -165,4 +161,53 @@ describe "Integer#<< (with n << m)" do
-> { @bignum << "4" }.should raise_error(TypeError)
end
end
+
+ context "when m is a bignum or larger than int" do
+ it "returns -1 when m < 0 and n < 0" do
+ (-1 << -bignum_value).should == -1
+ (-1 << -(2**40)).should == -1
+
+ (-bignum_value << -bignum_value).should == -1
+ (-bignum_value << -(2**40)).should == -1
+ end
+
+ it "returns 0 when m < 0 and n >= 0" do
+ (0 << -bignum_value).should == 0
+ (1 << -bignum_value).should == 0
+ (bignum_value << -bignum_value).should == 0
+
+ (0 << -(2**40)).should == 0
+ (1 << -(2**40)).should == 0
+ (bignum_value << -(2**40)).should == 0
+ end
+
+ ruby_bug "#18517", ""..."3.2" do
+ it "returns 0 when m > 0 long and n == 0" do
+ (0 << (2**40)).should == 0
+ end
+ end
+
+ it "returns 0 when m > 0 bignum and n == 0" do
+ (0 << bignum_value).should == 0
+ end
+
+ it "raises RangeError when m > 0 and n != 0" do
+ # https://bugs.ruby-lang.org/issues/18518#note-9
+ limit = RUBY_ENGINE == 'ruby' ? 2**67 : 2**32
+
+ coerce_long = mock("long")
+ coerce_long.stub!(:to_int).and_return(limit)
+ coerce_bignum = mock("bignum")
+ coerce_bignum.stub!(:to_int).and_return(bignum_value)
+ exps = [limit, coerce_long]
+ exps << bignum_value << coerce_bignum if bignum_value >= limit
+
+ exps.each { |exp|
+ -> { (1 << exp) }.should raise_error(RangeError, 'shift width too big')
+ -> { (-1 << exp) }.should raise_error(RangeError, 'shift width too big')
+ -> { (bignum_value << exp) }.should raise_error(RangeError, 'shift width too big')
+ -> { (-bignum_value << exp) }.should raise_error(RangeError, 'shift width too big')
+ }
+ end
+ end
end
diff --git a/spec/ruby/core/integer/minus_spec.rb b/spec/ruby/core/integer/minus_spec.rb
index ce50c8752f..aadf416a05 100644
--- a/spec/ruby/core/integer/minus_spec.rb
+++ b/spec/ruby/core/integer/minus_spec.rb
@@ -10,7 +10,7 @@ describe "Integer#-" do
(9237212 - 5_280).should == 9231932
(781 - 0.5).should == 780.5
- (2_560_496 - bignum_value).should == -9223372036852215312
+ (2_560_496 - bignum_value).should == -18446744073706991120
end
it "raises a TypeError when given a non-Integer" do
@@ -29,8 +29,8 @@ describe "Integer#-" do
end
it "returns self minus the given Integer" do
- (@bignum - 9).should == 9223372036854776113
- (@bignum - 12.57).should be_close(9223372036854776109.43, TOLERANCE)
+ (@bignum - 9).should == 18446744073709551921
+ (@bignum - 12.57).should be_close(18446744073709551917.43, TOLERANCE)
(@bignum - bignum_value(42)).should == 272
end
diff --git a/spec/ruby/core/integer/multiply_spec.rb b/spec/ruby/core/integer/multiply_spec.rb
index d1e9c2640d..5037d27458 100644
--- a/spec/ruby/core/integer/multiply_spec.rb
+++ b/spec/ruby/core/integer/multiply_spec.rb
@@ -10,7 +10,7 @@ describe "Integer#*" do
(1342177 * 800).should == 1073741600
(65536 * 65536).should == 4294967296
- (256 * bignum_value).should == 2361183241434822606848
+ (256 * bignum_value).should == 4722366482869645213696
(6712 * 0.25).should == 1678.0
end
@@ -32,8 +32,8 @@ describe "Integer#*" do
it "returns self multiplied by the given Integer" do
(@bignum * (1/bignum_value(0xffff).to_f)).should be_close(1.0, TOLERANCE)
(@bignum * (1/bignum_value(0xffff).to_f)).should be_close(1.0, TOLERANCE)
- (@bignum * 10).should == 92233720368547765800
- (@bignum * (@bignum - 40)).should == 85070591730234629737795195287525433200
+ (@bignum * 10).should == 184467440737095523880
+ (@bignum * (@bignum - 40)).should == 340282366920938491207277694290934407024
end
it "raises a TypeError when given a non-Integer" do
diff --git a/spec/ruby/core/integer/plus_spec.rb b/spec/ruby/core/integer/plus_spec.rb
index 511a436872..d01a76ab58 100644
--- a/spec/ruby/core/integer/plus_spec.rb
+++ b/spec/ruby/core/integer/plus_spec.rb
@@ -9,7 +9,7 @@ describe "Integer#+" do
(491 + 2).should == 493
(90210 + 10).should == 90220
- (9 + bignum_value).should == 9223372036854775817
+ (9 + bignum_value).should == 18446744073709551625
(1001 + 5.219).should == 1006.219
end
@@ -29,9 +29,9 @@ describe "Integer#+" do
end
it "returns self plus the given Integer" do
- (@bignum + 4).should == 9223372036854775888
- (@bignum + 4.2).should be_close(9223372036854775888.2, TOLERANCE)
- (@bignum + bignum_value(3)).should == 18446744073709551695
+ (@bignum + 4).should == 18446744073709551696
+ (@bignum + 4.2).should be_close(18446744073709551696.2, TOLERANCE)
+ (@bignum + bignum_value(3)).should == 36893488147419103311
end
it "raises a TypeError when given a non-Integer" do
diff --git a/spec/ruby/core/integer/remainder_spec.rb b/spec/ruby/core/integer/remainder_spec.rb
index cd10dad6f2..96268b3af5 100644
--- a/spec/ruby/core/integer/remainder_spec.rb
+++ b/spec/ruby/core/integer/remainder_spec.rb
@@ -33,7 +33,7 @@ describe "Integer#remainder" do
it "returns the remainder of dividing self by other" do
a = bignum_value(79)
a.remainder(2).should == 1
- a.remainder(97.345).should be_close(46.5674996147722, TOLERANCE)
+ a.remainder(97.345).should be_close(93.1349992295444, TOLERANCE)
a.remainder(bignum_value).should == 79
end
diff --git a/spec/ruby/core/integer/right_shift_spec.rb b/spec/ruby/core/integer/right_shift_spec.rb
index c8e3f45f21..e91613d8d1 100644
--- a/spec/ruby/core/integer/right_shift_spec.rb
+++ b/spec/ruby/core/integer/right_shift_spec.rb
@@ -52,10 +52,6 @@ describe "Integer#>> (with n >> m)" do
(-7 >> 64).should == -1
end
- it "returns 0 when m is a bignum" do
- (3 >> bignum_value).should == 0
- end
-
it "returns a Bignum == fixnum_max * 2 when fixnum_max >> -1 and n > 0" do
result = fixnum_max >> -1
result.should be_an_instance_of(Integer)
@@ -96,7 +92,7 @@ describe "Integer#>> (with n >> m)" do
context "bignum" do
before :each do
- @bignum = bignum_value * 16
+ @bignum = bignum_value * 8 # 2 ** 67
end
it "returns n shifted right m bits when n > 0, m > 0" do
@@ -153,10 +149,6 @@ describe "Integer#>> (with n >> m)" do
(@bignum >> 68).should == 0
end
- it "returns 0 when m is a Bignum" do
- (@bignum >> bignum_value).should == 0
- end
-
it "returns a Fixnum == fixnum_max when (fixnum_max * 2) >> 1 and n > 0" do
result = (fixnum_max * 2) >> 1
result.should be_an_instance_of(Integer)
@@ -191,4 +183,53 @@ describe "Integer#>> (with n >> m)" do
-> { @bignum >> "4" }.should raise_error(TypeError)
end
end
+
+ context "when m is a bignum or larger than int" do
+ it "returns -1 when m > 0 and n < 0" do
+ (-1 >> bignum_value).should == -1
+ (-1 >> (2**40)).should == -1
+
+ (-bignum_value >> bignum_value).should == -1
+ (-bignum_value >> (2**40)).should == -1
+ end
+
+ it "returns 0 when m > 0 and n >= 0" do
+ (0 >> bignum_value).should == 0
+ (1 >> bignum_value).should == 0
+ (bignum_value >> bignum_value).should == 0
+
+ (0 >> (2**40)).should == 0
+ (1 >> (2**40)).should == 0
+ (bignum_value >> (2**40)).should == 0
+ end
+
+ ruby_bug "#18517", ""..."3.2" do
+ it "returns 0 when m < 0 long and n == 0" do
+ (0 >> -(2**40)).should == 0
+ end
+ end
+
+ it "returns 0 when m < 0 bignum and n == 0" do
+ (0 >> -bignum_value).should == 0
+ end
+
+ it "raises RangeError when m < 0 and n != 0" do
+ # https://bugs.ruby-lang.org/issues/18518#note-9
+ limit = RUBY_ENGINE == 'ruby' ? 2**67 : 2**32
+
+ coerce_long = mock("long")
+ coerce_long.stub!(:to_int).and_return(-limit)
+ coerce_bignum = mock("bignum")
+ coerce_bignum.stub!(:to_int).and_return(-bignum_value)
+ exps = [-limit, coerce_long]
+ exps << -bignum_value << coerce_bignum if bignum_value >= limit
+
+ exps.each { |exp|
+ -> { (1 >> exp) }.should raise_error(RangeError, 'shift width too big')
+ -> { (-1 >> exp) }.should raise_error(RangeError, 'shift width too big')
+ -> { (bignum_value >> exp) }.should raise_error(RangeError, 'shift width too big')
+ -> { (-bignum_value >> exp) }.should raise_error(RangeError, 'shift width too big')
+ }
+ end
+ end
end
diff --git a/spec/ruby/core/integer/shared/abs.rb b/spec/ruby/core/integer/shared/abs.rb
index 946aa21864..43844c9065 100644
--- a/spec/ruby/core/integer/shared/abs.rb
+++ b/spec/ruby/core/integer/shared/abs.rb
@@ -11,8 +11,8 @@ describe :integer_abs, shared: true do
context "bignum" do
it "returns the absolute bignum value" do
- bignum_value(39).send(@method).should == 9223372036854775847
- (-bignum_value(18)).send(@method).should == 9223372036854775826
+ bignum_value(39).send(@method).should == 18446744073709551655
+ (-bignum_value(18)).send(@method).should == 18446744073709551634
end
end
end
diff --git a/spec/ruby/core/integer/shared/arithmetic_coerce.rb b/spec/ruby/core/integer/shared/arithmetic_coerce.rb
index 4c0cbcb999..1260192df1 100644
--- a/spec/ruby/core/integer/shared/arithmetic_coerce.rb
+++ b/spec/ruby/core/integer/shared/arithmetic_coerce.rb
@@ -1,25 +1,5 @@
require_relative '../fixtures/classes'
-describe :integer_arithmetic_coerce_rescue, shared: true do
- it "rescues exception (StandardError and subclasses) raised in other#coerce and raises TypeError" do
- b = mock("numeric with failed #coerce")
- b.should_receive(:coerce).and_raise(IntegerSpecs::CoerceError)
-
- # e.g. 1 + b
- -> { 1.send(@method, b) }.should raise_error(TypeError, /MockObject can't be coerced into Integer/)
- end
-
- it "does not rescue Exception and StandardError siblings raised in other#coerce" do
- [Exception, NoMemoryError].each do |exception|
- b = mock("numeric with failed #coerce")
- b.should_receive(:coerce).and_raise(exception)
-
- # e.g. 1 + b
- -> { 1.send(@method, b) }.should raise_error(exception)
- end
- end
-end
-
describe :integer_arithmetic_coerce_not_rescue, shared: true do
it "does not rescue exception raised in other#coerce" do
b = mock("numeric with failed #coerce")
diff --git a/spec/ruby/core/integer/shared/exponent.rb b/spec/ruby/core/integer/shared/exponent.rb
index f949c514c8..15df518b7e 100644
--- a/spec/ruby/core/integer/shared/exponent.rb
+++ b/spec/ruby/core/integer/shared/exponent.rb
@@ -30,11 +30,13 @@ describe :integer_exponent, shared: true do
(-2).send(@method, 30).should eql(1073741824)
(-2).send(@method, 31).should eql(-2147483648)
(-2).send(@method, 32).should eql(4294967296)
+ (-2).send(@method, 33).should eql(-8589934592)
(-2).send(@method, 61).should eql(-2305843009213693952)
(-2).send(@method, 62).should eql(4611686018427387904)
(-2).send(@method, 63).should eql(-9223372036854775808)
(-2).send(@method, 64).should eql(18446744073709551616)
+ (-2).send(@method, 65).should eql(-36893488147419103232)
end
it "can raise 1 to a bignum safely" do
@@ -96,8 +98,8 @@ describe :integer_exponent, shared: true do
end
it "returns self raised to other power" do
- (@bignum.send(@method, 4)).should == 7237005577332262361485077344629993318496048279512298547155833600056910050625
- (@bignum.send(@method, 1.2)).should be_close(57262152889751597425762.57804, TOLERANCE)
+ (@bignum.send(@method, 4)).should == 115792089237316196603666111261383895964500887398800252671052694326794607293761
+ (@bignum.send(@method, 1.3)).should be_close(11109528802438156839288832.0, TOLERANCE)
end
it "raises a TypeError when given a non-Integer" do
@@ -116,8 +118,9 @@ describe :integer_exponent, shared: true do
end
it "returns a complex number when negative and raised to a fractional power" do
- ((-@bignum).send(@method, (1.0/3))) .should be_close(Complex(1048576,1816186.907597341), TOLERANCE)
- ((-@bignum).send(@method, Rational(1,3))).should be_close(Complex(1048576,1816186.907597341), TOLERANCE)
+ (-bignum_value).send(@method, (1.0/2)).should be_close(Complex(0.0, 4294967296.0), TOLERANCE)
+ (-@bignum).send(@method, (1.0/3)) .should be_close(Complex(1321122.9748145656, 2288252.1154253655), TOLERANCE)
+ (-@bignum).send(@method, Rational(1,3)).should be_close(Complex(1321122.9748145656, 2288252.1154253655), TOLERANCE)
end
end
end
diff --git a/spec/ruby/core/integer/shared/modulo.rb b/spec/ruby/core/integer/shared/modulo.rb
index b06d81e17d..f678a10806 100644
--- a/spec/ruby/core/integer/shared/modulo.rb
+++ b/spec/ruby/core/integer/shared/modulo.rb
@@ -48,11 +48,11 @@ describe :integer_modulo, shared: true do
end
it "returns the modulus obtained from dividing self by the given argument" do
- @bignum.send(@method, 5).should == 3
- @bignum.send(@method, -5).should == -2
- @bignum.send(@method, -100).should == -92
- @bignum.send(@method, 2.22).should be_close(0.780180180180252, TOLERANCE)
- @bignum.send(@method, bignum_value(10)).should == 9223372036854775808
+ @bignum.send(@method, 5).should == 1
+ @bignum.send(@method, -5).should == -4
+ @bignum.send(@method, -100).should == -84
+ @bignum.send(@method, 2.22).should be_close(1.5603603603605034, TOLERANCE)
+ @bignum.send(@method, bignum_value(10)).should == 18446744073709551616
end
it "raises a ZeroDivisionError when the given argument is 0" do
diff --git a/spec/ruby/core/integer/to_f_spec.rb b/spec/ruby/core/integer/to_f_spec.rb
index 06092eaa92..9f1df9ada9 100644
--- a/spec/ruby/core/integer/to_f_spec.rb
+++ b/spec/ruby/core/integer/to_f_spec.rb
@@ -11,9 +11,9 @@ describe "Integer#to_f" do
context "bignum" do
it "returns self converted to a Float" do
- bignum_value(0x4000_0aa0_0bb0_0000).to_f.should eql(13_835_069_737_789_292_544.00)
- bignum_value(0x8000_0000_0000_0ccc).to_f.should eql(18_446_744_073_709_555_712.00)
- (-bignum_value(99)).to_f.should eql(-9_223_372_036_854_775_808.00)
+ bignum_value(0x4000_0aa0_0bb0_0000).to_f.should eql(23_058_441_774_644_068_352.0)
+ bignum_value(0x8000_0000_0000_0ccc).to_f.should eql(27_670_116_110_564_330_700.0)
+ (-bignum_value(99)).to_f.should eql(-18_446_744_073_709_551_715.0)
end
it "converts number close to Float::MAX without exceeding MAX or producing NaN" do
diff --git a/spec/ruby/core/integer/to_s_spec.rb b/spec/ruby/core/integer/to_s_spec.rb
index 7988bfde7a..ca08dad95c 100644
--- a/spec/ruby/core/integer/to_s_spec.rb
+++ b/spec/ruby/core/integer/to_s_spec.rb
@@ -68,9 +68,9 @@ describe "Integer#to_s" do
describe "when given no base" do
it "returns self converted to a String using base 10" do
- bignum_value(9).to_s.should == "9223372036854775817"
- bignum_value.to_s.should == "9223372036854775808"
- (-bignum_value(675)).to_s.should == "-9223372036854776483"
+ bignum_value(9).to_s.should == "18446744073709551625"
+ bignum_value.to_s.should == "18446744073709551616"
+ (-bignum_value(675)).to_s.should == "-18446744073709552291"
end
end
diff --git a/spec/ruby/core/integer/try_convert_spec.rb b/spec/ruby/core/integer/try_convert_spec.rb
index 45c66eec79..4bc7d3851a 100644
--- a/spec/ruby/core/integer/try_convert_spec.rb
+++ b/spec/ruby/core/integer/try_convert_spec.rb
@@ -28,7 +28,17 @@ ruby_version_is "3.1" do
it "sends #to_int to the argument and raises TypeError if it's not a kind of Integer" do
obj = mock("to_int")
obj.should_receive(:to_int).and_return(Object.new)
- -> { Integer.try_convert obj }.should raise_error(TypeError)
+ -> {
+ 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 "does not rescue exceptions raised by #to_int" do
diff --git a/spec/ruby/core/integer/uminus_spec.rb b/spec/ruby/core/integer/uminus_spec.rb
index b6b110dec4..7a9cfe89bf 100644
--- a/spec/ruby/core/integer/uminus_spec.rb
+++ b/spec/ruby/core/integer/uminus_spec.rb
@@ -20,11 +20,11 @@ describe "Integer#-@" do
context "bignum" do
it "returns self as a negative value" do
- bignum_value.send(:-@).should == -9223372036854775808
- (-bignum_value).send(:-@).should == 9223372036854775808
+ bignum_value.send(:-@).should == -18446744073709551616
+ (-bignum_value).send(:-@).should == 18446744073709551616
- bignum_value(921).send(:-@).should == -9223372036854776729
- (-bignum_value(921).send(:-@)).should == 9223372036854776729
+ bignum_value(921).send(:-@).should == -18446744073709552537
+ (-bignum_value(921).send(:-@)).should == 18446744073709552537
end
end
end
diff --git a/spec/ruby/core/integer/zero_spec.rb b/spec/ruby/core/integer/zero_spec.rb
index 2dac50c406..bd362c4181 100644
--- a/spec/ruby/core/integer/zero_spec.rb
+++ b/spec/ruby/core/integer/zero_spec.rb
@@ -7,15 +7,7 @@ describe "Integer#zero?" do
-1.should_not.zero?
end
- ruby_version_is "3.0" do
- it "Integer#zero? overrides Numeric#zero?" do
- 42.method(:zero?).owner.should == Integer
- end
- end
-
- ruby_version_is ""..."3.0" do
- it "Integer#zero? uses Numeric#zero?" do
- 42.method(:zero?).owner.should == Numeric
- end
+ it "Integer#zero? overrides Numeric#zero?" do
+ 42.method(:zero?).owner.should == Integer
end
end
diff --git a/spec/ruby/core/io/advise_spec.rb b/spec/ruby/core/io/advise_spec.rb
index 0a845487e2..651fc52378 100644
--- a/spec/ruby/core/io/advise_spec.rb
+++ b/spec/ruby/core/io/advise_spec.rb
@@ -73,19 +73,9 @@ describe "IO#advise" do
end
end
- platform_is :linux do
+ guard -> { platform_is :linux and kernel_version_is '3.6' } do # [ruby-core:65355] tmpfs is not supported
it "supports the willneed advice type" do
- require 'etc'
- uname = if Etc.respond_to?(:uname)
- Etc.uname[:release]
- else
- `uname -r`.chomp
- end
- if (uname.split('.').map(&:to_i) <=> [3,6]) < 0
- skip "[ruby-core:65355] tmpfs is not supported"
- else
- @io.advise(:willneed).should be_nil
- end
+ @io.advise(:willneed).should be_nil
end
end
diff --git a/spec/ruby/core/io/binread_spec.rb b/spec/ruby/core/io/binread_spec.rb
index a3f752d8f9..418e89213b 100644
--- a/spec/ruby/core/io/binread_spec.rb
+++ b/spec/ruby/core/io/binread_spec.rb
@@ -44,4 +44,14 @@ describe "IO.binread" do
it "raises an Errno::EINVAL when not passed a valid offset" do
-> { IO.binread @fname, 0, -1 }.should raise_error(Errno::EINVAL)
end
+
+ ruby_version_is "3.3" do
+ # https://bugs.ruby-lang.org/issues/19630
+ it "warns about deprecation given a path with a pipe" do
+ cmd = "|echo ok"
+ -> {
+ IO.binread(cmd)
+ }.should complain(/IO process creation with a leading '\|'/)
+ end
+ end
end
diff --git a/spec/ruby/core/io/bytes_spec.rb b/spec/ruby/core/io/bytes_spec.rb
deleted file mode 100644
index 6e328983f2..0000000000
--- a/spec/ruby/core/io/bytes_spec.rb
+++ /dev/null
@@ -1,47 +0,0 @@
-# -*- encoding: utf-8 -*-
-require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-
-ruby_version_is ''...'3.0' do
- describe "IO#bytes" do
- before :each do
- @io = IOSpecs.io_fixture "lines.txt"
- @verbose, $VERBOSE = $VERBOSE, nil
- end
-
- after :each do
- $VERBOSE = @verbose
- @io.close unless @io.closed?
- end
-
- it "returns an enumerator of the next bytes from the stream" do
- enum = @io.bytes
- enum.should be_an_instance_of(Enumerator)
- @io.readline.should == "Voici la ligne une.\n"
- enum.first(5).should == [81, 117, 105, 32, 195]
- end
-
- it "yields each byte" do
- count = 0
- ScratchPad.record []
- @io.each_byte do |byte|
- ScratchPad << byte
- break if 4 < count += 1
- end
-
- ScratchPad.recorded.should == [86, 111, 105, 99, 105]
- end
-
- it "raises an IOError on closed stream" do
- enum = IOSpecs.closed_io.bytes
- -> { enum.first }.should raise_error(IOError)
- end
-
- it "raises an IOError on an enumerator for a stream that has been closed" do
- enum = @io.bytes
- enum.first.should == 86
- @io.close
- -> { enum.first }.should raise_error(IOError)
- end
- end
-end
diff --git a/spec/ruby/core/io/chars_spec.rb b/spec/ruby/core/io/chars_spec.rb
deleted file mode 100644
index 15db595aed..0000000000
--- a/spec/ruby/core/io/chars_spec.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-# -*- encoding: utf-8 -*-
-require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/chars'
-
-ruby_version_is ''...'3.0' do
- describe "IO#chars" do
- before :each do
- @verbose, $VERBOSE = $VERBOSE, nil
- end
-
- after :each do
- $VERBOSE = @verbose
- end
-
- it_behaves_like :io_chars, :chars
- end
-
- describe "IO#chars" do
- before :each do
- @verbose, $VERBOSE = $VERBOSE, nil
- end
-
- after :each do
- $VERBOSE = @verbose
- end
-
- it_behaves_like :io_chars_empty, :chars
- end
-end
diff --git a/spec/ruby/core/io/close_read_spec.rb b/spec/ruby/core/io/close_read_spec.rb
index 26454bfddd..e700e85bd9 100644
--- a/spec/ruby/core/io/close_read_spec.rb
+++ b/spec/ruby/core/io/close_read_spec.rb
@@ -4,7 +4,8 @@ require_relative 'fixtures/classes'
describe "IO#close_read" do
before :each do
- @io = IO.popen 'cat', "r+"
+ cmd = platform_is(:windows) ? 'rem' : 'cat'
+ @io = IO.popen cmd, "r+"
@path = tmp('io.close.txt')
end
diff --git a/spec/ruby/core/io/close_spec.rb b/spec/ruby/core/io/close_spec.rb
index eb560eaf67..3a44cc8b17 100644
--- a/spec/ruby/core/io/close_spec.rb
+++ b/spec/ruby/core/io/close_spec.rb
@@ -44,6 +44,12 @@ describe "IO#close" do
@io.close.should be_nil
end
+ it "does not call the #flush method but flushes the stream internally" do
+ @io.should_not_receive(:flush)
+ @io.close
+ @io.should.closed?
+ end
+
it 'raises an IOError with a clear message' do
matching_exception = nil
diff --git a/spec/ruby/core/io/close_write_spec.rb b/spec/ruby/core/io/close_write_spec.rb
index 14835e4e2c..70610a3e9d 100644
--- a/spec/ruby/core/io/close_write_spec.rb
+++ b/spec/ruby/core/io/close_write_spec.rb
@@ -3,7 +3,8 @@ require_relative 'fixtures/classes'
describe "IO#close_write" do
before :each do
- @io = IO.popen 'cat', 'r+'
+ cmd = platform_is(:windows) ? 'rem' : 'cat'
+ @io = IO.popen cmd, 'r+'
@path = tmp('io.close.txt')
end
@@ -48,12 +49,15 @@ describe "IO#close_write" do
io.should.closed?
end
- it "flushes and closes the write stream" do
- @io.puts '12345'
+ # Windows didn't have command like cat
+ platform_is_not :windows do
+ it "flushes and closes the write stream" do
+ @io.puts '12345'
- @io.close_write
+ @io.close_write
- @io.read.should == "12345\n"
+ @io.read.should == "12345\n"
+ end
end
it "does nothing on closed stream" do
diff --git a/spec/ruby/core/io/codepoints_spec.rb b/spec/ruby/core/io/codepoints_spec.rb
deleted file mode 100644
index 04c115dd3f..0000000000
--- a/spec/ruby/core/io/codepoints_spec.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/codepoints'
-
-ruby_version_is ''...'3.0' do
-
- # See redmine #1667
- describe "IO#codepoints" do
- before :each do
- @verbose, $VERBOSE = $VERBOSE, nil
- end
-
- after :each do
- $VERBOSE = @verbose
- end
-
- it_behaves_like :io_codepoints, :codepoints
- end
-
- describe "IO#codepoints" do
- before :each do
- @io = IOSpecs.io_fixture "lines.txt"
- @verbose, $VERBOSE = $VERBOSE, nil
- end
-
- after :each do
- $VERBOSE = @verbose
- @io.close unless @io.closed?
- end
-
- it "calls the given block" do
- r = []
- @io.codepoints { |c| r << c }
- r[24].should == 232
- r.last.should == 10
- end
- end
-end
diff --git a/spec/ruby/core/io/copy_stream_spec.rb b/spec/ruby/core/io/copy_stream_spec.rb
index df9c5c7390..ffa2ea992c 100644
--- a/spec/ruby/core/io/copy_stream_spec.rb
+++ b/spec/ruby/core/io/copy_stream_spec.rb
@@ -69,9 +69,12 @@ describe :io_copy_stream_to_io, shared: true do
end
it "raises an IOError if the destination IO is not open for writing" do
- @to_io.close
- @to_io = new_io @to_name, "r"
- -> { IO.copy_stream @object.from, @to_io }.should raise_error(IOError)
+ to_io = new_io __FILE__, "r"
+ begin
+ -> { IO.copy_stream @object.from, to_io }.should raise_error(IOError)
+ ensure
+ to_io.close
+ end
end
it "does not close the destination IO" do
@@ -109,7 +112,8 @@ describe "IO.copy_stream" do
end
after :each do
- rm_r @to_name, @from_bigfile
+ rm_r @to_name if @to_name
+ rm_r @from_bigfile
end
describe "from an IO" do
@@ -164,6 +168,25 @@ describe "IO.copy_stream" do
it_behaves_like :io_copy_stream_to_io, nil, IOSpecs::CopyStream
it_behaves_like :io_copy_stream_to_io_with_offset, nil, IOSpecs::CopyStream
end
+
+ describe "to a Tempfile" do
+ before :all do
+ require 'tempfile'
+ end
+
+ before :each do
+ @to_io = Tempfile.new("rubyspec_copy_stream", encoding: Encoding::BINARY, mode: File::RDONLY)
+ @to_name = @to_io.path
+ end
+
+ after :each do
+ @to_io.close!
+ @to_name = nil # do not rm_r it, already done by Tempfile#close!
+ end
+
+ it_behaves_like :io_copy_stream_to_io, nil, IOSpecs::CopyStream
+ it_behaves_like :io_copy_stream_to_io_with_offset, nil, IOSpecs::CopyStream
+ end
end
describe "from a file name" do
@@ -277,10 +300,8 @@ describe "IO.copy_stream" do
@io.should_not_receive(:pos)
IO.copy_stream(@io, @to_name)
end
-
end
-
describe "with a destination that does partial reads" do
before do
@from_out, @from_in = IO.pipe
diff --git a/spec/ruby/core/io/eof_spec.rb b/spec/ruby/core/io/eof_spec.rb
index 315345d942..b4850df437 100644
--- a/spec/ruby/core/io/eof_spec.rb
+++ b/spec/ruby/core/io/eof_spec.rb
@@ -76,7 +76,7 @@ describe "IO#eof?" do
end
it "returns true on one-byte stream after single-byte read" do
- File.open(File.dirname(__FILE__) + '/fixtures/one_byte.txt') { |one_byte|
+ File.open(__dir__ + '/fixtures/one_byte.txt') { |one_byte|
one_byte.read(1)
one_byte.should.eof?
}
diff --git a/spec/ruby/core/io/fixtures/classes.rb b/spec/ruby/core/io/fixtures/classes.rb
index 5d81d5fcd9..204a2a101b 100644
--- a/spec/ruby/core/io/fixtures/classes.rb
+++ b/spec/ruby/core/io/fixtures/classes.rb
@@ -7,6 +7,18 @@ module IOSpecs
class SubIO < IO
end
+ class SubIOWithRedefinedNew < IO
+ def self.new(...)
+ ScratchPad << :redefined_new_called
+ super
+ end
+
+ def initialize(...)
+ ScratchPad << :call_original_initialize
+ super
+ end
+ end
+
def self.collector
Proc.new { |x| ScratchPad << x }
end
@@ -108,6 +120,14 @@ module IOSpecs
"linha ", "cinco.\nHere ", "is ", "line ", "six.\n" ]
end
+ def self.lines_space_separator_without_trailing_spaces
+ [ "Voici", "la", "ligne", "une.\nQui",
+ "\303\250", "la", "linea", "due.\n\n\nAqu\303\255",
+ "est\303\241", "la", "l\303\255nea", "tres.\nHier",
+ "ist", "Zeile", "vier.\n\nEst\303\241", "aqui", "a",
+ "linha", "cinco.\nHere", "is", "line", "six.\n" ]
+ end
+
def self.lines_arbitrary_separator
[ "Voici la ligne une.\nQui \303\250",
" la linea due.\n\n\nAqu\303\255 est\303\241 la l\303\255nea tres.\nHier ist Zeile vier.\n\nEst\303\241 aqui a linha cinco.\nHere is line six.\n" ]
@@ -119,6 +139,12 @@ module IOSpecs
"Est\303\241 aqui a linha cinco.\nHere is line six.\n" ]
end
+ def self.paragraphs_without_trailing_new_line_characters
+ [ "Voici la ligne une.\nQui \303\250 la linea due.",
+ "Aqu\303\255 est\303\241 la l\303\255nea tres.\nHier ist Zeile vier.",
+ "Est\303\241 aqui a linha cinco.\nHere is line six.\n" ]
+ end
+
# Creates an IO instance for an existing fixture file. The
# file should obviously not be deleted.
def self.io_fixture(name, mode = "r:utf-8")
diff --git a/spec/ruby/core/io/flush_spec.rb b/spec/ruby/core/io/flush_spec.rb
index 34cf42c425..f7d5ba77fc 100644
--- a/spec/ruby/core/io/flush_spec.rb
+++ b/spec/ruby/core/io/flush_spec.rb
@@ -19,11 +19,11 @@ describe "IO#flush" do
end
end
- # [ruby-core:90895] MJIT worker may leave fd open in a forked child.
- # For instance, MJIT creates a worker before @r.close with fork(), @r.close happens,
- # and the MJIT worker keeps the pipe open until the worker execve().
- # TODO: consider acquiring GVL from MJIT worker.
- guard_not -> { defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? } do
+ # [ruby-core:90895] RJIT worker may leave fd open in a forked child.
+ # For instance, RJIT creates a worker before @r.close with fork(), @r.close happens,
+ # and the RJIT worker keeps the pipe open until the worker execve().
+ # TODO: consider acquiring GVL from RJIT worker.
+ guard_not -> { defined?(RubyVM::RJIT) && RubyVM::RJIT.enabled? } do
it "raises Errno::EPIPE if sync=false and the read end is closed" do
@w.sync = false
@w.write "foo"
diff --git a/spec/ruby/core/io/foreach_spec.rb b/spec/ruby/core/io/foreach_spec.rb
index c2276cf544..c361d27879 100644
--- a/spec/ruby/core/io/foreach_spec.rb
+++ b/spec/ruby/core/io/foreach_spec.rb
@@ -20,7 +20,10 @@ describe "IO.foreach" do
platform_is :windows do
cmd = "|cmd.exe /C echo hello&echo line2"
end
- 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
@@ -28,7 +31,9 @@ describe "IO.foreach" do
it "gets data from a fork when passed -" do
parent_pid = $$
- IO.foreach("|-") { |l| ScratchPad << l }
+ 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"]
@@ -39,6 +44,16 @@ describe "IO.foreach" do
end
end
end
+
+ ruby_version_is "3.3" do
+ # https://bugs.ruby-lang.org/issues/19630
+ it "warns about deprecation given a path with a pipe" do
+ cmd = "|echo ok"
+ -> {
+ IO.foreach(cmd).to_a
+ }.should complain(/IO process creation with a leading '\|'/)
+ end
+ end
end
end
diff --git a/spec/ruby/core/io/getbyte_spec.rb b/spec/ruby/core/io/getbyte_spec.rb
index 6ba8f0a3e0..b4351160e6 100644
--- a/spec/ruby/core/io/getbyte_spec.rb
+++ b/spec/ruby/core/io/getbyte_spec.rb
@@ -40,3 +40,19 @@ describe "IO#getbyte" do
@io.getbyte.should == nil
end
end
+
+describe "IO#getbyte" do
+ before :each do
+ @name = tmp("io_getbyte.txt")
+ @io = new_io(@name, 'w')
+ end
+
+ after :each do
+ @io.close if @io
+ rm_r @name if @name
+ end
+
+ it "raises an IOError if the stream is not readable" do
+ -> { @io.getbyte }.should raise_error(IOError)
+ end
+end
diff --git a/spec/ruby/core/io/gets_spec.rb b/spec/ruby/core/io/gets_spec.rb
index a3cd180b66..ca64bf860e 100644
--- a/spec/ruby/core/io/gets_spec.rb
+++ b/spec/ruby/core/io/gets_spec.rb
@@ -24,6 +24,12 @@ describe "IO#gets" do
end
end
+ it "sets $_ to nil after the last line has been read" do
+ while @io.gets
+ end
+ $_.should be_nil
+ end
+
it "returns nil if called at the end of the stream" do
IOSpecs.lines.length.times { @io.gets }
@io.gets.should == nil
@@ -38,14 +44,6 @@ describe "IO#gets" do
IOSpecs.lines.each { |line| line.should == @io.gets }
end
- ruby_version_is ''...'2.7' do
- it "returns tainted strings" do
- while line = @io.gets
- line.should.tainted?
- end
- end
- end
-
it "updates lineno with each invocation" do
while @io.gets
@io.lineno.should == @count += 1
@@ -64,14 +62,6 @@ describe "IO#gets" do
@io.gets(nil).should == IOSpecs.lines.join("")
end
- ruby_version_is ''...'2.7' do
- it "returns tainted strings" do
- while line = @io.gets(nil)
- line.should.tainted?
- end
- end
- end
-
it "updates lineno with each invocation" do
while @io.gets(nil)
@io.lineno.should == @count += 1
@@ -100,14 +90,6 @@ describe "IO#gets" do
@io.gets.should == IOSpecs.lines[4]
end
- ruby_version_is ''...'2.7' do
- it "returns tainted strings" do
- while line = @io.gets("")
- line.should.tainted?
- end
- end
- end
-
it "updates lineno with each invocation" do
while @io.gets("")
@io.lineno.should == @count += 1
@@ -126,14 +108,6 @@ describe "IO#gets" do
@io.gets("la linea").should == "Voici la ligne une.\nQui \303\250 la linea"
end
- ruby_version_is ''...'2.7' do
- it "returns tainted strings" do
- while line = @io.gets("la")
- line.should.tainted?
- end
- end
- end
-
it "updates lineno with each invocation" do
while (@io.gets("la"))
@io.lineno.should == @count += 1
@@ -145,12 +119,49 @@ describe "IO#gets" do
$..should == @count += 1
end
end
+
+ describe "that consists of multiple bytes" do
+ platform_is_not :windows do
+ it "should match the separator even if the buffer is filled over successive reads" do
+ IO.pipe do |read, write|
+
+ # Write part of the string with the separator split between two write calls. We want
+ # the read to intertwine such that when the read starts the full data isn't yet
+ # available in the buffer.
+ write.write("Aquí está la línea tres\r\n")
+
+ t = Thread.new do
+ # Continue reading until the separator is encountered or the pipe is closed.
+ read.gets("\r\n\r\n")
+ end
+
+ # Write the other half of the separator, which should cause the `gets` call to now
+ # match. Explicitly close the pipe for good measure so a bug in `gets` doesn't block forever.
+ Thread.pass until t.stop?
+
+ write.write("\r\nelse\r\n\r\n")
+ write.close
+
+ t.value.bytes.should == "Aquí está la línea tres\r\n\r\n".bytes
+ read.read(8).bytes.should == "else\r\n\r\n".bytes
+ end
+ end
+ end
+ end
end
describe "when passed chomp" do
it "returns the first line without a trailing newline character" do
@io.gets(chomp: true).should == IOSpecs.lines_without_newline_characters[0]
end
+
+ it "raises exception when options passed as Hash" do
+ -> { @io.gets({ chomp: true }) }.should raise_error(TypeError)
+
+ -> {
+ @io.gets("\n", 1, { chomp: true })
+ }.should raise_error(ArgumentError, "wrong number of arguments (given 3, expected 0..2)")
+ end
end
end
@@ -232,6 +243,16 @@ describe "IO#gets" do
it "reads all bytes when pass a separator and reading more than all bytes" do
@io.gets("\t", 100).should == "one\n\ntwo\n\nthree\nfour\n"
end
+
+ it "returns empty string when 0 passed as a limit" do
+ @io.gets(0).should == ""
+ @io.gets(nil, 0).should == ""
+ @io.gets("", 0).should == ""
+ end
+
+ it "does not accept limit that doesn't fit in a C off_t" do
+ -> { @io.gets(2**128) }.should raise_error(RangeError)
+ end
end
describe "IO#gets" do
@@ -317,11 +338,23 @@ describe "IO#gets" do
@io.gets.encoding.should == Encoding::BINARY
end
- it "transcodes to internal encoding if the IO object's external encoding is BINARY" do
- Encoding.default_external = Encoding::BINARY
- Encoding.default_internal = Encoding::UTF_8
- @io = new_io @name, 'r'
- @io.set_encoding Encoding::BINARY, Encoding::UTF_8
- @io.gets.encoding.should == Encoding::UTF_8
+ ruby_version_is ''...'3.3' do
+ it "transcodes to internal encoding if the IO object's external encoding is BINARY" do
+ Encoding.default_external = Encoding::BINARY
+ Encoding.default_internal = Encoding::UTF_8
+ @io = new_io @name, 'r'
+ @io.set_encoding Encoding::BINARY, Encoding::UTF_8
+ @io.gets.encoding.should == Encoding::UTF_8
+ end
+ end
+
+ ruby_version_is '3.3' do
+ it "ignores the internal encoding if the IO object's external encoding is BINARY" do
+ Encoding.default_external = Encoding::BINARY
+ Encoding.default_internal = Encoding::UTF_8
+ @io = new_io @name, 'r'
+ @io.set_encoding Encoding::BINARY, Encoding::UTF_8
+ @io.gets.encoding.should == Encoding::BINARY
+ end
end
end
diff --git a/spec/ruby/core/io/initialize_spec.rb b/spec/ruby/core/io/initialize_spec.rb
index ba5bc117b7..026252a13d 100644
--- a/spec/ruby/core/io/initialize_spec.rb
+++ b/spec/ruby/core/io/initialize_spec.rb
@@ -27,6 +27,17 @@ describe "IO#initialize" do
@io.fileno.should == fd
end
+ it "accepts options as keyword arguments" do
+ fd = new_fd @name, "w:utf-8"
+
+ @io.send(:initialize, fd, "w", flags: File::CREAT)
+ @io.fileno.should == fd
+
+ -> {
+ @io.send(:initialize, fd, "w", {flags: File::CREAT})
+ }.should raise_error(ArgumentError, "wrong number of arguments (given 3, expected 1..2)")
+ end
+
it "raises a TypeError when passed an IO" do
-> { @io.send :initialize, STDOUT, 'w' }.should raise_error(TypeError)
end
diff --git a/spec/ruby/core/io/ioctl_spec.rb b/spec/ruby/core/io/ioctl_spec.rb
index 8dcd9eb2c6..3f7b5ad5d7 100644
--- a/spec/ruby/core/io/ioctl_spec.rb
+++ b/spec/ruby/core/io/ioctl_spec.rb
@@ -12,7 +12,7 @@ describe "IO#ioctl" do
guard -> { RUBY_PLATFORM.include?("86") } do # x86 / x86_64
it "resizes an empty String to match the output size" do
File.open(__FILE__, 'r') do |f|
- buffer = ''
+ buffer = +''
# FIONREAD in /usr/include/asm-generic/ioctls.h
f.ioctl 0x541B, buffer
buffer.unpack('I').first.should be_kind_of(Integer)
diff --git a/spec/ruby/core/io/lineno_spec.rb b/spec/ruby/core/io/lineno_spec.rb
index 99266ecca1..e82cdd9f17 100644
--- a/spec/ruby/core/io/lineno_spec.rb
+++ b/spec/ruby/core/io/lineno_spec.rb
@@ -26,7 +26,8 @@ describe "IO#lineno" do
end
it "raises an IOError on a duplexed stream with the read side closed" do
- IO.popen('cat', 'r+') do |p|
+ cmd = platform_is(:windows) ? 'rem' : 'cat'
+ IO.popen(cmd, 'r+') do |p|
p.close_read
-> { p.lineno }.should raise_error(IOError)
end
@@ -70,7 +71,8 @@ describe "IO#lineno=" do
end
it "raises an IOError on a duplexed stream with the read side closed" do
- IO.popen('cat', 'r+') do |p|
+ cmd = platform_is(:windows) ? 'rem' : 'cat'
+ IO.popen(cmd, 'r+') do |p|
p.close_read
-> { p.lineno = 0 }.should raise_error(IOError)
end
@@ -92,8 +94,13 @@ describe "IO#lineno=" do
@io.lineno.should == 92233
end
- it "raises TypeError on nil argument" do
- -> { @io.lineno = nil }.should raise_error(TypeError)
+ it "raises TypeError if cannot convert argument to Integer implicitly" do
+ -> { @io.lineno = "1" }.should raise_error(TypeError, 'no implicit conversion of String into Integer')
+ -> { @io.lineno = nil }.should raise_error(TypeError, 'no implicit conversion from nil to integer')
+ end
+
+ it "does not accept Integers that don't fit in a C int" do
+ -> { @io.lineno = 2**32 }.should raise_error(RangeError)
end
it "sets the current line number to the given value" do
diff --git a/spec/ruby/core/io/lines_spec.rb b/spec/ruby/core/io/lines_spec.rb
deleted file mode 100644
index 5b29a1d07e..0000000000
--- a/spec/ruby/core/io/lines_spec.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-# -*- encoding: utf-8 -*-
-require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-
-ruby_version_is ''...'3.0' do
- describe "IO#lines" do
- before :each do
- @io = IOSpecs.io_fixture "lines.txt"
- @verbose, $VERBOSE = $VERBOSE, nil
- end
-
- after :each do
- $VERBOSE = @verbose
- @io.close if @io
- end
-
- it "returns an Enumerator" do
- @io.lines.should be_an_instance_of(Enumerator)
- end
-
- describe "when no block is given" do
- it "returns an Enumerator" do
- @io.lines.should be_an_instance_of(Enumerator)
- end
-
- describe "returned Enumerator" do
- describe "size" do
- it "should return nil" do
- @io.lines.size.should == nil
- end
- end
- end
- end
-
- it "returns a line when accessed" do
- enum = @io.lines
- enum.first.should == IOSpecs.lines[0]
- end
-
- it "yields each line to the passed block" do
- ScratchPad.record []
- @io.lines { |s| ScratchPad << s }
- ScratchPad.recorded.should == IOSpecs.lines
- end
- end
-end
diff --git a/spec/ruby/core/io/new_spec.rb b/spec/ruby/core/io/new_spec.rb
index 3597098caf..979ac0efcb 100644
--- a/spec/ruby/core/io/new_spec.rb
+++ b/spec/ruby/core/io/new_spec.rb
@@ -1,8 +1,16 @@
require_relative '../../spec_helper'
require_relative 'shared/new'
+# NOTE: should be synchronized with library/stringio/initialize_spec.rb
+
describe "IO.new" do
it_behaves_like :io_new, :new
+
+ it "does not use the given block and warns to use IO::open" do
+ -> {
+ @io = IO.send(@method, @fd) { raise }
+ }.should complain(/warning: IO::new\(\) does not take block; use IO::open\(\) instead/)
+ end
end
describe "IO.new" do
diff --git a/spec/ruby/core/io/nonblock_spec.rb b/spec/ruby/core/io/nonblock_spec.rb
index e81ac10c58..99dc0cafd0 100644
--- a/spec/ruby/core/io/nonblock_spec.rb
+++ b/spec/ruby/core/io/nonblock_spec.rb
@@ -12,43 +12,21 @@ platform_is_not :windows do
end
end
- ruby_version_is ""..."3.0" do
- it "returns false for pipe by default" do
- r, w = IO.pipe
- begin
- r.nonblock?.should == false
- w.nonblock?.should == false
- ensure
- r.close
- w.close
- end
- end
-
- it "returns false for socket by default" do
- require 'socket'
- TCPServer.open(0) do |socket|
- socket.nonblock?.should == false
- end
+ it "returns true for pipe by default" do
+ r, w = IO.pipe
+ begin
+ r.nonblock?.should == true
+ w.nonblock?.should == true
+ ensure
+ r.close
+ w.close
end
end
- ruby_version_is "3.0" do
- it "returns true for pipe by default" do
- r, w = IO.pipe
- begin
- r.nonblock?.should == true
- w.nonblock?.should == true
- ensure
- r.close
- w.close
- end
- end
-
- it "returns true for socket by default" do
- require 'socket'
- TCPServer.open(0) do |socket|
- socket.nonblock?.should == true
- end
+ it "returns true for socket by default" do
+ require 'socket'
+ TCPServer.open(0) do |socket|
+ socket.nonblock?.should == true
end
end
end
diff --git a/spec/ruby/core/io/open_spec.rb b/spec/ruby/core/io/open_spec.rb
index d3a3961df7..d151da9ce5 100644
--- a/spec/ruby/core/io/open_spec.rb
+++ b/spec/ruby/core/io/open_spec.rb
@@ -37,6 +37,19 @@ describe "IO.open" do
ScratchPad.recorded.should == :called
end
+ it "propagate an exception in the block after calling #close" do
+ -> do
+ IO.open(@fd, "w") do |io|
+ IOSpecs.io_mock(io, :close) do
+ super()
+ ScratchPad.record :called
+ end
+ raise Exception
+ end
+ end.should raise_error(Exception)
+ ScratchPad.recorded.should == :called
+ end
+
it "propagates an exception raised by #close that is not a StandardError" do
-> do
IO.open(@fd, "w") do |io|
diff --git a/spec/ruby/core/io/path_spec.rb b/spec/ruby/core/io/path_spec.rb
new file mode 100644
index 0000000000..8145c32f39
--- /dev/null
+++ b/spec/ruby/core/io/path_spec.rb
@@ -0,0 +1,14 @@
+require_relative '../../spec_helper'
+
+describe "IO#path" do
+ ruby_version_is "3.2" do
+ it "returns the path of the file associated with the IO object" do
+ path = tmp("io_path.txt")
+ File.open(path, "w") do |file|
+ IO.new(file.fileno, path: file.path, autoclose: false).path.should == file.path
+ end
+ ensure
+ File.unlink(path)
+ end
+ end
+end
diff --git a/spec/ruby/core/io/pipe_spec.rb b/spec/ruby/core/io/pipe_spec.rb
index 2f2cf06f4d..aee0d9003f 100644
--- a/spec/ruby/core/io/pipe_spec.rb
+++ b/spec/ruby/core/io/pipe_spec.rb
@@ -25,6 +25,17 @@ describe "IO.pipe" do
@r.should be_an_instance_of(IOSpecs::SubIO)
@w.should be_an_instance_of(IOSpecs::SubIO)
end
+
+ it "does not use IO.new method to create pipes and allows its overriding" do
+ ScratchPad.record []
+
+ # so redefined .new is not called, but original #initialize is
+ @r, @w = IOSpecs::SubIOWithRedefinedNew.pipe
+ ScratchPad.recorded.should == [:call_original_initialize, :call_original_initialize] # called 2 times - for each pipe (r and w)
+
+ @r.should be_an_instance_of(IOSpecs::SubIOWithRedefinedNew)
+ @w.should be_an_instance_of(IOSpecs::SubIOWithRedefinedNew)
+ end
end
describe "IO.pipe" do
diff --git a/spec/ruby/core/io/pread_spec.rb b/spec/ruby/core/io/pread_spec.rb
index 43071d6a31..28afc80e5c 100644
--- a/spec/ruby/core/io/pread_spec.rb
+++ b/spec/ruby/core/io/pread_spec.rb
@@ -1,7 +1,7 @@
# -*- encoding: utf-8 -*-
require_relative '../../spec_helper'
-platform_is_not :windows do
+guard -> { platform_is_not :windows or ruby_version_is "3.3" } do
describe "IO#pread" do
before :each do
@fname = tmp("io_pread.txt")
@@ -21,16 +21,93 @@ platform_is_not :windows do
end
it "accepts a length, an offset, and an output buffer" do
- buffer = "foo"
+ buffer = +"foo"
@file.pread(3, 4, buffer)
buffer.should == "567"
end
+ it "shrinks the buffer in case of less bytes read" do
+ buffer = +"foo"
+ @file.pread(1, 0, buffer)
+ buffer.should == "1"
+ end
+
+ it "grows the buffer in case of more bytes read" do
+ buffer = +"foo"
+ @file.pread(5, 0, buffer)
+ buffer.should == "12345"
+ end
+
it "does not advance the file pointer" do
@file.pread(4, 0).should == "1234"
@file.read.should == "1234567890"
end
+ it "ignores the current offset" do
+ @file.pos = 3
+ @file.pread(4, 0).should == "1234"
+ end
+
+ it "returns an empty string for maxlen = 0" do
+ @file.pread(0, 4).should == ""
+ end
+
+ it "ignores the offset for maxlen = 0, even if it is out of file bounds" do
+ @file.pread(0, 400).should == ""
+ end
+
+ it "does not reset the buffer when reading with maxlen = 0" do
+ buffer = +"foo"
+ @file.pread(0, 4, buffer)
+ buffer.should == "foo"
+
+ @file.pread(0, 400, buffer)
+ buffer.should == "foo"
+ end
+
+ it "converts maxlen to Integer using #to_int" do
+ maxlen = mock('maxlen')
+ maxlen.should_receive(:to_int).and_return(4)
+ @file.pread(maxlen, 0).should == "1234"
+ end
+
+ it "converts offset to Integer using #to_int" do
+ offset = mock('offset')
+ offset.should_receive(:to_int).and_return(0)
+ @file.pread(4, offset).should == "1234"
+ end
+
+ it "converts a buffer to String using to_str" do
+ buffer = mock('buffer')
+ buffer.should_receive(:to_str).at_least(1).and_return(+"foo")
+ @file.pread(4, 0, buffer)
+ buffer.should_not.is_a?(String)
+ buffer.to_str.should == "1234"
+ end
+
+ it "raises TypeError if maxlen is not an Integer and cannot be coerced into Integer" do
+ maxlen = Object.new
+ -> { @file.pread(maxlen, 0) }.should raise_error(TypeError, 'no implicit conversion of Object into Integer')
+ end
+
+ it "raises TypeError if offset is not an Integer and cannot be coerced into Integer" do
+ offset = Object.new
+ -> { @file.pread(4, offset) }.should raise_error(TypeError, 'no implicit conversion of Object into Integer')
+ end
+
+ it "raises ArgumentError for negative values of maxlen" do
+ -> { @file.pread(-4, 0) }.should raise_error(ArgumentError, 'negative string size (or size too big)')
+ end
+
+ it "raised Errno::EINVAL for negative values of offset" do
+ -> { @file.pread(4, -1) }.should raise_error(Errno::EINVAL, /Invalid argument/)
+ end
+
+ it "raises TypeError if the buffer is not a String and cannot be coerced into String" do
+ buffer = Object.new
+ -> { @file.pread(4, 0, buffer) }.should raise_error(TypeError, 'no implicit conversion of Object into String')
+ end
+
it "raises EOFError if end-of-file is reached" do
-> { @file.pread(1, 10) }.should raise_error(EOFError)
end
diff --git a/spec/ruby/core/io/print_spec.rb b/spec/ruby/core/io/print_spec.rb
index 04e971ef6d..085852024c 100644
--- a/spec/ruby/core/io/print_spec.rb
+++ b/spec/ruby/core/io/print_spec.rb
@@ -3,16 +3,27 @@ require_relative 'fixtures/classes'
describe "IO#print" do
before :each do
- @old_separator = $\
- suppress_warning {$\ = '->'}
+ @old_record_separator = $\
+ @old_field_separator = $,
+ suppress_warning {
+ $\ = '->'
+ $, = '^^'
+ }
@name = tmp("io_print")
end
after :each do
- suppress_warning {$\ = @old_separator}
+ suppress_warning {
+ $\ = @old_record_separator
+ $, = @old_field_separator
+ }
rm_r @name
end
+ it "returns nil" do
+ touch(@name) { |f| f.print.should be_nil }
+ end
+
it "writes $_.to_s followed by $\\ (if any) to the stream if no arguments given" do
o = mock('o')
o.should_receive(:to_s).and_return("mockmockmock")
@@ -38,13 +49,15 @@ describe "IO#print" do
IO.read(@name).should == "hello#{$\}"
end
- it "writes each obj.to_s to the stream and appends $\\ (if any) given multiple objects" do
+ it "writes each obj.to_s to the stream separated by $, (if any) and appends $\\ (if any) given multiple objects" do
o, o2 = Object.new, Object.new
def o.to_s(); 'o'; end
def o2.to_s(); 'o2'; end
- touch(@name) { |f| f.print(o, o2) }
- IO.read(@name).should == "#{o.to_s}#{o2.to_s}#{$\}"
+ suppress_warning {
+ touch(@name) { |f| f.print(o, o2) }
+ }
+ IO.read(@name).should == "#{o.to_s}#{$,}#{o2.to_s}#{$\}"
end
it "raises IOError on closed stream" do
diff --git a/spec/ruby/core/io/puts_spec.rb b/spec/ruby/core/io/puts_spec.rb
index 9a708fffef..9ed343c94c 100644
--- a/spec/ruby/core/io/puts_spec.rb
+++ b/spec/ruby/core/io/puts_spec.rb
@@ -6,7 +6,7 @@ describe "IO#puts" do
@before_separator = $/
@name = tmp("io_puts.txt")
@io = new_io @name
- ScratchPad.record ""
+ ScratchPad.record(+"")
def @io.write(str)
ScratchPad << str
end
diff --git a/spec/ruby/core/io/pwrite_spec.rb b/spec/ruby/core/io/pwrite_spec.rb
index fe29d1e1f6..2bc508b37d 100644
--- a/spec/ruby/core/io/pwrite_spec.rb
+++ b/spec/ruby/core/io/pwrite_spec.rb
@@ -1,7 +1,7 @@
# -*- encoding: utf-8 -*-
require_relative '../../spec_helper'
-platform_is_not :windows do
+guard -> { platform_is_not :windows or ruby_version_is "3.3" } do
describe "IO#pwrite" do
before :each do
@fname = tmp("io_pwrite.txt")
@@ -28,16 +28,42 @@ platform_is_not :windows do
@file.pread(6, 0).should == "foobar"
end
+ it "calls #to_s on the object to be written" do
+ object = mock("to_s")
+ object.should_receive(:to_s).and_return("foo")
+ @file.pwrite(object, 0)
+ @file.pread(3, 0).should == "foo"
+ end
+
+ it "calls #to_int on the offset" do
+ offset = mock("to_int")
+ offset.should_receive(:to_int).and_return(2)
+ @file.pwrite("foo", offset)
+ @file.pread(3, 2).should == "foo"
+ end
+
it "raises IOError when file is not open in write mode" do
File.open(@fname, "r") do |file|
- -> { file.pwrite("foo", 1) }.should raise_error(IOError)
+ -> { file.pwrite("foo", 1) }.should raise_error(IOError, "not opened for writing")
end
end
it "raises IOError when file is closed" do
file = File.open(@fname, "w+")
file.close
- -> { file.pwrite("foo", 1) }.should raise_error(IOError)
+ -> { file.pwrite("foo", 1) }.should raise_error(IOError, "closed stream")
+ end
+
+ it "raises a NoMethodError if object does not respond to #to_s" do
+ -> {
+ @file.pwrite(BasicObject.new, 0)
+ }.should raise_error(NoMethodError, /undefined method [`']to_s'/)
+ end
+
+ it "raises a TypeError if the offset cannot be converted to an Integer" do
+ -> {
+ @file.pwrite("foo", Object.new)
+ }.should raise_error(TypeError, "no implicit conversion of Object into Integer")
end
end
end
diff --git a/spec/ruby/core/io/read_nonblock_spec.rb b/spec/ruby/core/io/read_nonblock_spec.rb
index e50531d336..51e7cd6bd2 100644
--- a/spec/ruby/core/io/read_nonblock_spec.rb
+++ b/spec/ruby/core/io/read_nonblock_spec.rb
@@ -55,6 +55,27 @@ describe "IO#read_nonblock" do
@read.read_nonblock(4).should == "hell"
end
+ it "reads after ungetc with data in the buffer" do
+ @write.write("foobar")
+ @read.set_encoding(
+ 'utf-8', universal_newline: false
+ )
+ c = @read.getc
+ @read.ungetc(c)
+ @read.read_nonblock(3).should == "foo"
+ @read.read_nonblock(3).should == "bar"
+ end
+
+ it "raises an exception after ungetc with data in the buffer and character conversion enabled" do
+ @write.write("foobar")
+ @read.set_encoding(
+ 'utf-8', universal_newline: true
+ )
+ c = @read.getc
+ @read.ungetc(c)
+ -> { @read.read_nonblock(3).should == "foo" }.should raise_error(IOError)
+ end
+
it "returns less data if that is all that is available" do
@write << "hello"
@read.read_nonblock(10).should == "hello"
@@ -70,20 +91,39 @@ describe "IO#read_nonblock" do
@read.read_nonblock(1).should == "1"
end
+ it "raises ArgumentError when length is less than 0" do
+ -> { @read.read_nonblock(-1) }.should raise_error(ArgumentError)
+ end
+
it "reads into the passed buffer" do
- buffer = ""
+ buffer = +""
@write.write("1")
@read.read_nonblock(1, buffer)
buffer.should == "1"
end
it "returns the passed buffer" do
- buffer = ""
+ buffer = +""
@write.write("1")
output = @read.read_nonblock(1, buffer)
output.should equal(buffer)
end
+ it "discards the existing buffer content upon successful read" do
+ buffer = +"existing content"
+ @write.write("hello world")
+ @write.close
+ @read.read_nonblock(11, buffer)
+ buffer.should == "hello world"
+ end
+
+ it "discards the existing buffer content upon error" do
+ buffer = +"existing content"
+ @write.close
+ -> { @read.read_nonblock(1, buffer) }.should raise_error(EOFError)
+ buffer.should be_empty
+ end
+
it "raises IOError on closed stream" do
-> { IOSpecs.closed_io.read_nonblock(5) }.should raise_error(IOError)
end
@@ -96,4 +136,13 @@ describe "IO#read_nonblock" do
-> { @read.read_nonblock(5) }.should raise_error(EOFError)
end
+
+ it "preserves the encoding of the given buffer" do
+ buffer = ''.encode(Encoding::ISO_8859_1)
+ @write.write("abc")
+ @write.close
+ @read.read_nonblock(10, buffer)
+
+ buffer.encoding.should == Encoding::ISO_8859_1
+ end
end
diff --git a/spec/ruby/core/io/read_spec.rb b/spec/ruby/core/io/read_spec.rb
index 841e693f37..eb3652e692 100644
--- a/spec/ruby/core/io/read_spec.rb
+++ b/spec/ruby/core/io/read_spec.rb
@@ -23,6 +23,15 @@ describe "IO.read" do
IO.read(p)
end
+ # https://bugs.ruby-lang.org/issues/19354
+ it "accepts options as keyword arguments" do
+ IO.read(@fname, 3, 0, mode: "r+").should == @contents[0, 3]
+
+ -> {
+ IO.read(@fname, 3, 0, {mode: "r+"})
+ }.should raise_error(ArgumentError, /wrong number of arguments/)
+ end
+
it "accepts an empty options Hash" do
IO.read(@fname, **{}).should == @contents
end
@@ -55,6 +64,33 @@ describe "IO.read" do
IO.read(@fname, mode: "a+").should == @contents
end
+ platform_is_not :windows do
+ ruby_version_is ""..."3.3" do
+ it "uses an :open_args option" do
+ string = IO.read(@fname, nil, 0, open_args: ["r", nil, {encoding: Encoding::US_ASCII}])
+ string.encoding.should == Encoding::US_ASCII
+
+ string = IO.read(@fname, nil, 0, open_args: ["r", nil, {}])
+ string.encoding.should == Encoding::UTF_8
+ end
+ end
+ end
+
+ it "disregards other options if :open_args is given" do
+ string = IO.read(@fname,mode: "w", encoding: Encoding::UTF_32LE, open_args: ["r", encoding: Encoding::UTF_8])
+ string.encoding.should == Encoding::UTF_8
+ end
+
+ it "doesn't require mode to be specified in :open_args" do
+ string = IO.read(@fname, nil, 0, open_args: [{encoding: Encoding::US_ASCII}])
+ string.encoding.should == Encoding::US_ASCII
+ end
+
+ it "doesn't require mode to be specified in :open_args even if flags option passed" do
+ string = IO.read(@fname, nil, 0, open_args: [{encoding: Encoding::US_ASCII, flags: File::CREAT}])
+ string.encoding.should == Encoding::US_ASCII
+ end
+
it "treats second nil argument as no length limit" do
IO.read(@fname, nil).should == @contents
IO.read(@fname, nil, 5).should == IO.read(@fname, @contents.length, 5)
@@ -77,6 +113,15 @@ describe "IO.read" do
IO.read(@fname, 1, 10).should == nil
end
+ it "returns an empty string when reading zero bytes" do
+ IO.read(@fname, 0).should == ''
+ end
+
+ it "returns a String in BINARY when passed a size" do
+ IO.read(@fname, 1).encoding.should == Encoding::BINARY
+ IO.read(@fname, 0).encoding.should == Encoding::BINARY
+ end
+
it "raises an Errno::ENOENT when the requested file does not exist" do
rm_r @fname
-> { IO.read @fname }.should raise_error(Errno::ENOENT)
@@ -90,9 +135,18 @@ describe "IO.read" do
-> { IO.read @fname, -1 }.should raise_error(ArgumentError)
end
- it "raises an Errno::EINVAL when not passed a valid offset" do
- -> { IO.read @fname, 0, -1 }.should raise_error(Errno::EINVAL)
- -> { IO.read @fname, -1, -1 }.should raise_error(Errno::EINVAL)
+ ruby_version_is ''...'3.3' do
+ it "raises an Errno::EINVAL when not passed a valid offset" do
+ -> { IO.read @fname, 0, -1 }.should raise_error(Errno::EINVAL)
+ -> { IO.read @fname, -1, -1 }.should raise_error(Errno::EINVAL)
+ end
+ end
+
+ ruby_version_is '3.3' do
+ it "raises an ArgumentError when not passed a valid offset" do
+ -> { IO.read @fname, 0, -1 }.should raise_error(ArgumentError)
+ -> { IO.read @fname, -1, -1 }.should raise_error(ArgumentError)
+ end
end
it "uses the external encoding specified via the :external_encoding option" do
@@ -104,6 +158,14 @@ describe "IO.read" do
str = IO.read(@fname, encoding: Encoding::ISO_8859_1)
str.encoding.should == Encoding::ISO_8859_1
end
+
+ platform_is :windows do
+ it "reads the file in text mode" do
+ # 0x1A is CTRL+Z and is EOF in Windows text mode.
+ File.binwrite(@fname, "\x1Abbb")
+ IO.read(@fname).should.empty?
+ end
+ end
end
describe "IO.read from a pipe" do
@@ -112,12 +174,19 @@ describe "IO.read from a pipe" do
platform_is :windows do
cmd = "|cmd.exe /C echo hello"
end
- IO.read(cmd).should == "hello\n"
+
+ 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 = IO.read("|-")
+ str = nil
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ str = IO.read("|-")
+ end
+
if str # parent
str.should == "hello from child\n"
else #child
@@ -132,13 +201,18 @@ describe "IO.read from a pipe" do
platform_is :windows do
cmd = "|cmd.exe /C echo hello"
end
- IO.read(cmd, 1).should == "h"
+
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ IO.read(cmd, 1).should == "h"
+ end
end
platform_is_not :windows do
it "raises Errno::ESPIPE if passed an offset" do
-> {
- IO.read("|sh -c 'echo hello'", 1, 1)
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ IO.read("|sh -c 'echo hello'", 1, 1)
+ end
}.should raise_error(Errno::ESPIPE)
end
end
@@ -149,11 +223,23 @@ quarantine! do # The process tried to write to a nonexistent pipe.
# once https://bugs.ruby-lang.org/issues/12230 is fixed.
it "raises Errno::EINVAL if passed an offset" do
-> {
- IO.read("|cmd.exe /C echo hello", 1, 1)
+ 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 given a path with a pipe" do
+ cmd = "|echo ok"
+ -> {
+ IO.read(cmd)
+ }.should complain(/IO process creation with a leading '\|'/)
+ end
+ end
end
describe "IO.read on an empty file" do
@@ -197,21 +283,55 @@ describe "IO#read" do
@io.read(4).should == '7890'
end
+ it "treats first nil argument as no length limit" do
+ @io.read(nil).should == @contents
+ end
+
+ it "raises an ArgumentError when not passed a valid length" do
+ -> { @io.read(-1) }.should raise_error(ArgumentError)
+ end
+
it "clears the output buffer if there is nothing to read" do
@io.pos = 10
- buf = 'non-empty string'
+ buf = +'non-empty string'
@io.read(10, buf).should == nil
buf.should == ''
+
+ buf = +'non-empty string'
+
+ @io.read(nil, buf).should == ""
+
+ buf.should == ''
+
+ buf = +'non-empty string'
+
+ @io.read(0, buf).should == ""
+
+ buf.should == ''
+ end
+
+ it "raise FrozenError if the output buffer is frozen" do
+ @io.read
+ -> { @io.read(0, 'frozen-string'.freeze) }.should raise_error(FrozenError)
+ -> { @io.read(1, 'frozen-string'.freeze) }.should raise_error(FrozenError)
+ -> { @io.read(nil, 'frozen-string'.freeze) }.should raise_error(FrozenError)
+ end
+
+ ruby_bug "", ""..."3.3" do
+ it "raise FrozenError if the output buffer is frozen (2)" do
+ @io.read
+ -> { @io.read(1, ''.freeze) }.should raise_error(FrozenError)
+ end
end
it "consumes zero bytes when reading zero bytes" do
@io.read(0).should == ''
@io.pos.should == 0
- @io.getc.chr.should == '1'
+ @io.getc.should == '1'
end
it "is at end-of-file when everything has been read" do
@@ -224,46 +344,53 @@ describe "IO#read" do
end
it "places the specified number of bytes in the buffer" do
- buf = ""
+ buf = +""
@io.read 5, buf
buf.should == "12345"
end
it "expands the buffer when too small" do
- buf = "ABCDE"
+ buf = +"ABCDE"
@io.read nil, buf
buf.should == @contents
end
it "overwrites the buffer" do
- buf = "ABCDEFGHIJ"
+ buf = +"ABCDEFGHIJ"
@io.read nil, buf
buf.should == @contents
end
it "truncates the buffer when too big" do
- buf = "ABCDEFGHIJKLMNO"
+ buf = +"ABCDEFGHIJKLMNO"
@io.read nil, buf
buf.should == @contents
@io.rewind
- buf = "ABCDEFGHIJKLMNO"
+ buf = +"ABCDEFGHIJKLMNO"
@io.read 5, buf
buf.should == @contents[0..4]
end
it "returns the given buffer" do
- buf = ""
+ buf = +""
@io.read(nil, buf).should equal buf
end
+ it "returns the given buffer when there is nothing to read" do
+ buf = +""
+
+ @io.read
+ @io.read(nil, buf).should equal buf
+ end
+
it "coerces the second argument to string and uses it as a buffer" do
- buf = "ABCDE"
+ buf = +"ABCDE"
obj = mock("buff")
obj.should_receive(:to_str).any_number_of_times.and_return(buf)
@@ -304,6 +431,9 @@ describe "IO#read" do
-> { IOSpecs.closed_io.read }.should raise_error(IOError)
end
+ it "raises ArgumentError when length is less than 0" do
+ -> { @io.read(-1) }.should raise_error(ArgumentError)
+ end
platform_is_not :windows do
it "raises IOError when stream is closed by another thread" do
@@ -384,13 +514,6 @@ describe "IO#read in binary mode" do
xE2 = [226].pack('C*')
result.should == ("abc" + xE2 + "def").force_encoding(Encoding::BINARY)
end
-
- it "does not transcode file contents when an internal encoding is specified" do
- result = File.open(@name, "r:binary:utf-8") { |f| f.read }.chomp
- result.encoding.should == Encoding::BINARY
- xE2 = [226].pack('C*')
- result.should == ("abc" + xE2 + "def").force_encoding(Encoding::BINARY)
- end
end
describe "IO#read in text mode" do
@@ -465,13 +588,13 @@ describe :io_read_internal_encoding, shared: true do
describe "when passed nil for limit" do
it "sets the buffer to a transcoded String" do
- result = @io.read(nil, buf = "")
+ result = @io.read(nil, buf = +"")
buf.should equal(result)
buf.should == "ありがとう\n"
end
it "sets the buffer's encoding to the internal encoding" do
- buf = "".force_encoding Encoding::ISO_8859_1
+ buf = "".dup.force_encoding Encoding::ISO_8859_1
@io.read(nil, buf)
buf.encoding.should equal(Encoding::UTF_8)
end
@@ -485,17 +608,18 @@ describe :io_read_size_internal_encoding, shared: true do
it "returns a String in BINARY when passed a size" do
@io.read(4).encoding.should equal(Encoding::BINARY)
+ @io.read(0).encoding.should equal(Encoding::BINARY)
end
it "does not change the buffer's encoding when passed a limit" do
- buf = "".force_encoding Encoding::ISO_8859_1
+ buf = "".dup.force_encoding Encoding::ISO_8859_1
@io.read(4, buf)
buf.should == [164, 162, 164, 234].pack('C*').force_encoding(Encoding::ISO_8859_1)
buf.encoding.should equal(Encoding::ISO_8859_1)
end
it "truncates the buffer but does not change the buffer's encoding when no data remains" do
- buf = "abc".force_encoding Encoding::ISO_8859_1
+ buf = "abc".dup.force_encoding Encoding::ISO_8859_1
@io.read
@io.read(1, buf).should be_nil
diff --git a/spec/ruby/core/io/readchar_spec.rb b/spec/ruby/core/io/readchar_spec.rb
index b5f762a846..a66773851a 100644
--- a/spec/ruby/core/io/readchar_spec.rb
+++ b/spec/ruby/core/io/readchar_spec.rb
@@ -1,6 +1,16 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
+describe :io_readchar_internal_encoding, shared: true do
+ it "returns a transcoded String" do
+ @io.readchar.should == "あ"
+ end
+
+ it "sets the String encoding to the internal encoding" do
+ @io.readchar.encoding.should equal(Encoding::UTF_8)
+ end
+end
+
describe "IO#readchar" do
before :each do
@io = IOSpecs.io_fixture "lines.txt"
@@ -29,6 +39,62 @@ describe "IO#readchar" do
end
end
+describe "IO#readchar with internal encoding" do
+ after :each do
+ @io.close if @io
+ end
+
+ describe "not specified" do
+ before :each do
+ @io = IOSpecs.io_fixture "read_euc_jp.txt", "r:euc-jp"
+ end
+
+ it "does not transcode the String" do
+ @io.readchar.should == ("あ").encode(Encoding::EUC_JP)
+ end
+
+ it "sets the String encoding to the external encoding" do
+ @io.readchar.encoding.should equal(Encoding::EUC_JP)
+ end
+ end
+
+ describe "specified by open mode" do
+ before :each do
+ @io = IOSpecs.io_fixture "read_euc_jp.txt", "r:euc-jp:utf-8"
+ end
+
+ it_behaves_like :io_readchar_internal_encoding, nil
+ end
+
+ describe "specified by mode: option" do
+ before :each do
+ @io = IOSpecs.io_fixture "read_euc_jp.txt", mode: "r:euc-jp:utf-8"
+ end
+
+ it_behaves_like :io_readchar_internal_encoding, nil
+ end
+
+ describe "specified by internal_encoding: option" do
+ before :each do
+ options = { mode: "r",
+ internal_encoding: "utf-8",
+ external_encoding: "euc-jp" }
+ @io = IOSpecs.io_fixture "read_euc_jp.txt", options
+ end
+
+ it_behaves_like :io_readchar_internal_encoding, nil
+ end
+
+ describe "specified by encoding: option" do
+ before :each do
+ options = { mode: "r", encoding: "euc-jp:utf-8" }
+ @io = IOSpecs.io_fixture "read_euc_jp.txt", options
+ end
+
+ it_behaves_like :io_readchar_internal_encoding, nil
+ end
+end
+
describe "IO#readchar" do
before :each do
@io = IOSpecs.io_fixture "empty.txt"
diff --git a/spec/ruby/core/io/readline_spec.rb b/spec/ruby/core/io/readline_spec.rb
index 7cb1601816..a814c1be90 100644
--- a/spec/ruby/core/io/readline_spec.rb
+++ b/spec/ruby/core/io/readline_spec.rb
@@ -43,9 +43,42 @@ describe "IO#readline" do
end
end
+ describe "when passed limit" do
+ it "reads limit bytes" do
+ @io.readline(3).should == "Voi"
+ end
+
+ it "returns an empty string when passed 0 as a limit" do
+ @io.readline(0).should == ""
+ end
+
+ it "does not accept Integers that don't fit in a C off_t" do
+ -> { @io.readline(2**128) }.should raise_error(RangeError)
+ end
+ end
+
+ describe "when passed separator and limit" do
+ it "reads limit bytes till the separator" do
+ # Voici la ligne une.\
+ @io.readline(" ", 4).should == "Voic"
+ @io.readline(" ", 4).should == "i "
+ @io.readline(" ", 4).should == "la "
+ @io.readline(" ", 4).should == "lign"
+ @io.readline(" ", 4).should == "e "
+ end
+ end
+
describe "when passed chomp" do
it "returns the first line without a trailing newline character" do
@io.readline(chomp: true).should == IOSpecs.lines_without_newline_characters[0]
end
+
+ it "raises exception when options passed as Hash" do
+ -> { @io.readline({ chomp: true }) }.should raise_error(TypeError)
+
+ -> {
+ @io.readline("\n", 1, { chomp: true })
+ }.should raise_error(ArgumentError, "wrong number of arguments (given 3, expected 0..2)")
+ end
end
end
diff --git a/spec/ruby/core/io/readlines_spec.rb b/spec/ruby/core/io/readlines_spec.rb
index 254f2927b5..3a6ff3d0f3 100644
--- a/spec/ruby/core/io/readlines_spec.rb
+++ b/spec/ruby/core/io/readlines_spec.rb
@@ -101,6 +101,36 @@ describe "IO#readlines" do
@io.readlines(obj).should == IOSpecs.lines_r_separator
end
end
+
+ describe "when passed limit" do
+ it "raises ArgumentError when passed 0 as a limit" do
+ -> { @io.readlines(0) }.should raise_error(ArgumentError)
+ end
+
+ it "does not accept Integers that don't fit in a C off_t" do
+ -> { @io.readlines(2**128) }.should raise_error(RangeError)
+ end
+ end
+
+ describe "when passed chomp" do
+ it "returns the first line without a trailing newline character" do
+ @io.readlines(chomp: true).should == IOSpecs.lines_without_newline_characters
+ end
+
+ it "raises exception when options passed as Hash" do
+ -> { @io.readlines({ chomp: true }) }.should raise_error(TypeError)
+
+ -> {
+ @io.readlines("\n", 1, { chomp: true })
+ }.should raise_error(ArgumentError, "wrong number of arguments (given 3, expected 0..2)")
+ end
+ end
+
+ describe "when passed arbitrary keyword argument" do
+ it "tolerates it" do
+ @io.readlines(chomp: true, foo: :bar).should == IOSpecs.lines_without_newline_characters
+ end
+ end
end
describe "IO#readlines" do
@@ -150,13 +180,20 @@ describe "IO.readlines" do
platform_is :windows do
cmd = "|cmd.exe /C echo hello&echo line2"
end
- lines = IO.readlines(cmd)
+
+ lines = nil
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ lines = IO.readlines(cmd)
+ end
lines.should == ["hello\n", "line2\n"]
end
platform_is_not :windows do
it "gets data from a fork when passed -" do
- lines = IO.readlines("|-")
+ 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"]
@@ -169,6 +206,16 @@ describe "IO.readlines" do
end
end
+ ruby_version_is "3.3" do
+ # https://bugs.ruby-lang.org/issues/19630
+ it "warns about deprecation given a path with a pipe" do
+ cmd = "|echo ok"
+ -> {
+ IO.readlines(cmd)
+ }.should complain(/IO process creation with a leading '\|'/)
+ end
+ end
+
it_behaves_like :io_readlines, :readlines
it_behaves_like :io_readlines_options_19, :readlines
end
diff --git a/spec/ruby/core/io/readpartial_spec.rb b/spec/ruby/core/io/readpartial_spec.rb
index 2b33a0d5b1..0060beb545 100644
--- a/spec/ruby/core/io/readpartial_spec.rb
+++ b/spec/ruby/core/io/readpartial_spec.rb
@@ -59,7 +59,7 @@ describe "IO#readpartial" do
end
it "discards the existing buffer content upon successful read" do
- buffer = "existing"
+ buffer = +"existing content"
@wr.write("hello world")
@wr.close
@rd.readpartial(11, buffer)
@@ -74,7 +74,7 @@ describe "IO#readpartial" do
end
it "discards the existing buffer content upon error" do
- buffer = 'hello'
+ buffer = +'hello'
@wr.close
-> { @rd.readpartial(1, buffer) }.should raise_error(EOFError)
buffer.should be_empty
@@ -93,4 +93,19 @@ describe "IO#readpartial" do
@rd.readpartial(0).should == ""
end
+ ruby_bug "#18421", ""..."3.0.4" do
+ it "clears and returns the given buffer if the length argument is 0" do
+ buffer = +"existing content"
+ @rd.readpartial(0, buffer).should == buffer
+ buffer.should == ""
+ end
+ end
+
+ it "preserves the encoding of the given buffer" do
+ buffer = ''.encode(Encoding::ISO_8859_1)
+ @wr.write("abc")
+ @wr.close
+ @rd.readpartial(10, buffer)
+ buffer.encoding.should == Encoding::ISO_8859_1
+ end
end
diff --git a/spec/ruby/core/io/rewind_spec.rb b/spec/ruby/core/io/rewind_spec.rb
index 649041afaf..5579cbd988 100644
--- a/spec/ruby/core/io/rewind_spec.rb
+++ b/spec/ruby/core/io/rewind_spec.rb
@@ -18,6 +18,17 @@ describe "IO#rewind" do
@io.readline.should == "Voici la ligne une.\n"
end
+ it "positions the instance to the beginning of output for write-only IO" do
+ name = tmp("io_rewind_spec")
+ io = File.open(name, "w")
+ io.write("Voici la ligne une.\n")
+ io.rewind
+ io.pos.should == 0
+ ensure
+ io.close
+ rm_r name
+ end
+
it "positions the instance to the beginning of input and clears EOF" do
value = @io.read
@io.rewind
@@ -32,6 +43,10 @@ describe "IO#rewind" do
@io.lineno.should == 0
end
+ it "returns 0" do
+ @io.rewind.should == 0
+ end
+
it "raises IOError on closed stream" do
-> { IOSpecs.closed_io.rewind }.should raise_error(IOError)
end
diff --git a/spec/ruby/core/io/select_spec.rb b/spec/ruby/core/io/select_spec.rb
index 4603c1fbbc..3893e7620f 100644
--- a/spec/ruby/core/io/select_spec.rb
+++ b/spec/ruby/core/io/select_spec.rb
@@ -55,8 +55,8 @@ describe "IO.select" do
end
end
- it "returns supplied objects correctly even when monitoring the same object in different arrays" do
- filename = tmp("IO_select_pipe_file") + $$.to_s
+ it "returns supplied objects correctly when monitoring the same object in different arrays" do
+ filename = tmp("IO_select_pipe_file")
io = File.open(filename, 'w+')
result = IO.select [io], [io], nil, 0
result.should == [[io], [io], []]
@@ -64,6 +64,17 @@ describe "IO.select" do
rm_r filename
end
+ it "returns the pipe read end in read set if the pipe write end is closed concurrently" do
+ main = Thread.current
+ t = Thread.new {
+ Thread.pass until main.stop?
+ @wr.close
+ }
+ IO.select([@rd]).should == [[@rd], [], []]
+ ensure
+ t.join
+ end
+
it "invokes to_io on supplied objects that are not IO and returns the supplied objects" do
# make some data available
@wr.write("foobar")
@@ -103,6 +114,39 @@ describe "IO.select" do
it "raises an ArgumentError when passed a negative timeout" do
-> { IO.select(nil, nil, nil, -5)}.should raise_error(ArgumentError)
end
+
+ describe "returns the available descriptors when the file descriptor" do
+ it "is in both read and error arrays" do
+ @wr.write("foobar")
+ result = IO.select([@rd], nil, [@rd])
+ result.should == [[@rd], [], []]
+ end
+
+ it "is in both write and error arrays" do
+ result = IO.select(nil, [@wr], [@wr])
+ result.should == [[], [@wr], []]
+ end
+
+ it "is in both read and write arrays" do
+ filename = tmp("IO_select_read_write_file")
+ w = File.open(filename, 'w+')
+ begin
+ IO.select([w], [w], []).should == [[w], [w], []]
+ ensure
+ w.close
+ rm_r filename
+ end
+
+ IO.select([@wr], [@wr], []).should == [[], [@wr], []]
+
+ @wr.write("foobar")
+ # CRuby on macOS returns [[@rd], [@rd], []], weird but we accept it here, probably only for pipe read-end
+ [
+ [[@rd], [], []],
+ [[@rd], [@rd], []]
+ ].should.include? IO.select([@rd], [@rd], [])
+ end
+ end
end
describe "IO.select when passed nil for timeout" do
diff --git a/spec/ruby/core/io/set_encoding_by_bom_spec.rb b/spec/ruby/core/io/set_encoding_by_bom_spec.rb
index 7368ec7677..92433d6640 100644
--- a/spec/ruby/core/io/set_encoding_by_bom_spec.rb
+++ b/spec/ruby/core/io/set_encoding_by_bom_spec.rb
@@ -12,66 +12,251 @@ describe "IO#set_encoding_by_bom" do
rm_r @name
end
- ruby_version_is "2.7" do
- it "returns the result encoding if found BOM UTF-8 sequence" do
- File.binwrite(@name, "\u{FEFF}abc")
+ it "returns nil if not readable" do
+ not_readable_io = new_io(@name, 'wb')
- @io.set_encoding_by_bom.should == Encoding::UTF_8
- @io.external_encoding.should == Encoding::UTF_8
- end
+ not_readable_io.set_encoding_by_bom.should be_nil
+ not_readable_io.external_encoding.should == Encoding::ASCII_8BIT
+ ensure
+ not_readable_io.close
+ end
+
+ it "returns the result encoding if found BOM UTF-8 sequence" do
+ File.binwrite(@name, "\u{FEFF}")
+
+ @io.set_encoding_by_bom.should == Encoding::UTF_8
+ @io.external_encoding.should == Encoding::UTF_8
+ @io.read.b.should == "".b
+ @io.rewind
+ @io.set_encoding(Encoding::ASCII_8BIT)
+
+ File.binwrite(@name, "\u{FEFF}abc")
+
+ @io.set_encoding_by_bom.should == Encoding::UTF_8
+ @io.external_encoding.should == Encoding::UTF_8
+ @io.read.b.should == "abc".b
+ end
+
+ it "returns the result encoding if found BOM UTF_16LE sequence" do
+ File.binwrite(@name, "\xFF\xFE")
+
+ @io.set_encoding_by_bom.should == Encoding::UTF_16LE
+ @io.external_encoding.should == Encoding::UTF_16LE
+ @io.read.b.should == "".b
+ @io.rewind
+ @io.set_encoding(Encoding::ASCII_8BIT)
+
+ File.binwrite(@name, "\xFF\xFEabc")
+
+ @io.set_encoding_by_bom.should == Encoding::UTF_16LE
+ @io.external_encoding.should == Encoding::UTF_16LE
+ @io.read.b.should == "abc".b
+ end
+
+ it "returns the result encoding if found BOM UTF_16BE sequence" do
+ File.binwrite(@name, "\xFE\xFF")
+
+ @io.set_encoding_by_bom.should == Encoding::UTF_16BE
+ @io.external_encoding.should == Encoding::UTF_16BE
+ @io.read.b.should == "".b
+ @io.rewind
+ @io.set_encoding(Encoding::ASCII_8BIT)
+
+ File.binwrite(@name, "\xFE\xFFabc")
+
+ @io.set_encoding_by_bom.should == Encoding::UTF_16BE
+ @io.external_encoding.should == Encoding::UTF_16BE
+ @io.read.b.should == "abc".b
+ end
+
+ it "returns the result encoding if found BOM UTF_32LE sequence" do
+ File.binwrite(@name, "\xFF\xFE\x00\x00")
+
+ @io.set_encoding_by_bom.should == Encoding::UTF_32LE
+ @io.external_encoding.should == Encoding::UTF_32LE
+ @io.read.b.should == "".b
+ @io.rewind
+ @io.set_encoding(Encoding::ASCII_8BIT)
+
+ File.binwrite(@name, "\xFF\xFE\x00\x00abc")
+
+ @io.set_encoding_by_bom.should == Encoding::UTF_32LE
+ @io.external_encoding.should == Encoding::UTF_32LE
+ @io.read.b.should == "abc".b
+ end
+
+ it "returns the result encoding if found BOM UTF_32BE sequence" do
+ File.binwrite(@name, "\x00\x00\xFE\xFF")
+
+ @io.set_encoding_by_bom.should == Encoding::UTF_32BE
+ @io.external_encoding.should == Encoding::UTF_32BE
+ @io.read.b.should == "".b
+ @io.rewind
+ @io.set_encoding(Encoding::ASCII_8BIT)
+
+ File.binwrite(@name, "\x00\x00\xFE\xFFabc")
+
+ @io.set_encoding_by_bom.should == Encoding::UTF_32BE
+ @io.external_encoding.should == Encoding::UTF_32BE
+ @io.read.b.should == "abc".b
+ end
+
+ it "returns nil if io is empty" do
+ @io.set_encoding_by_bom.should be_nil
+ @io.external_encoding.should == Encoding::ASCII_8BIT
+ end
+
+ it "returns nil if UTF-8 BOM sequence is incomplete" do
+ File.write(@name, "\xEF")
+
+ @io.set_encoding_by_bom.should == nil
+ @io.external_encoding.should == Encoding::ASCII_8BIT
+ @io.read.b.should == "\xEF".b
+ @io.rewind
+
+ File.write(@name, "\xEFa")
- it "returns the result encoding if found BOM UTF_16LE sequence" do
- File.binwrite(@name, "\xFF\xFEabc")
+ @io.set_encoding_by_bom.should == nil
+ @io.external_encoding.should == Encoding::ASCII_8BIT
+ @io.read.b.should == "\xEFa".b
+ @io.rewind
- @io.set_encoding_by_bom.should == Encoding::UTF_16LE
- @io.external_encoding.should == Encoding::UTF_16LE
- end
+ File.write(@name, "\xEF\xBB")
- it "returns the result encoding if found BOM UTF_16BE sequence" do
- File.binwrite(@name, "\xFE\xFFabc")
+ @io.set_encoding_by_bom.should == nil
+ @io.external_encoding.should == Encoding::ASCII_8BIT
+ @io.read.b.should == "\xEF\xBB".b
+ @io.rewind
- @io.set_encoding_by_bom.should == Encoding::UTF_16BE
- @io.external_encoding.should == Encoding::UTF_16BE
- end
+ File.write(@name, "\xEF\xBBa")
- it "returns the result encoding if found BOM UTF_32LE sequence" do
- File.binwrite(@name, "\xFF\xFE\x00\x00abc")
+ @io.set_encoding_by_bom.should == nil
+ @io.external_encoding.should == Encoding::ASCII_8BIT
+ @io.read.b.should == "\xEF\xBBa".b
+ end
+
+ it "returns nil if UTF-16BE BOM sequence is incomplete" do
+ File.write(@name, "\xFE")
+
+ @io.set_encoding_by_bom.should == nil
+ @io.external_encoding.should == Encoding::ASCII_8BIT
+ @io.read.b.should == "\xFE".b
+ @io.rewind
+
+ File.write(@name, "\xFEa")
+
+ @io.set_encoding_by_bom.should == nil
+ @io.external_encoding.should == Encoding::ASCII_8BIT
+ @io.read.b.should == "\xFEa".b
+ end
+
+ it "returns nil if UTF-16LE/UTF-32LE BOM sequence is incomplete" do
+ File.write(@name, "\xFF")
+
+ @io.set_encoding_by_bom.should == nil
+ @io.external_encoding.should == Encoding::ASCII_8BIT
+ @io.read.b.should == "\xFF".b
+ @io.rewind
- @io.set_encoding_by_bom.should == Encoding::UTF_32LE
- @io.external_encoding.should == Encoding::UTF_32LE
- end
+ File.write(@name, "\xFFa")
- it "returns the result encoding if found BOM UTF_32BE sequence" do
- File.binwrite(@name, "\x00\x00\xFE\xFFabc")
+ @io.set_encoding_by_bom.should == nil
+ @io.external_encoding.should == Encoding::ASCII_8BIT
+ @io.read.b.should == "\xFFa".b
+ end
+
+ it "returns UTF-16LE if UTF-32LE BOM sequence is incomplete" do
+ File.write(@name, "\xFF\xFE")
+
+ @io.set_encoding_by_bom.should == Encoding::UTF_16LE
+ @io.external_encoding.should == Encoding::UTF_16LE
+ @io.read.b.should == "".b
+ @io.rewind
+ @io.set_encoding(Encoding::ASCII_8BIT)
+
+ File.write(@name, "\xFF\xFE\x00")
+
+ @io.set_encoding_by_bom.should == Encoding::UTF_16LE
+ @io.external_encoding.should == Encoding::UTF_16LE
+ @io.read.b.should == "\x00".b
+ @io.rewind
+ @io.set_encoding(Encoding::ASCII_8BIT)
+
+ File.write(@name, "\xFF\xFE\x00a")
+
+ @io.set_encoding_by_bom.should == Encoding::UTF_16LE
+ @io.external_encoding.should == Encoding::UTF_16LE
+ @io.read.b.should == "\x00a".b
+ end
- @io.set_encoding_by_bom.should == Encoding::UTF_32BE
- @io.external_encoding.should == Encoding::UTF_32BE
- end
+ it "returns nil if UTF-32BE BOM sequence is incomplete" do
+ File.write(@name, "\x00")
- it "returns nil if found BOM sequence not provided" do
- File.write(@name, "abc")
+ @io.set_encoding_by_bom.should == nil
+ @io.external_encoding.should == Encoding::ASCII_8BIT
+ @io.read.b.should == "\x00".b
+ @io.rewind
- @io.set_encoding_by_bom.should == nil
- end
+ File.write(@name, "\x00a")
- it 'returns exception if io not in binary mode' do
- not_binary_io = new_io(@name, 'r')
+ @io.set_encoding_by_bom.should == nil
+ @io.external_encoding.should == Encoding::ASCII_8BIT
+ @io.read.b.should == "\x00a".b
+ @io.rewind
- -> { not_binary_io.set_encoding_by_bom }.should raise_error(ArgumentError, 'ASCII incompatible encoding needs binmode')
- ensure
- not_binary_io.close
- end
+ File.write(@name, "\x00\x00")
- it 'returns exception if encoding already set' do
- @io.set_encoding("utf-8")
+ @io.set_encoding_by_bom.should == nil
+ @io.external_encoding.should == Encoding::ASCII_8BIT
+ @io.read.b.should == "\x00\x00".b
+ @io.rewind
- -> { @io.set_encoding_by_bom }.should raise_error(ArgumentError, 'encoding is set to UTF-8 already')
- end
+ File.write(@name, "\x00\x00a")
+
+ @io.set_encoding_by_bom.should == nil
+ @io.external_encoding.should == Encoding::ASCII_8BIT
+ @io.read.b.should == "\x00\x00a".b
+ @io.rewind
+
+ File.write(@name, "\x00\x00\xFE")
+
+ @io.set_encoding_by_bom.should == nil
+ @io.external_encoding.should == Encoding::ASCII_8BIT
+ @io.read.b.should == "\x00\x00\xFE".b
+ @io.rewind
+
+ File.write(@name, "\x00\x00\xFEa")
+
+ @io.set_encoding_by_bom.should == nil
+ @io.external_encoding.should == Encoding::ASCII_8BIT
+ @io.read.b.should == "\x00\x00\xFEa".b
+ end
+
+ it "returns nil if found BOM sequence not provided" do
+ File.write(@name, "abc")
+
+ @io.set_encoding_by_bom.should == nil
+ @io.external_encoding.should == Encoding::ASCII_8BIT
+ @io.read(3).should == "abc".b
+ end
+
+ it 'returns exception if io not in binary mode' do
+ not_binary_io = new_io(@name, 'r')
+
+ -> { not_binary_io.set_encoding_by_bom }.should raise_error(ArgumentError, 'ASCII incompatible encoding needs binmode')
+ ensure
+ not_binary_io.close
+ end
+
+ it 'returns exception if encoding already set' do
+ @io.set_encoding("utf-8")
+
+ -> { @io.set_encoding_by_bom }.should raise_error(ArgumentError, 'encoding is set to UTF-8 already')
+ end
- it 'returns exception if encoding conversion is already set' do
- @io.set_encoding(Encoding::UTF_8, Encoding::UTF_16BE)
+ it 'returns exception if encoding conversion is already set' do
+ @io.set_encoding(Encoding::UTF_8, Encoding::UTF_16BE)
- -> { @io.set_encoding_by_bom }.should raise_error(ArgumentError, 'encoding conversion is set')
- end
+ -> { @io.set_encoding_by_bom }.should raise_error(ArgumentError, 'encoding conversion is set')
end
end
diff --git a/spec/ruby/core/io/set_encoding_spec.rb b/spec/ruby/core/io/set_encoding_spec.rb
index 5aec6a96c3..22d9017635 100644
--- a/spec/ruby/core/io/set_encoding_spec.rb
+++ b/spec/ruby/core/io/set_encoding_spec.rb
@@ -1,7 +1,7 @@
require_relative '../../spec_helper'
describe :io_set_encoding_write, shared: true do
- it "sets the encodings to nil" do
+ it "sets the encodings to nil when they were set previously" do
@io = new_io @name, "#{@object}:ibm437:ibm866"
@io.set_encoding nil, nil
@@ -9,6 +9,19 @@ describe :io_set_encoding_write, shared: true do
@io.internal_encoding.should be_nil
end
+ it "sets the encodings to nil when the IO is built with no explicit encoding" do
+ @io = new_io @name, @object
+
+ # Checking our assumptions first
+ @io.external_encoding.should be_nil
+ @io.internal_encoding.should be_nil
+
+ @io.set_encoding nil, nil
+
+ @io.external_encoding.should be_nil
+ @io.internal_encoding.should be_nil
+ end
+
it "prevents the encodings from changing when Encoding defaults are changed" do
@io = new_io @name, "#{@object}:utf-8:us-ascii"
@io.set_encoding nil, nil
@@ -38,6 +51,7 @@ describe "IO#set_encoding when passed nil, nil" do
@external = Encoding.default_external
@internal = Encoding.default_internal
+ # The defaults
Encoding.default_external = Encoding::UTF_8
Encoding.default_internal = nil
@@ -113,6 +127,22 @@ describe "IO#set_encoding when passed nil, nil" do
describe "with 'a+' mode" do
it_behaves_like :io_set_encoding_write, nil, "a+"
end
+
+ describe "with standard IOs" do
+ it "correctly resets them" do
+ STDOUT.external_encoding.should == nil
+ STDOUT.internal_encoding.should == nil
+
+ begin
+ STDOUT.set_encoding(Encoding::US_ASCII, Encoding::ISO_8859_1)
+ ensure
+ STDOUT.set_encoding(nil, nil)
+ end
+
+ STDOUT.external_encoding.should == nil
+ STDOUT.internal_encoding.should == nil
+ end
+ end
end
describe "IO#set_encoding" do
@@ -188,4 +218,21 @@ describe "IO#set_encoding" do
@io.external_encoding.should == Encoding::UTF_8
@io.internal_encoding.should == Encoding::UTF_16BE
end
+
+ it "saves encoding options passed as a hash in the last argument" do
+ File.write(@name, "\xff")
+ io = File.open(@name)
+ io.set_encoding(Encoding::EUC_JP, Encoding::SHIFT_JIS, invalid: :replace, replace: ".")
+ io.read.should == "."
+ ensure
+ io.close
+ end
+
+ it "raises ArgumentError when no arguments are given" do
+ -> { @io.set_encoding() }.should raise_error(ArgumentError)
+ end
+
+ it "raises ArgumentError when too many arguments are given" do
+ -> { @io.set_encoding(1, 2, 3) }.should raise_error(ArgumentError)
+ end
end
diff --git a/spec/ruby/core/io/shared/binwrite.rb b/spec/ruby/core/io/shared/binwrite.rb
index 3649bb47ff..e51093329b 100644
--- a/spec/ruby/core/io/shared/binwrite.rb
+++ b/spec/ruby/core/io/shared/binwrite.rb
@@ -21,6 +21,14 @@ describe :io_binwrite, shared: true do
IO.send(@method, @filename, "abcde").should == 5
end
+ it "accepts options as a keyword argument" do
+ IO.send(@method, @filename, "hi", 0, flags: File::CREAT).should == 2
+
+ -> {
+ IO.send(@method, @filename, "hi", 0, {flags: File::CREAT})
+ }.should raise_error(ArgumentError, "wrong number of arguments (given 4, expected 2..3)")
+ end
+
it "creates a file if missing" do
fn = @filename + "xxx"
begin
@@ -67,6 +75,11 @@ describe :io_binwrite, shared: true do
File.read(@filename).should == "\0\0foo"
end
+ it "accepts a :flags option without :mode one" do
+ IO.send(@method, @filename, "hello, world!", flags: File::CREAT)
+ File.read(@filename).should == "hello, world!"
+ end
+
it "raises an error if readonly mode is specified" do
-> { IO.send(@method, @filename, "abcde", mode: "r") }.should raise_error(IOError)
end
diff --git a/spec/ruby/core/io/shared/each.rb b/spec/ruby/core/io/shared/each.rb
index 91766fbe03..aca622834f 100644
--- a/spec/ruby/core/io/shared/each.rb
+++ b/spec/ruby/core/io/shared/each.rb
@@ -33,10 +33,6 @@ describe :io_each, shared: true do
$_.should == "test"
end
- it "returns self" do
- @io.send(@method) { |l| l }.should equal(@io)
- end
-
it "raises an IOError when self is not readable" do
-> { IOSpecs.closed_io.send(@method) {} }.should raise_error(IOError)
end
@@ -77,6 +73,10 @@ describe :io_each, shared: true do
-> { @io.send(@method, 0){} }.should raise_error(ArgumentError)
end
end
+
+ it "does not accept Integers that don't fit in a C off_t" do
+ -> { @io.send(@method, 2**128){} }.should raise_error(RangeError)
+ end
end
describe "when passed a String containing one space as a separator" do
@@ -113,6 +113,13 @@ describe :io_each, shared: true do
@io.send(@method, "") { |s| ScratchPad << s }
ScratchPad.recorded.should == IOSpecs.paragraphs
end
+
+ it "discards leading newlines" do
+ @io.readline
+ @io.readline
+ @io.send(@method, "") { |s| ScratchPad << s }
+ ScratchPad.recorded.should == IOSpecs.paragraphs[1..-1]
+ end
end
describe "with both separator and limit" do
@@ -152,6 +159,13 @@ describe :io_each, shared: true do
@io.send(@method, "", 1024) { |s| ScratchPad << s }
ScratchPad.recorded.should == IOSpecs.paragraphs
end
+
+ it "discards leading newlines" do
+ @io.readline
+ @io.readline
+ @io.send(@method, "", 1024) { |s| ScratchPad << s }
+ ScratchPad.recorded.should == IOSpecs.paragraphs[1..-1]
+ end
end
end
end
@@ -161,6 +175,70 @@ describe :io_each, shared: true do
@io.send(@method, chomp: true) { |s| ScratchPad << s }
ScratchPad.recorded.should == IOSpecs.lines_without_newline_characters
end
+
+ it "raises exception when options passed as Hash" do
+ -> {
+ @io.send(@method, { chomp: true }) { |s| }
+ }.should raise_error(TypeError)
+
+ -> {
+ @io.send(@method, "\n", 1, { chomp: true }) { |s| }
+ }.should raise_error(ArgumentError, "wrong number of arguments (given 3, expected 0..2)")
+ end
+ end
+
+ describe "when passed chomp and a separator" do
+ it "yields each line without separator to the passed block" do
+ @io.send(@method, " ", chomp: true) { |s| ScratchPad << s }
+ ScratchPad.recorded.should == IOSpecs.lines_space_separator_without_trailing_spaces
+ end
+ end
+
+ describe "when passed chomp and empty line as a separator" do
+ it "yields each paragraph without trailing new line characters" do
+ @io.send(@method, "", 1024, chomp: true) { |s| ScratchPad << s }
+ ScratchPad.recorded.should == IOSpecs.paragraphs_without_trailing_new_line_characters
+ end
+ end
+
+ describe "when passed chomp and nil as a separator" do
+ ruby_version_is "3.2" do
+ it "yields self's content" do
+ @io.pos = 100
+ @io.send(@method, nil, chomp: true) { |s| ScratchPad << s }
+ ScratchPad.recorded.should == ["qui a linha cinco.\nHere is line six.\n"]
+ end
+ end
+
+ ruby_version_is ""..."3.2" do
+ it "yields self's content without trailing new line character" do
+ @io.pos = 100
+ @io.send(@method, nil, chomp: true) { |s| ScratchPad << s }
+ ScratchPad.recorded.should == ["qui a linha cinco.\nHere is line six."]
+ end
+ end
+ end
+
+ describe "when passed chomp, nil as a separator, and a limit" do
+ it "yields each line of limit size without truncating trailing new line character" do
+ # 43 - is a size of the 1st paragraph in the file
+ @io.send(@method, nil, 43, chomp: true) { |s| ScratchPad << s }
+
+ ScratchPad.recorded.should == [
+ "Voici la ligne une.\nQui è la linea due.\n\n\n",
+ "Aquí está la línea tres.\n" + "Hier ist Zeile ",
+ "vier.\n\nEstá aqui a linha cinco.\nHere is li",
+ "ne six.\n"
+ ]
+ end
+ end
+
+ describe "when passed too many arguments" do
+ it "raises ArgumentError" do
+ -> {
+ @io.send(@method, "", 1, "excess argument", chomp: true) {}
+ }.should raise_error(ArgumentError)
+ end
end
end
diff --git a/spec/ruby/core/io/shared/new.rb b/spec/ruby/core/io/shared/new.rb
index f2a0970a40..cba5f33ebf 100644
--- a/spec/ruby/core/io/shared/new.rb
+++ b/spec/ruby/core/io/shared/new.rb
@@ -1,5 +1,7 @@
require_relative '../fixtures/classes'
+# NOTE: should be synchronized with library/stringio/initialize_spec.rb
+
# This group of specs may ONLY contain specs that do successfully create
# an IO instance from the file descriptor returned by #new_fd helper.
describe :io_new, shared: true do
@@ -62,6 +64,15 @@ describe :io_new, shared: true do
@io.should be_an_instance_of(IO)
end
+ it "accepts options as keyword arguments" do
+ @io = IO.send(@method, @fd, "w", flags: File::CREAT)
+ @io.write("foo").should == 3
+
+ -> {
+ IO.send(@method, @fd, "w", {flags: File::CREAT})
+ }.should raise_error(ArgumentError, "wrong number of arguments (given 3, expected 1..2)")
+ end
+
it "accepts a :mode option" do
@io = IO.send(@method, @fd, mode: "w")
@io.write("foo").should == 3
@@ -197,21 +208,10 @@ describe :io_new, shared: true do
@io.internal_encoding.to_s.should == 'IBM866'
end
- ruby_version_is ''...'3.0' do
- it "accepts nil options" do
- @io = suppress_keyword_warning do
- IO.send(@method, @fd, 'w', nil)
- end
- @io.write("foo").should == 3
- end
- end
-
- ruby_version_is '3.0' do
- it "raises ArgumentError for nil options" do
- -> {
- IO.send(@method, @fd, 'w', nil)
- }.should raise_error(ArgumentError)
- end
+ it "raises ArgumentError for nil options" do
+ -> {
+ IO.send(@method, @fd, 'w', nil)
+ }.should raise_error(ArgumentError)
end
it "coerces mode with #to_str" do
@@ -382,21 +382,9 @@ describe :io_new_errors, shared: true do
}.should raise_error(ArgumentError)
end
- ruby_version_is ''...'3.0' do
- it "raises TypeError if passed a hash for mode and nil for options" do
- -> {
- suppress_keyword_warning do
- @io = IO.send(@method, @fd, {mode: 'w'}, nil)
- end
- }.should raise_error(TypeError)
- end
- end
-
- ruby_version_is '3.0' do
- it "raises ArgumentError if passed a hash for mode and nil for options" do
- -> {
- @io = IO.send(@method, @fd, {mode: 'w'}, nil)
- }.should raise_error(ArgumentError)
- end
+ it "raises ArgumentError if passed a hash for mode and nil for options" do
+ -> {
+ @io = IO.send(@method, @fd, {mode: 'w'}, nil)
+ }.should raise_error(ArgumentError)
end
end
diff --git a/spec/ruby/core/io/shared/pos.rb b/spec/ruby/core/io/shared/pos.rb
index d83a6c6692..3fdd3eb2b3 100644
--- a/spec/ruby/core/io/shared/pos.rb
+++ b/spec/ruby/core/io/shared/pos.rb
@@ -60,7 +60,13 @@ describe :io_set_pos, shared: true do
end
end
- it "does not accept Integers that don't fit in a C long" do
+ it "raises TypeError when cannot convert implicitly argument to Integer" do
+ File.open @fname do |io|
+ -> { io.send @method, Object.new }.should raise_error(TypeError, "no implicit conversion of Object into Integer")
+ end
+ end
+
+ it "does not accept Integers that don't fit in a C off_t" do
File.open @fname do |io|
-> { io.send @method, 2**128 }.should raise_error(RangeError)
end
diff --git a/spec/ruby/core/io/shared/readlines.rb b/spec/ruby/core/io/shared/readlines.rb
index 8e4a73bb98..6c1fa11a59 100644
--- a/spec/ruby/core/io/shared/readlines.rb
+++ b/spec/ruby/core/io/shared/readlines.rb
@@ -73,6 +73,23 @@ describe :io_readlines_options_19, shared: true do
result = IO.send(@method, @name, 10, &@object)
(result ? result : ScratchPad.recorded).should == IOSpecs.lines_limit
end
+
+ it "ignores the object as a limit if it is negative" do
+ result = IO.send(@method, @name, -2, &@object)
+ (result ? result : ScratchPad.recorded).should == IOSpecs.lines
+ end
+
+ it "does not accept Integers that don't fit in a C off_t" do
+ -> { IO.send(@method, @name, 2**128, &@object) }.should raise_error(RangeError)
+ end
+
+ ruby_bug "#18767", ""..."3.3" do
+ describe "when passed limit" do
+ it "raises ArgumentError when passed 0 as a limit" do
+ -> { IO.send(@method, @name, 0, &@object) }.should raise_error(ArgumentError)
+ end
+ end
+ end
end
describe "when the object is a String" do
@@ -82,36 +99,38 @@ describe :io_readlines_options_19, shared: true do
end
it "accepts non-ASCII data as separator" do
- result = IO.send(@method, @name, "\303\250".force_encoding("utf-8"), &@object)
+ result = IO.send(@method, @name, "\303\250".dup.force_encoding("utf-8"), &@object)
(result ? result : ScratchPad.recorded).should == IOSpecs.lines_arbitrary_separator
end
end
- describe "when the object is a Hash" do
- it "uses the value as the options hash" do
- result = IO.send(@method, @name, mode: "r", &@object)
- (result ? result : ScratchPad.recorded).should == IOSpecs.lines
+ describe "when the object is an options Hash" do
+ it "raises TypeError exception" do
+ -> {
+ IO.send(@method, @name, { chomp: true }, &@object)
+ }.should raise_error(TypeError)
end
end
- end
- describe "when passed name, object, object" do
- describe "when the first object is an Integer" do
- it "uses the second object as an options Hash" do
- -> do
- IO.send(@method, @filename, 10, mode: "w", &@object)
- end.should raise_error(IOError)
- end
+ describe "when the object is neither Integer nor String" do
+ it "raises TypeError exception" do
+ obj = mock("not io readlines limit")
- it "calls #to_hash to convert the second object to a Hash" do
- options = mock("io readlines options Hash")
- options.should_receive(:to_hash).and_return({ mode: "w" })
- -> do
- IO.send(@method, @filename, 10, **options, &@object)
- end.should raise_error(IOError)
+ -> {
+ IO.send(@method, @name, obj, &@object)
+ }.should raise_error(TypeError)
end
end
+ end
+
+ describe "when passed name, keyword arguments" do
+ it "uses the keyword arguments as options" do
+ result = IO.send(@method, @name, mode: "r", &@object)
+ (result ? result : ScratchPad.recorded).should == IOSpecs.lines
+ end
+ end
+ describe "when passed name, object, object" do
describe "when the first object is a String" do
it "uses the second object as a limit if it is an Integer" do
result = IO.send(@method, @name, " ", 10, &@object)
@@ -124,32 +143,18 @@ describe :io_readlines_options_19, shared: true do
result = IO.send(@method, @name, " ", limit, &@object)
(result ? result : ScratchPad.recorded).should == IOSpecs.lines_space_separator_limit
end
-
- it "uses the second object as an options Hash" do
- -> do
- IO.send(@method, @filename, " ", mode: "w", &@object)
- end.should raise_error(IOError)
- end
-
- it "calls #to_hash to convert the second object to a Hash" do
- options = mock("io readlines options Hash")
- options.should_receive(:to_hash).and_return({ mode: "w" })
- -> do
- IO.send(@method, @filename, " ", **options, &@object)
- end.should raise_error(IOError)
- end
end
describe "when the first object is not a String or Integer" do
it "calls #to_str to convert the object to a String" do
sep = mock("io readlines separator")
sep.should_receive(:to_str).at_least(1).and_return(" ")
- result = IO.send(@method, @name, sep, 10, mode: "r", &@object)
+ result = IO.send(@method, @name, sep, 10, &@object)
(result ? result : ScratchPad.recorded).should == IOSpecs.lines_space_separator_limit
end
it "uses the second object as a limit if it is an Integer" do
- result = IO.send(@method, @name, " ", 10, mode: "r", &@object)
+ result = IO.send(@method, @name, " ", 10, &@object)
(result ? result : ScratchPad.recorded).should == IOSpecs.lines_space_separator_limit
end
@@ -159,24 +164,57 @@ describe :io_readlines_options_19, shared: true do
result = IO.send(@method, @name, " ", limit, &@object)
(result ? result : ScratchPad.recorded).should == IOSpecs.lines_space_separator_limit
end
+ end
+
+ describe "when the second object is neither Integer nor String" do
+ it "raises TypeError exception" do
+ obj = mock("not io readlines limit")
+
+ -> {
+ IO.send(@method, @name, " ", obj, &@object)
+ }.should raise_error(TypeError)
+ end
+ end
- it "uses the second object as an options Hash" do
+ describe "when the second object is an options Hash" do
+ it "raises TypeError exception" do
+ -> {
+ IO.send(@method, @name, "", { chomp: true }, &@object)
+ }.should raise_error(TypeError)
+ end
+ end
+ end
+
+ describe "when passed name, object, keyword arguments" do
+ describe "when the first object is an Integer" do
+ it "uses the keyword arguments as options" do
+ -> do
+ IO.send(@method, @filename, 10, mode: "w", &@object)
+ end.should raise_error(IOError)
+ end
+ end
+
+ describe "when the first object is a String" do
+ it "uses the keyword arguments as options" do
-> do
IO.send(@method, @filename, " ", mode: "w", &@object)
end.should raise_error(IOError)
end
+ end
+
+ describe "when the first object is not a String or Integer" do
+ it "uses the keyword arguments as options" do
+ sep = mock("io readlines separator")
+ sep.should_receive(:to_str).at_least(1).and_return(" ")
- it "calls #to_hash to convert the second object to a Hash" do
- options = mock("io readlines options Hash")
- options.should_receive(:to_hash).and_return({ mode: "w" })
-> do
- IO.send(@method, @filename, " ", **options, &@object)
+ IO.send(@method, @filename, sep, mode: "w", &@object)
end.should raise_error(IOError)
end
end
end
- describe "when passed name, separator, limit, options" do
+ describe "when passed name, separator, limit, keyword arguments" do
it "calls #to_path to convert the name object" do
name = mock("io name to_path")
name.should_receive(:to_path).and_return(@name)
@@ -198,12 +236,24 @@ describe :io_readlines_options_19, shared: true do
(result ? result : ScratchPad.recorded).should == IOSpecs.lines_space_separator_limit
end
- it "calls #to_hash to convert the options object" do
- options = mock("io readlines options Hash")
- options.should_receive(:to_hash).and_return({ mode: "w" })
+ it "uses the keyword arguments as options" do
-> do
- IO.send(@method, @filename, " ", 10, **options, &@object)
+ IO.send(@method, @filename, " ", 10, mode: "w", &@object)
end.should raise_error(IOError)
end
+
+ describe "when passed chomp, nil as a separator, and a limit" do
+ it "yields each line of limit size without truncating trailing new line character" do
+ # 43 - is a size of the 1st paragraph in the file
+ result = IO.send(@method, @name, nil, 43, chomp: true, &@object)
+
+ (result ? result : ScratchPad.recorded).should == [
+ "Voici la ligne une.\nQui è la linea due.\n\n\n",
+ "Aquí está la línea tres.\n" + "Hier ist Zeile ",
+ "vier.\n\nEstá aqui a linha cinco.\nHere is li",
+ "ne six.\n"
+ ]
+ end
+ end
end
end
diff --git a/spec/ruby/core/io/shared/write.rb b/spec/ruby/core/io/shared/write.rb
index 270b84ac39..964064746a 100644
--- a/spec/ruby/core/io/shared/write.rb
+++ b/spec/ruby/core/io/shared/write.rb
@@ -69,16 +69,6 @@ describe :io_write, shared: true do
-> { IOSpecs.closed_io.send(@method, "hello") }.should raise_error(IOError)
end
- it "does not modify the passed argument" do
- File.open(@filename, "w") do |f|
- f.set_encoding(Encoding::IBM437)
- # A character whose codepoint differs between UTF-8 and IBM437
- f.write "ƒ".freeze
- end
-
- File.binread(@filename).bytes.should == [159]
- end
-
describe "on a pipe" do
before :each do
@r, @w = IO.pipe
@@ -95,11 +85,11 @@ describe :io_write, shared: true do
@r.read.should == "foo"
end
- # [ruby-core:90895] MJIT worker may leave fd open in a forked child.
- # For instance, MJIT creates a worker before @r.close with fork(), @r.close happens,
- # and the MJIT worker keeps the pipe open until the worker execve().
- # TODO: consider acquiring GVL from MJIT worker.
- guard_not -> { defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? } do
+ # [ruby-core:90895] RJIT worker may leave fd open in a forked child.
+ # For instance, RJIT creates a worker before @r.close with fork(), @r.close happens,
+ # and the RJIT worker keeps the pipe open until the worker execve().
+ # TODO: consider acquiring GVL from RJIT worker.
+ guard_not -> { defined?(RubyVM::RJIT) && RubyVM::RJIT.enabled? } do
it "raises Errno::EPIPE if the read end is closed and does not die from SIGPIPE" do
@r.close
-> { @w.send(@method, "foo") }.should raise_error(Errno::EPIPE, /Broken pipe/)
@@ -107,3 +97,58 @@ describe :io_write, shared: true do
end
end
end
+
+describe :io_write_transcode, shared: true do
+ before :each do
+ @transcode_filename = tmp("io_write_transcode")
+ end
+
+ after :each do
+ rm_r @transcode_filename
+ end
+
+ it "transcodes the given string when the external encoding is set and neither is BINARY" do
+ utf8_str = "hello"
+
+ File.open(@transcode_filename, "w", external_encoding: Encoding::UTF_16BE) do |file|
+ file.external_encoding.should == Encoding::UTF_16BE
+ file.send(@method, utf8_str)
+ end
+
+ result = File.binread(@transcode_filename)
+ expected = [0, 104, 0, 101, 0, 108, 0, 108, 0, 111] # UTF-16BE bytes for "hello"
+
+ result.bytes.should == expected
+ end
+
+ it "transcodes the given string when the external encoding is set and the string encoding is BINARY" do
+ str = "été".b
+
+ File.open(@transcode_filename, "w", external_encoding: Encoding::UTF_16BE) do |file|
+ file.external_encoding.should == Encoding::UTF_16BE
+ -> { file.send(@method, str) }.should raise_error(Encoding::UndefinedConversionError)
+ end
+ end
+end
+
+describe :io_write_no_transcode, shared: true do
+ before :each do
+ @transcode_filename = tmp("io_write_no_transcode")
+ end
+
+ after :each do
+ rm_r @transcode_filename
+ end
+
+ it "does not transcode the given string even when the external encoding is set" do
+ utf8_str = "hello"
+
+ File.open(@transcode_filename, "w", external_encoding: Encoding::UTF_16BE) do |file|
+ file.external_encoding.should == Encoding::UTF_16BE
+ file.send(@method, utf8_str)
+ end
+
+ result = File.binread(@transcode_filename)
+ result.bytes.should == utf8_str.bytes
+ end
+end
diff --git a/spec/ruby/core/io/stat_spec.rb b/spec/ruby/core/io/stat_spec.rb
index 58eba02b8f..717c45d0a3 100644
--- a/spec/ruby/core/io/stat_spec.rb
+++ b/spec/ruby/core/io/stat_spec.rb
@@ -3,7 +3,8 @@ require_relative 'fixtures/classes'
describe "IO#stat" do
before :each do
- @io = IO.popen 'cat', "r+"
+ cmd = platform_is(:windows) ? 'rem' : 'cat'
+ @io = IO.popen cmd, "r+"
end
after :each do
diff --git a/spec/ruby/core/io/sysread_spec.rb b/spec/ruby/core/io/sysread_spec.rb
index 8201ad47ca..003bb9eb94 100644
--- a/spec/ruby/core/io/sysread_spec.rb
+++ b/spec/ruby/core/io/sysread_spec.rb
@@ -6,7 +6,7 @@ describe "IO#sysread on a file" do
@file_name = tmp("IO_sysread_file") + $$.to_s
File.open(@file_name, "w") do |f|
# write some stuff
- f.write("012345678901234567890123456789")
+ f.write("012345678901234567890123456789\nabcdef")
end
@file = File.open(@file_name, "r+")
end
@@ -21,25 +21,25 @@ describe "IO#sysread on a file" do
end
it "reads the specified number of bytes from the file to the buffer" do
- buf = "" # empty buffer
+ buf = +"" # empty buffer
@file.sysread(15, buf).should == buf
buf.should == "012345678901234"
@file.rewind
- buf = "ABCDE" # small buffer
+ buf = +"ABCDE" # small buffer
@file.sysread(15, buf).should == buf
buf.should == "012345678901234"
@file.rewind
- buf = "ABCDE" * 5 # large buffer
+ buf = +"ABCDE" * 5 # large buffer
@file.sysread(15, buf).should == buf
buf.should == "012345678901234"
end
it "coerces the second argument to string and uses it as a buffer" do
- buf = "ABCDE"
+ buf = +"ABCDE"
(obj = mock("buff")).should_receive(:to_str).any_number_of_times.and_return(buf)
@file.sysread(15, obj).should == buf
buf.should == "012345678901234"
@@ -84,6 +84,29 @@ describe "IO#sysread on a file" do
it "raises IOError on closed stream" do
-> { IOSpecs.closed_io.sysread(5) }.should raise_error(IOError)
end
+
+ it "immediately returns an empty string if the length argument is 0" do
+ @file.sysread(0).should == ""
+ end
+
+ it "immediately returns the given buffer if the length argument is 0" do
+ buffer = +"existing content"
+ @file.sysread(0, buffer).should == buffer
+ buffer.should == "existing content"
+ end
+
+ it "discards the existing buffer content upon successful read" do
+ buffer = +"existing content"
+ @file.sysread(11, buffer)
+ buffer.should == "01234567890"
+ end
+
+ it "discards the existing buffer content upon error" do
+ buffer = +"existing content"
+ @file.seek(0, :END)
+ -> { @file.sysread(1, buffer) }.should raise_error(EOFError)
+ buffer.should be_empty
+ end
end
describe "IO#sysread" do
@@ -100,4 +123,10 @@ describe "IO#sysread" do
@write.syswrite "ab"
@read.sysread(3).should == "ab"
end
+
+ guard_not -> { platform_is :windows and ruby_version_is ""..."3.2" } do # https://bugs.ruby-lang.org/issues/18880
+ it "raises ArgumentError when length is less than 0" do
+ -> { @read.sysread(-1) }.should raise_error(ArgumentError)
+ end
+ end
end
diff --git a/spec/ruby/core/io/sysseek_spec.rb b/spec/ruby/core/io/sysseek_spec.rb
index e631939bce..002f2a14eb 100644
--- a/spec/ruby/core/io/sysseek_spec.rb
+++ b/spec/ruby/core/io/sysseek_spec.rb
@@ -4,7 +4,7 @@ require_relative 'fixtures/classes'
require_relative 'shared/pos'
describe "IO#sysseek" do
- it_behaves_like :io_set_pos, :seek
+ it_behaves_like :io_set_pos, :sysseek
end
describe "IO#sysseek" do
diff --git a/spec/ruby/core/io/syswrite_spec.rb b/spec/ruby/core/io/syswrite_spec.rb
index a28cc62174..8bf61a27c3 100644
--- a/spec/ruby/core/io/syswrite_spec.rb
+++ b/spec/ruby/core/io/syswrite_spec.rb
@@ -29,6 +29,16 @@ describe "IO#syswrite on a file" do
end
end
+ it "does not modify the passed argument" do
+ File.open(@filename, "w") do |f|
+ f.set_encoding(Encoding::IBM437)
+ # A character whose codepoint differs between UTF-8 and IBM437
+ f.syswrite("ƒ".freeze)
+ end
+
+ File.binread(@filename).bytes.should == [198, 146]
+ end
+
it "warns if called immediately after a buffered IO#write" do
@file.write("abcde")
-> { @file.syswrite("fghij") }.should complain(/syswrite/)
@@ -68,4 +78,5 @@ end
describe "IO#syswrite" do
it_behaves_like :io_write, :syswrite
+ it_behaves_like :io_write_no_transcode, :syswrite
end
diff --git a/spec/ruby/core/io/try_convert_spec.rb b/spec/ruby/core/io/try_convert_spec.rb
index 5fbd10b6fa..a9e99de7aa 100644
--- a/spec/ruby/core/io/try_convert_spec.rb
+++ b/spec/ruby/core/io/try_convert_spec.rb
@@ -38,7 +38,7 @@ describe "IO.try_convert" do
it "raises a TypeError if the object does not return an IO from #to_io" do
obj = mock("io")
obj.should_receive(:to_io).and_return("io")
- -> { IO.try_convert(obj) }.should raise_error(TypeError)
+ -> { IO.try_convert(obj) }.should raise_error(TypeError, "can't convert MockObject to IO (MockObject#to_io gives String)")
end
it "propagates an exception raised by #to_io" do
diff --git a/spec/ruby/core/io/ungetbyte_spec.rb b/spec/ruby/core/io/ungetbyte_spec.rb
index 776707205a..716743a6af 100644
--- a/spec/ruby/core/io/ungetbyte_spec.rb
+++ b/spec/ruby/core/io/ungetbyte_spec.rb
@@ -36,20 +36,10 @@ describe "IO#ungetbyte" do
@io.getbyte.should == 97
end
- ruby_version_is ''...'2.6.1' do
- it "is an RangeError if the integer is not in 8bit" do
- for i in [4095, 0x4f7574206f6620636861722072616e6765] do
- -> { @io.ungetbyte(i) }.should raise_error(RangeError)
- end
- end
- end
-
- ruby_version_is '2.6.1' do
- it "never raises RangeError" do
- for i in [4095, 0x4f7574206f6620636861722072616e67ff] do
- @io.ungetbyte(i).should be_nil
- @io.getbyte.should == 255
- end
+ it "never raises RangeError" do
+ for i in [4095, 0x4f7574206f6620636861722072616e67ff] do
+ @io.ungetbyte(i).should be_nil
+ @io.getbyte.should == 255
end
end
diff --git a/spec/ruby/core/io/ungetc_spec.rb b/spec/ruby/core/io/ungetc_spec.rb
index 41a455c836..47a4e99ebf 100644
--- a/spec/ruby/core/io/ungetc_spec.rb
+++ b/spec/ruby/core/io/ungetc_spec.rb
@@ -103,19 +103,9 @@ describe "IO#ungetc" do
-> { @io.sysread(1) }.should raise_error(IOError)
end
- ruby_version_is ""..."3.0" do
- it "does not affect the stream and returns nil when passed nil" do
- @io.getc.should == ?V
- @io.ungetc(nil)
- @io.getc.should == ?o
- end
- end
-
- ruby_version_is "3.0" do
- it "raises TypeError if passed nil" do
- @io.getc.should == ?V
- proc{@io.ungetc(nil)}.should raise_error(TypeError)
- end
+ it "raises TypeError if passed nil" do
+ @io.getc.should == ?V
+ proc{@io.ungetc(nil)}.should raise_error(TypeError)
end
it "puts one or more characters back in the stream" do
diff --git a/spec/ruby/core/io/write_nonblock_spec.rb b/spec/ruby/core/io/write_nonblock_spec.rb
index a8b9ce0a36..c403c864fd 100644
--- a/spec/ruby/core/io/write_nonblock_spec.rb
+++ b/spec/ruby/core/io/write_nonblock_spec.rb
@@ -31,6 +31,16 @@ platform_is_not :windows do
end
end
+ it "does not modify the passed argument" do
+ File.open(@filename, "w") do |f|
+ f.set_encoding(Encoding::IBM437)
+ # A character whose codepoint differs between UTF-8 and IBM437
+ f.write_nonblock("ƒ".freeze)
+ end
+
+ File.binread(@filename).bytes.should == [198, 146]
+ end
+
it "checks if the file is writable if writing zero bytes" do
-> {
@readonly_file.write_nonblock("")
@@ -40,6 +50,7 @@ platform_is_not :windows do
describe "IO#write_nonblock" do
it_behaves_like :io_write, :write_nonblock
+ it_behaves_like :io_write_no_transcode, :write_nonblock
end
end
diff --git a/spec/ruby/core/io/write_spec.rb b/spec/ruby/core/io/write_spec.rb
index 60e66e998f..4a26f8dbaf 100644
--- a/spec/ruby/core/io/write_spec.rb
+++ b/spec/ruby/core/io/write_spec.rb
@@ -24,10 +24,6 @@ describe "IO#write on a file" do
-> { @readonly_file.write("") }.should_not raise_error
end
- it "returns a length of 0 when writing a blank string" do
- @file.write('').should == 0
- end
-
before :each do
@external = Encoding.default_external
@internal = Encoding.default_internal
@@ -40,10 +36,44 @@ describe "IO#write on a file" do
Encoding.default_internal = @internal
end
+ it "returns a length of 0 when writing a blank string" do
+ @file.write('').should == 0
+ end
+
+ it "returns a length of 0 when writing blank strings" do
+ @file.write('', '', '').should == 0
+ end
+
+ it "returns a length of 0 when passed no arguments" do
+ @file.write().should == 0
+ end
+
it "returns the number of bytes written" do
@file.write("hellø").should == 6
end
+ it "does not modify the passed argument" do
+ File.open(@filename, "w") do |f|
+ f.set_encoding(Encoding::IBM437)
+ # A character whose codepoint differs between UTF-8 and IBM437
+ f.write("ƒ".freeze)
+ end
+
+ File.binread(@filename).bytes.should == [159]
+ end
+
+ it "does not modify arguments when passed multiple arguments and external encoding not set" do
+ a, b = "a".freeze, "b".freeze
+
+ File.open(@filename, "w") do |f|
+ f.write(a, b)
+ end
+
+ File.binread(@filename).bytes.should == [97, 98]
+ a.encoding.should == Encoding::UTF_8
+ b.encoding.should == Encoding::UTF_8
+ end
+
it "uses the encoding from the given option for non-ascii encoding" do
File.open(@filename, "w", encoding: Encoding::UTF_32LE) do |file|
file.write("hi").should == 8
@@ -51,8 +81,25 @@ describe "IO#write on a file" do
File.binread(@filename).should == "h\u0000\u0000\u0000i\u0000\u0000\u0000"
end
- it "uses an :open_args option" do
- IO.write(@filename, 'hi', open_args: ["w", nil, {encoding: Encoding::UTF_32LE}]).should == 8
+ it "uses the encoding from the given option for non-ascii encoding even if in binary mode" do
+ File.open(@filename, "w", encoding: Encoding::UTF_32LE, binmode: true) do |file|
+ file.should.binmode?
+ file.write("hi").should == 8
+ end
+ File.binread(@filename).should == "h\u0000\u0000\u0000i\u0000\u0000\u0000"
+
+ File.open(@filename, "wb", encoding: Encoding::UTF_32LE) do |file|
+ file.should.binmode?
+ file.write("hi").should == 8
+ end
+ File.binread(@filename).should == "h\u0000\u0000\u0000i\u0000\u0000\u0000"
+ end
+
+ it "uses the encoding from the given option for non-ascii encoding when multiple arguments passes" do
+ File.open(@filename, "w", encoding: Encoding::UTF_32LE) do |file|
+ file.write("h", "i").should == 8
+ end
+ File.binread(@filename).should == "h\u0000\u0000\u0000i\u0000\u0000\u0000"
end
it "raises a invalid byte sequence error if invalid bytes are being written" do
@@ -72,6 +119,20 @@ describe "IO#write on a file" do
res = "H#{ë}ll#{ö}"
File.binread(@filename).should == res.force_encoding(Encoding::BINARY)
end
+
+ platform_is_not :windows do
+ it "writes binary data if no encoding is given and multiple arguments passed" do
+ File.open(@filename, "w") do |file|
+ file.write("\x87".b, "ą") # 0x87 isn't a valid UTF-8 binary representation of a character
+ end
+ File.binread(@filename).bytes.should == [0x87, 0xC4, 0x85]
+
+ File.open(@filename, "w") do |file|
+ file.write("\x61".encode("utf-32le"), "ą")
+ end
+ File.binread(@filename).bytes.should == [0x61, 0x00, 0x00, 0x00, 0xC4, 0x85]
+ end
+ end
end
describe "IO.write" do
@@ -86,10 +147,38 @@ describe "IO.write" do
File.read(@filename).should == "\0\0hi"
end
+ it "requires mode to be specified in :open_args" do
+ -> {
+ IO.write(@filename, 'hi', open_args: [{encoding: Encoding::UTF_32LE, binmode: true}])
+ }.should raise_error(IOError, "not opened for writing")
+
+ IO.write(@filename, 'hi', open_args: ["w", {encoding: Encoding::UTF_32LE, binmode: true}]).should == 8
+ IO.write(@filename, 'hi', open_args: [{encoding: Encoding::UTF_32LE, binmode: true, mode: "w"}]).should == 8
+ end
+
+ it "requires mode to be specified in :open_args even if flags option passed" do
+ -> {
+ IO.write(@filename, 'hi', open_args: [{encoding: Encoding::UTF_32LE, binmode: true, flags: File::CREAT}])
+ }.should raise_error(IOError, "not opened for writing")
+
+ IO.write(@filename, 'hi', open_args: ["w", {encoding: Encoding::UTF_32LE, binmode: true, flags: File::CREAT}]).should == 8
+ IO.write(@filename, 'hi', open_args: [{encoding: Encoding::UTF_32LE, binmode: true, flags: File::CREAT, mode: "w"}]).should == 8
+ end
+
it "uses the given encoding and returns the number of bytes written" do
IO.write(@filename, 'hi', mode: "w", encoding: Encoding::UTF_32LE).should == 8
end
+ it "raises ArgumentError if encoding is specified in mode parameter and is given as :encoding option" do
+ -> {
+ IO.write(@filename, 'hi', mode: "w:UTF-16LE:UTF-16BE", encoding: Encoding::UTF_32LE)
+ }.should raise_error(ArgumentError, "encoding specified twice")
+
+ -> {
+ IO.write(@filename, 'hi', mode: "w:UTF-16BE", encoding: Encoding::UTF_32LE)
+ }.should raise_error(ArgumentError, "encoding specified twice")
+ end
+
it "writes the file with the permissions in the :perm parameter" do
rm_r @filename
IO.write(@filename, 'write :perm spec', mode: "w", perm: 0o755).should == 16
@@ -114,23 +203,39 @@ describe "IO.write" do
rm_r @fifo
end
- it "writes correctly" do
- thr = Thread.new do
- IO.read(@fifo)
- end
- begin
- string = "hi"
- IO.write(@fifo, string).should == string.length
- ensure
- thr.join
+ # rb_cloexec_open() is currently missing a retry on EINTR.
+ # @ioquatix is looking into fixing it. Quarantined until it's done.
+ quarantine! do
+ it "writes correctly" do
+ thr = Thread.new do
+ IO.read(@fifo)
+ end
+ begin
+ string = "hi"
+ IO.write(@fifo, string).should == string.length
+ ensure
+ thr.join
+ end
end
end
end
+
+ ruby_version_is "3.3" do
+ # https://bugs.ruby-lang.org/issues/19630
+ it "warns about deprecation given a path with a pipe" do
+ -> {
+ -> {
+ IO.write("|cat", "xxx")
+ }.should output_to_fd("xxx")
+ }.should complain(/IO process creation with a leading '\|'/)
+ end
+ end
end
end
describe "IO#write" do
it_behaves_like :io_write, :write
+ it_behaves_like :io_write_transcode, :write
it "accepts multiple arguments" do
IO.pipe do |r, w|
@@ -168,3 +273,25 @@ platform_is :windows do
end
end
end
+
+describe "IO#write on STDOUT" do
+ # https://bugs.ruby-lang.org/issues/14413
+ platform_is_not :windows do
+ it "raises SignalException SIGPIPE if the stream is closed instead of Errno::EPIPE like other IOs" do
+ stderr_file = tmp("stderr")
+ begin
+ IO.popen([*ruby_exe, "-e", "loop { puts :ok }"], "r", err: stderr_file) do |io|
+ io.gets.should == "ok\n"
+ io.close
+ end
+ status = $?
+ status.should_not.success?
+ status.should.signaled?
+ Signal.signame(status.termsig).should == 'PIPE'
+ File.read(stderr_file).should.empty?
+ ensure
+ rm_r stderr_file
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/kernel/Complex_spec.rb b/spec/ruby/core/kernel/Complex_spec.rb
index 4f043526b8..346d50ab5e 100644
--- a/spec/ruby/core/kernel/Complex_spec.rb
+++ b/spec/ruby/core/kernel/Complex_spec.rb
@@ -1,4 +1,6 @@
require_relative '../../spec_helper'
+require_relative '../../shared/kernel/complex'
+require_relative 'fixtures/Complex'
describe "Kernel.Complex()" do
describe "when passed [Complex, Complex]" do
@@ -58,7 +60,92 @@ describe "Kernel.Complex()" do
end
end
- describe "when passed a String" do
+ describe "when passed [String]" do
+ it_behaves_like :kernel_complex, :Complex_method, KernelSpecs
+
+ context "invalid argument" do
+ it "raises Encoding::CompatibilityError if String is in not ASCII-compatible encoding" do
+ -> {
+ Complex("79+4i".encode("UTF-16"))
+ }.should raise_error(Encoding::CompatibilityError, "ASCII incompatible encoding: UTF-16")
+ end
+
+ it "raises ArgumentError for unrecognised Strings" do
+ -> {
+ Complex("ruby")
+ }.should raise_error(ArgumentError, 'invalid value for convert(): "ruby"')
+ end
+
+ it "raises ArgumentError for trailing garbage" do
+ -> {
+ Complex("79+4iruby")
+ }.should raise_error(ArgumentError, 'invalid value for convert(): "79+4iruby"')
+ end
+
+ it "does not understand Float::INFINITY" do
+ -> {
+ Complex("Infinity")
+ }.should raise_error(ArgumentError, 'invalid value for convert(): "Infinity"')
+
+ -> {
+ Complex("-Infinity")
+ }.should raise_error(ArgumentError, 'invalid value for convert(): "-Infinity"')
+ end
+
+ it "does not understand Float::NAN" do
+ -> {
+ Complex("NaN")
+ }.should raise_error(ArgumentError, 'invalid value for convert(): "NaN"')
+ end
+
+ it "does not understand a sequence of _" do
+ -> {
+ Complex("7__9+4__0i")
+ }.should raise_error(ArgumentError, 'invalid value for convert(): "7__9+4__0i"')
+ end
+
+ it "does not allow null-byte" do
+ -> {
+ Complex("1-2i\0")
+ }.should raise_error(ArgumentError, "string contains null byte")
+ end
+ end
+
+ context "invalid argument and exception: false passed" do
+ it "raises Encoding::CompatibilityError if String is in not ASCII-compatible encoding" do
+ -> {
+ Complex("79+4i".encode("UTF-16"), exception: false)
+ }.should raise_error(Encoding::CompatibilityError, "ASCII incompatible encoding: UTF-16")
+ end
+
+ it "returns nil for unrecognised Strings" do
+ Complex("ruby", exception: false).should == nil
+ end
+
+ it "returns nil when trailing garbage" do
+ Complex("79+4iruby", exception: false).should == nil
+ end
+
+ it "returns nil for Float::INFINITY" do
+ Complex("Infinity", exception: false).should == nil
+ Complex("-Infinity", exception: false).should == nil
+ end
+
+ it "returns nil for Float::NAN" do
+ Complex("NaN", exception: false).should == nil
+ end
+
+ it "returns nil when there is a sequence of _" do
+ Complex("7__9+4__0i", exception: false).should == nil
+ end
+
+ it "returns nil when String contains null-byte" do
+ Complex("1-2i\0", exception: false).should == nil
+ end
+ end
+ end
+
+ describe "when passes [String, String]" do
it "needs to be reviewed for spec completeness"
end
@@ -182,4 +269,8 @@ describe "Kernel.Complex()" do
end
end
end
+
+ it "freezes its result" do
+ Complex(1).frozen?.should == true
+ end
end
diff --git a/spec/ruby/core/kernel/Float_spec.rb b/spec/ruby/core/kernel/Float_spec.rb
index 015bcb33d6..0f83cb5824 100644
--- a/spec/ruby/core/kernel/Float_spec.rb
+++ b/spec/ruby/core/kernel/Float_spec.rb
@@ -41,7 +41,7 @@ describe :kernel_float, shared: true do
end
it "converts Strings to floats without calling #to_f" do
- string = "10"
+ string = +"10"
string.should_not_receive(:to_f)
@object.send(:Float, string).should == 10.0
end
diff --git a/spec/ruby/core/kernel/Integer_spec.rb b/spec/ruby/core/kernel/Integer_spec.rb
index 2c78e27428..74dd3e0dd2 100644
--- a/spec/ruby/core/kernel/Integer_spec.rb
+++ b/spec/ruby/core/kernel/Integer_spec.rb
@@ -145,7 +145,7 @@ describe :kernel_integer, shared: true do
end
end
-describe "Integer() given a String", shared: true do
+describe :kernel_integer_string, shared: true do
it "raises an ArgumentError if the String is a null byte" do
-> { Integer("\0") }.should raise_error(ArgumentError)
end
@@ -348,7 +348,7 @@ describe "Integer() given a String", shared: true do
end
end
-describe "Integer() given a String and base", shared: true do
+describe :kernel_integer_string_base, shared: true do
it "raises an ArgumentError if the String is a null byte" do
-> { Integer("\0", 2) }.should raise_error(ArgumentError)
end
@@ -573,9 +573,31 @@ describe "Integer() given a String and base", shared: true do
-> { Integer("0#{d}1", base) }.should raise_error(ArgumentError)
end
end
+ end
+
+ it "raises an ArgumentError if a base is given for a non-String value" do
+ -> { Integer(98, 15) }.should raise_error(ArgumentError)
+ end
+
+ it "tries to convert the base to an integer using to_int" do
+ obj = mock('8')
+ obj.should_receive(:to_int).and_return(8)
+
+ Integer("777", obj).should == 0777
+ end
+
+ # https://bugs.ruby-lang.org/issues/19349
+ ruby_version_is ''...'3.3' do
+ it "ignores the base if it is not an integer and does not respond to #to_i" do
+ Integer("777", "8").should == 777
+ end
+ end
- it "raises an ArgumentError if a base is given for a non-String value" do
- -> { Integer(98, 15) }.should raise_error(ArgumentError)
+ ruby_version_is '3.3' do
+ it "raises a TypeError if it is not an integer and does not respond to #to_i" do
+ -> {
+ Integer("777", "8")
+ }.should raise_error(TypeError, "no implicit conversion of String into Integer")
end
end
@@ -777,9 +799,9 @@ describe "Kernel.Integer" do
# TODO: fix these specs
it_behaves_like :kernel_integer, :Integer, Kernel
- it_behaves_like "Integer() given a String", :Integer
+ it_behaves_like :kernel_integer_string, :Integer
- it_behaves_like "Integer() given a String and base", :Integer
+ it_behaves_like :kernel_integer_string_base, :Integer
it "is a public method" do
Kernel.Integer(10).should == 10
@@ -791,9 +813,9 @@ describe "Kernel#Integer" do
# TODO: fix these specs
it_behaves_like :kernel_integer, :Integer, Object.new
- it_behaves_like "Integer() given a String", :Integer
+ it_behaves_like :kernel_integer_string, :Integer
- it_behaves_like "Integer() given a String and base", :Integer
+ it_behaves_like :kernel_integer_string_base, :Integer
it "is a private method" do
Kernel.should have_private_instance_method(:Integer)
diff --git a/spec/ruby/core/kernel/String_spec.rb b/spec/ruby/core/kernel/String_spec.rb
index 47ee797be5..7caec6eda5 100644
--- a/spec/ruby/core/kernel/String_spec.rb
+++ b/spec/ruby/core/kernel/String_spec.rb
@@ -78,7 +78,7 @@ describe :kernel_String, shared: true do
end
it "returns the same object if it is already a String" do
- string = "Hello"
+ string = +"Hello"
string.should_not_receive(:to_s)
string2 = @object.send(@method, string)
string.should equal(string2)
diff --git a/spec/ruby/core/kernel/__dir___spec.rb b/spec/ruby/core/kernel/__dir___spec.rb
index 324792a408..242adbf48b 100644
--- a/spec/ruby/core/kernel/__dir___spec.rb
+++ b/spec/ruby/core/kernel/__dir___spec.rb
@@ -19,19 +19,9 @@ describe "Kernel#__dir__" do
end
end
- ruby_version_is ""..."3.0" do
- context "when used in eval with top level binding" do
- it "returns the real name of the directory containing the currently-executing file" do
- eval("__dir__", binding).should == File.realpath(File.dirname(__FILE__))
- end
- end
- end
-
- ruby_version_is "3.0" do
- context "when used in eval with top level binding" do
- it "returns nil" do
- eval("__dir__", binding).should == nil
- end
+ context "when used in eval with top level binding" do
+ it "returns nil" do
+ eval("__dir__", binding).should == nil
end
end
end
diff --git a/spec/ruby/core/kernel/at_exit_spec.rb b/spec/ruby/core/kernel/at_exit_spec.rb
index a784c1ae17..ebd9a71d15 100644
--- a/spec/ruby/core/kernel/at_exit_spec.rb
+++ b/spec/ruby/core/kernel/at_exit_spec.rb
@@ -1,67 +1,16 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
+require_relative '../../shared/kernel/at_exit'
describe "Kernel.at_exit" do
+ it_behaves_like :kernel_at_exit, :at_exit
+
it "is a private method" do
Kernel.should have_private_instance_method(:at_exit)
end
- it "runs after all other code" do
- ruby_exe("at_exit {print 5}; print 6").should == "65"
- end
-
- it "runs in reverse order of registration" do
- code = "at_exit {print 4};at_exit {print 5}; print 6; at_exit {print 7}"
- ruby_exe(code).should == "6754"
- end
-
- it "allows calling exit inside at_exit handler" do
- code = "at_exit {print 3}; at_exit {print 4; exit; print 5}; at_exit {print 6}"
- ruby_exe(code).should == "643"
- end
-
- it "gives access to the last raised exception" do
- code = <<-EOC
- at_exit do
- puts "The exception matches: \#{$! == $exception} (message=\#{$!.message})"
- end
-
- begin
- raise "foo"
- rescue => $exception
- raise
- end
- EOC
-
- result = ruby_exe(code, args: "2>&1", exit_status: 1)
- result.lines.should.include?("The exception matches: true (message=foo)\n")
- end
-
- it "both exceptions in at_exit and in the main script are printed" do
- code = 'at_exit { raise "at_exit_error" }; raise "main_script_error"'
- result = ruby_exe(code, args: "2>&1", exit_status: 1)
- result.should.include?('at_exit_error (RuntimeError)')
- result.should.include?('main_script_error (RuntimeError)')
- end
-
- it "decides the exit status if both at_exit and the main script raise SystemExit" do
- ruby_exe('at_exit { exit 43 }; exit 42', args: "2>&1", exit_status: 43)
- $?.exitstatus.should == 43
- end
-
- it "runs all at_exit even if some raise exceptions" do
- code = 'at_exit { STDERR.puts "last" }; at_exit { exit 43 }; at_exit { STDERR.puts "first" }; exit 42'
- result = ruby_exe(code, args: "2>&1", exit_status: 43)
- result.should == "first\nlast\n"
- $?.exitstatus.should == 43
- end
-
- it "runs at_exit handlers even if the main script fails to parse" do
- script = fixture(__FILE__, "at_exit.rb")
- result = ruby_exe('{', options: "-r#{script}", args: "2>&1", exit_status: 1)
- $?.should_not.success?
- result.should.include?("at_exit ran\n")
- result.should.include?("syntax error")
+ it "raises ArgumentError if called without a block" do
+ -> { at_exit }.should raise_error(ArgumentError, "called without a block")
end
end
diff --git a/spec/ruby/core/kernel/caller_locations_spec.rb b/spec/ruby/core/kernel/caller_locations_spec.rb
index 3ec8f0f432..aaacd9a910 100644
--- a/spec/ruby/core/kernel/caller_locations_spec.rb
+++ b/spec/ruby/core/kernel/caller_locations_spec.rb
@@ -34,12 +34,10 @@ describe 'Kernel#caller_locations' do
locations2.map(&:to_s).should == locations1[2..-1].map(&:to_s)
end
- ruby_version_is "2.7" do
- it "works with beginless ranges" do
- locations1 = caller_locations(0)
- locations2 = caller_locations(eval("(...5)"))
- locations2.map(&:to_s)[eval("(2..)")].should == locations1[eval("(...5)")].map(&:to_s)[eval("(2..)")]
- end
+ it "works with beginless ranges" do
+ locations1 = caller_locations(0)
+ locations2 = caller_locations((...5))
+ locations2.map(&:to_s)[eval("(2..)")].should == locations1[(...5)].map(&:to_s)[eval("(2..)")]
end
it "can be called with a range whose end is negative" do
@@ -73,14 +71,28 @@ describe 'Kernel#caller_locations' 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:')
-
- loc = nil
- tap { loc = caller_locations(1, 1)[0] }
- loc.label.should == "tap"
- loc.path.should.start_with? "<internal:"
+ ruby_version_is ""..."3.4" do
+ it "includes core library methods defined in Ruby" do
+ file, line = Kernel.instance_method(:tap).source_location
+ file.should.start_with?('<internal:')
+
+ loc = nil
+ tap { loc = caller_locations(1, 1)[0] }
+ loc.label.should == "tap"
+ loc.path.should.start_with? "<internal:"
+ end
+ end
+
+ ruby_version_is "3.4" do
+ it "includes core library methods defined in Ruby" do
+ file, line = Kernel.instance_method(:tap).source_location
+ file.should.start_with?('<internal:')
+
+ loc = nil
+ tap { loc = caller_locations(1, 1)[0] }
+ loc.label.should == "Kernel#tap"
+ loc.path.should.start_with? "<internal:"
+ end
end
end
end
diff --git a/spec/ruby/core/kernel/caller_spec.rb b/spec/ruby/core/kernel/caller_spec.rb
index dba65ddcb0..c3d63ccb00 100644
--- a/spec/ruby/core/kernel/caller_spec.rb
+++ b/spec/ruby/core/kernel/caller_spec.rb
@@ -38,10 +38,9 @@ describe 'Kernel#caller' do
it "returns an Array with the block given to #at_exit at the base of the stack" do
path = fixture(__FILE__, "caller_at_exit.rb")
lines = ruby_exe(path).lines
- lines.should == [
- "#{path}:6:in `foo'\n",
- "#{path}:2:in `block in <main>'\n"
- ]
+ lines.size.should == 2
+ lines[0].should =~ /\A#{path}:6:in [`'](?:Object#)?foo'\n\z/
+ lines[1].should =~ /\A#{path}:2:in [`']block in <main>'\n\z/
end
it "works with endless ranges" do
@@ -50,12 +49,10 @@ describe 'Kernel#caller' do
locations2.map(&:to_s).should == locations1[2..-1].map(&:to_s)
end
- ruby_version_is "2.7" do
- it "works with beginless ranges" do
- locations1 = KernelSpecs::CallerTest.locations(0)
- locations2 = KernelSpecs::CallerTest.locations(eval("(..5)"))
- locations2.map(&:to_s)[eval("(2..)")].should == locations1[eval("(..5)")].map(&:to_s)[eval("(2..)")]
- end
+ it "works with beginless ranges" do
+ locations1 = KernelSpecs::CallerTest.locations(0)
+ locations2 = KernelSpecs::CallerTest.locations((..5))
+ locations2.map(&:to_s)[eval("(2..)")].should == locations1[(..5)].map(&:to_s)[eval("(2..)")]
end
guard -> { Kernel.instance_method(:tap).source_location } do
@@ -65,8 +62,7 @@ describe 'Kernel#caller' do
loc = nil
tap { loc = caller(1, 1)[0] }
- loc.should.end_with? "in `tap'"
- loc.should.start_with? "<internal:"
+ loc.should =~ /\A<internal:.*in [`'](?:Kernel#)?tap'\z/
end
end
end
diff --git a/spec/ruby/core/kernel/catch_spec.rb b/spec/ruby/core/kernel/catch_spec.rb
index 4060172429..9f59d3b384 100644
--- a/spec/ruby/core/kernel/catch_spec.rb
+++ b/spec/ruby/core/kernel/catch_spec.rb
@@ -35,7 +35,7 @@ describe "Kernel.catch" do
end
it "raises an ArgumentError if a String with different identity is thrown" do
- -> { catch("exit") { throw "exit" } }.should raise_error(ArgumentError)
+ -> { catch("exit".dup) { throw "exit".dup } }.should raise_error(ArgumentError)
end
it "catches a Symbol when thrown a matching Symbol" do
diff --git a/spec/ruby/core/kernel/class_spec.rb b/spec/ruby/core/kernel/class_spec.rb
index 2725bde19b..b1d9df1671 100644
--- a/spec/ruby/core/kernel/class_spec.rb
+++ b/spec/ruby/core/kernel/class_spec.rb
@@ -19,7 +19,7 @@ describe "Kernel#class" do
end
it "returns the first non-singleton class" do
- a = "hello"
+ a = +"hello"
def a.my_singleton_method; end
a.class.should equal(String)
end
diff --git a/spec/ruby/core/kernel/clone_spec.rb b/spec/ruby/core/kernel/clone_spec.rb
index 38ae1984c0..5adcbbe603 100644
--- a/spec/ruby/core/kernel/clone_spec.rb
+++ b/spec/ruby/core/kernel/clone_spec.rb
@@ -45,26 +45,18 @@ describe "Kernel#clone" do
end
describe "with freeze: nil" do
- ruby_version_is ""..."3.0" do
- it "raises ArgumentError" do
- -> { @obj.clone(freeze: nil) }.should raise_error(ArgumentError, /unexpected value for freeze: NilClass/)
- end
- end
-
- ruby_version_is "3.0" do
- it "copies frozen state from the original, like #clone without arguments" do
- o2 = @obj.clone(freeze: nil)
- o2.should_not.frozen?
+ it "copies frozen state from the original, like #clone without arguments" do
+ o2 = @obj.clone(freeze: nil)
+ o2.should_not.frozen?
- @obj.freeze
- o3 = @obj.clone(freeze: nil)
- o3.should.frozen?
- end
+ @obj.freeze
+ o3 = @obj.clone(freeze: nil)
+ o3.should.frozen?
+ end
- it "copies frozen?" do
- o = "".freeze.clone(freeze: nil)
- o.frozen?.should be_true
- end
+ it "copies frozen?" do
+ o = "".freeze.clone(freeze: nil)
+ o.frozen?.should be_true
end
end
@@ -74,33 +66,19 @@ describe "Kernel#clone" do
@obj.clone(freeze: true).should.frozen?
end
- ruby_version_is ''...'3.0' do
- it 'does not freeze the copy even if the original is not frozen' do
- @obj.clone(freeze: true).should_not.frozen?
- end
-
- it "calls #initialize_clone with no kwargs" do
- obj = KernelSpecs::CloneFreeze.new
- obj.clone(freeze: true)
- ScratchPad.recorded.should == [obj, {}]
- end
+ it 'freezes the copy even if the original was not frozen' do
+ @obj.clone(freeze: true).should.frozen?
end
- ruby_version_is '3.0' do
- it 'freezes the copy even if the original was not frozen' do
- @obj.clone(freeze: true).should.frozen?
- end
-
- it "calls #initialize_clone with kwargs freeze: true" do
- obj = KernelSpecs::CloneFreeze.new
- obj.clone(freeze: true)
- ScratchPad.recorded.should == [obj, { freeze: true }]
- end
+ it "calls #initialize_clone with kwargs freeze: true" do
+ obj = KernelSpecs::CloneFreeze.new
+ obj.clone(freeze: true)
+ ScratchPad.recorded.should == [obj, { freeze: true }]
+ end
- it "calls #initialize_clone with kwargs freeze: true even if #initialize_clone only takes a single argument" do
- obj = KernelSpecs::Clone.new
- -> { obj.clone(freeze: true) }.should raise_error(ArgumentError, 'wrong number of arguments (given 2, expected 1)')
- end
+ it "calls #initialize_clone with kwargs freeze: true even if #initialize_clone only takes a single argument" do
+ obj = KernelSpecs::Clone.new
+ -> { obj.clone(freeze: true) }.should raise_error(ArgumentError, 'wrong number of arguments (given 2, expected 1)')
end
end
@@ -114,25 +92,15 @@ describe "Kernel#clone" do
@obj.clone(freeze: false).should_not.frozen?
end
- ruby_version_is ''...'3.0' do
- it "calls #initialize_clone with no kwargs" do
- obj = KernelSpecs::CloneFreeze.new
- obj.clone(freeze: false)
- ScratchPad.recorded.should == [obj, {}]
- end
+ it "calls #initialize_clone with kwargs freeze: false" do
+ obj = KernelSpecs::CloneFreeze.new
+ obj.clone(freeze: false)
+ ScratchPad.recorded.should == [obj, { freeze: false }]
end
- ruby_version_is '3.0' do
- it "calls #initialize_clone with kwargs freeze: false" do
- obj = KernelSpecs::CloneFreeze.new
- obj.clone(freeze: false)
- ScratchPad.recorded.should == [obj, { freeze: false }]
- end
-
- it "calls #initialize_clone with kwargs freeze: false even if #initialize_clone only takes a single argument" do
- obj = KernelSpecs::Clone.new
- -> { obj.clone(freeze: false) }.should raise_error(ArgumentError, 'wrong number of arguments (given 2, expected 1)')
- end
+ it "calls #initialize_clone with kwargs freeze: false even if #initialize_clone only takes a single argument" do
+ obj = KernelSpecs::Clone.new
+ -> { obj.clone(freeze: false) }.should raise_error(ArgumentError, 'wrong number of arguments (given 2, expected 1)')
end
end
@@ -206,11 +174,4 @@ describe "Kernel#clone" do
cloned.bar.should == ['a']
end
-
- ruby_version_is ''...'2.7' do
- it 'copies tainted?' do
- o = ''.taint.clone
- o.tainted?.should be_true
- end
- end
end
diff --git a/spec/ruby/core/kernel/define_singleton_method_spec.rb b/spec/ruby/core/kernel/define_singleton_method_spec.rb
index dc77c3e6f8..24acec84f5 100644
--- a/spec/ruby/core/kernel/define_singleton_method_spec.rb
+++ b/spec/ruby/core/kernel/define_singleton_method_spec.rb
@@ -96,4 +96,25 @@ describe "Kernel#define_singleton_method" do
o.define(:foo) { raise "not used" }
}.should raise_error(ArgumentError)
end
+
+ it "always defines the method with public visibility" do
+ cls = Class.new
+ def cls.define(name, &block)
+ private
+ define_singleton_method(name, &block)
+ end
+
+ -> {
+ suppress_warning do
+ cls.define(:foo) { :ok }
+ end
+ cls.foo.should == :ok
+ }.should_not raise_error(NoMethodError)
+ end
+
+ it "cannot define a singleton method with a frozen singleton class" do
+ o = Object.new
+ o.freeze
+ -> { o.define_singleton_method(:foo) { 1 } }.should raise_error(FrozenError)
+ end
end
diff --git a/spec/ruby/core/kernel/eval_spec.rb b/spec/ruby/core/kernel/eval_spec.rb
index 9be0f2dfd3..454bc4a58e 100644
--- a/spec/ruby/core/kernel/eval_spec.rb
+++ b/spec/ruby/core/kernel/eval_spec.rb
@@ -135,7 +135,7 @@ describe "Kernel#eval" do
it "includes file and line information in syntax error" do
expected = 'speccing.rb'
-> {
- eval('if true',TOPLEVEL_BINDING, expected)
+ eval('if true', TOPLEVEL_BINDING, expected)
}.should raise_error(SyntaxError) { |e|
e.message.should =~ /#{expected}:1:.+/
}
@@ -144,7 +144,7 @@ describe "Kernel#eval" do
it "evaluates string with given filename and negative linenumber" do
expected_file = 'speccing.rb'
-> {
- eval('if true',TOPLEVEL_BINDING, expected_file, -100)
+ eval('if true', TOPLEVEL_BINDING, expected_file, -100)
}.should raise_error(SyntaxError) { |e|
e.message.should =~ /#{expected_file}:-100:.+/
}
@@ -159,24 +159,7 @@ describe "Kernel#eval" do
end
end
- ruby_version_is ""..."3.0" do
- it "uses the filename of the binding if none is provided" do
- eval("__FILE__").should == "(eval)"
- suppress_warning {eval("__FILE__", binding)}.should == __FILE__
- eval("__FILE__", binding, "success").should == "success"
- suppress_warning {eval("eval '__FILE__', binding")}.should == "(eval)"
- suppress_warning {eval("eval '__FILE__', binding", binding)}.should == __FILE__
- suppress_warning {eval("eval '__FILE__', binding", binding, 'success')}.should == 'success'
- end
-
- it 'uses the given binding file and line for __FILE__ and __LINE__' do
- suppress_warning {
- eval("[__FILE__, __LINE__]", binding).should == [__FILE__, __LINE__]
- }
- end
- end
-
- ruby_version_is "3.0" do
+ ruby_version_is ""..."3.3" do
it "uses (eval) filename if none is provided" do
eval("__FILE__").should == "(eval)"
eval("__FILE__", binding).should == "(eval)"
@@ -192,6 +175,21 @@ describe "Kernel#eval" do
end
end
+ ruby_version_is "3.3" do
+ it "uses (eval at __FILE__:__LINE__) if none is provided" do
+ eval("__FILE__").should == "(eval at #{__FILE__}:#{__LINE__})"
+ eval("__FILE__", binding).should == "(eval at #{__FILE__}:#{__LINE__})"
+ eval("__FILE__", binding, "success").should == "success"
+ eval("eval '__FILE__', binding").should == "(eval at (eval at #{__FILE__}:#{__LINE__}):1)"
+ eval("eval '__FILE__', binding", binding).should == "(eval at (eval at #{__FILE__}:#{__LINE__}):1)"
+ eval("eval '__FILE__', binding", binding, 'success').should == "(eval at success:1)"
+ eval("eval '__FILE__', binding, 'success'", binding).should == 'success'
+ end
+
+ it 'uses (eval at __FILE__:__LINE__) for __FILE__ and 1 for __LINE__ with a binding argument' do
+ eval("[__FILE__, __LINE__]", binding).should == ["(eval at #{__FILE__}:#{__LINE__})", 1]
+ end
+ end
# Found via Rubinius bug github:#149
it "does not alter the value of __FILE__ in the binding" do
first_time = EvalSpecs.call_eval
@@ -228,6 +226,20 @@ describe "Kernel#eval" do
-> { eval("return :eval") }.call.should == :eval
end
+ it "returns from the method calling #eval when evaluating 'return'" do
+ def eval_return(n)
+ eval("return n*2")
+ end
+ -> { eval_return(3) }.call.should == 6
+ end
+
+ it "returns from the method calling #eval when evaluating 'return' in BEGIN" do
+ def eval_return(n)
+ eval("BEGIN {return n*3}")
+ end
+ -> { eval_return(4) }.call.should == 12
+ end
+
it "unwinds through a Proc-style closure and returns from a lambda-style closure in the closure chain" do
code = fixture __FILE__, "eval_return_with_lambda.rb"
ruby_exe(code).chomp.should == "a,b,c,eval,f"
@@ -249,6 +261,19 @@ describe "Kernel#eval" do
end
end
+ it "makes flip-flop operator work correctly" do
+ ScratchPad.record []
+
+ eval "10.times { |i| ScratchPad << i if (i == 4)...(i == 4) }"
+ ScratchPad.recorded.should == [4, 5, 6, 7, 8, 9]
+
+ ScratchPad.clear
+ end
+
+ it "returns nil if given an empty string" do
+ eval("").should == nil
+ end
+
# See language/magic_comment_spec.rb for more magic comments specs
describe "with a magic encoding comment" do
it "uses the magic comment encoding for the encoding of literal strings" do
@@ -325,12 +350,11 @@ CODE
end
it "allows a magic encoding comment and a subsequent frozen_string_literal magic comment" do
- # Make sure frozen_string_literal is not default true
- eval("'foo'".b).frozen?.should be_false
+ frozen_string_default = "test".frozen?
code = <<CODE.b
# encoding: UTF-8
-# frozen_string_literal: true
+# frozen_string_literal: #{!frozen_string_default}
class EvalSpecs
Vπstring = "frozen"
end
@@ -340,7 +364,7 @@ CODE
EvalSpecs.constants(false).should include(:"Vπstring")
EvalSpecs::Vπstring.should == "frozen"
EvalSpecs::Vπstring.encoding.should == Encoding::UTF_8
- EvalSpecs::Vπstring.frozen?.should be_true
+ EvalSpecs::Vπstring.frozen?.should == !frozen_string_default
end
it "allows a magic encoding comment and a frozen_string_literal magic comment on the same line in emacs style" do
@@ -359,8 +383,9 @@ CODE
end
it "ignores the magic encoding comment if it is after a frozen_string_literal magic comment" do
+ frozen_string_default = "test".frozen?
code = <<CODE.b
-# frozen_string_literal: true
+# frozen_string_literal: #{!frozen_string_default}
# encoding: UTF-8
class EvalSpecs
Vπfrozen_first = "frozen"
@@ -374,23 +399,24 @@ CODE
value = EvalSpecs.const_get(binary_constant)
value.should == "frozen"
value.encoding.should == Encoding::BINARY
- value.frozen?.should be_true
+ value.frozen?.should == !frozen_string_default
end
it "ignores the frozen_string_literal magic comment if it appears after a token and warns if $VERBOSE is true" do
+ frozen_string_default = "test".frozen?
code = <<CODE
some_token_before_magic_comment = :anything
-# frozen_string_literal: true
+# frozen_string_literal: #{!frozen_string_default}
class EvalSpecs
Vπstring_not_frozen = "not frozen"
end
CODE
- -> { eval(code) }.should complain(/warning: `frozen_string_literal' is ignored after any tokens/, verbose: true)
- EvalSpecs::Vπstring_not_frozen.frozen?.should be_false
+ -> { eval(code) }.should complain(/warning: [`']frozen_string_literal' is ignored after any tokens/, verbose: true)
+ EvalSpecs::Vπstring_not_frozen.frozen?.should == frozen_string_default
EvalSpecs.send :remove_const, :Vπstring_not_frozen
-> { eval(code) }.should_not complain(verbose: false)
- EvalSpecs::Vπstring_not_frozen.frozen?.should be_false
+ EvalSpecs::Vπstring_not_frozen.frozen?.should == frozen_string_default
EvalSpecs.send :remove_const, :Vπstring_not_frozen
end
end
diff --git a/spec/ruby/core/kernel/exec_spec.rb b/spec/ruby/core/kernel/exec_spec.rb
index 1b4a7ae6f4..3d9520ad67 100644
--- a/spec/ruby/core/kernel/exec_spec.rb
+++ b/spec/ruby/core/kernel/exec_spec.rb
@@ -7,12 +7,12 @@ describe "Kernel#exec" do
end
it "runs the specified command, replacing current process" do
- ruby_exe('exec "echo hello"; puts "fail"', escape: true).should == "hello\n"
+ ruby_exe('exec "echo hello"; puts "fail"').should == "hello\n"
end
end
describe "Kernel.exec" do
it "runs the specified command, replacing current process" do
- ruby_exe('Kernel.exec "echo hello"; puts "fail"', escape: true).should == "hello\n"
+ ruby_exe('Kernel.exec "echo hello"; puts "fail"').should == "hello\n"
end
end
diff --git a/spec/ruby/core/kernel/exit_spec.rb b/spec/ruby/core/kernel/exit_spec.rb
index f168cb375e..93cec3fee5 100644
--- a/spec/ruby/core/kernel/exit_spec.rb
+++ b/spec/ruby/core/kernel/exit_spec.rb
@@ -10,6 +10,10 @@ describe "Kernel#exit" do
it_behaves_like :process_exit, :exit, KernelSpecs::Method.new
end
+describe "Kernel.exit" do
+ it_behaves_like :process_exit, :exit, Kernel
+end
+
describe "Kernel#exit!" do
it "is a private method" do
Kernel.should have_private_instance_method(:exit!)
@@ -18,10 +22,6 @@ describe "Kernel#exit!" do
it_behaves_like :process_exit!, :exit!, "self"
end
-describe "Kernel.exit" do
- it_behaves_like :process_exit, :exit, Kernel
-end
-
describe "Kernel.exit!" do
- it_behaves_like :process_exit!, :exit!, Kernel
+ it_behaves_like :process_exit!, :exit!, "Kernel"
end
diff --git a/spec/ruby/core/kernel/fixtures/Complex.rb b/spec/ruby/core/kernel/fixtures/Complex.rb
new file mode 100644
index 0000000000..bf14d55ad5
--- /dev/null
+++ b/spec/ruby/core/kernel/fixtures/Complex.rb
@@ -0,0 +1,5 @@
+module KernelSpecs
+ def self.Complex_method(string)
+ Complex(string)
+ end
+end
diff --git a/spec/ruby/core/kernel/fixtures/at_exit.rb b/spec/ruby/core/kernel/fixtures/at_exit.rb
deleted file mode 100644
index 9c11a7ad6c..0000000000
--- a/spec/ruby/core/kernel/fixtures/at_exit.rb
+++ /dev/null
@@ -1,3 +0,0 @@
-at_exit do
- STDERR.puts "at_exit ran"
-end
diff --git a/spec/ruby/core/kernel/fixtures/warn_core_method.rb b/spec/ruby/core/kernel/fixtures/warn_core_method.rb
index f5dee6b668..fd82562404 100644
--- a/spec/ruby/core/kernel/fixtures/warn_core_method.rb
+++ b/spec/ruby/core/kernel/fixtures/warn_core_method.rb
@@ -1,6 +1,6 @@
raise 'should be run without RubyGems' if defined?(Gem)
-def deprecated(n=1)
+public def deprecated(n=1)
# puts nil, caller(0), nil
warn "use X instead", uplevel: n
end
diff --git a/spec/ruby/core/kernel/initialize_clone_spec.rb b/spec/ruby/core/kernel/initialize_clone_spec.rb
index 2d889f5aad..21a90c19f0 100644
--- a/spec/ruby/core/kernel/initialize_clone_spec.rb
+++ b/spec/ruby/core/kernel/initialize_clone_spec.rb
@@ -18,11 +18,9 @@ describe "Kernel#initialize_clone" do
a.send(:initialize_clone, b)
end
- ruby_version_is "3.0" do
- it "accepts a :freeze keyword argument for obj.clone(freeze: value)" do
- a = Object.new
- b = Object.new
- a.send(:initialize_clone, b, freeze: true).should == a
- end
+ it "accepts a :freeze keyword argument for obj.clone(freeze: value)" do
+ a = Object.new
+ b = Object.new
+ a.send(:initialize_clone, b, freeze: true).should == a
end
end
diff --git a/spec/ruby/core/kernel/initialize_copy_spec.rb b/spec/ruby/core/kernel/initialize_copy_spec.rb
index fe08d184ad..d71ca9f60f 100644
--- a/spec/ruby/core/kernel/initialize_copy_spec.rb
+++ b/spec/ruby/core/kernel/initialize_copy_spec.rb
@@ -1,11 +1,18 @@
require_relative '../../spec_helper'
describe "Kernel#initialize_copy" do
+ it "returns self" do
+ obj = Object.new
+ obj.send(:initialize_copy, obj).should.equal?(obj)
+ end
+
it "does nothing if the argument is the same as the receiver" do
obj = Object.new
obj.send(:initialize_copy, obj).should.equal?(obj)
- obj.freeze
+
+ obj = Object.new.freeze
obj.send(:initialize_copy, obj).should.equal?(obj)
+
1.send(:initialize_copy, 1).should.equal?(1)
end
diff --git a/spec/ruby/core/kernel/inspect_spec.rb b/spec/ruby/core/kernel/inspect_spec.rb
index e6fca8bf6f..1f9ce834ab 100644
--- a/spec/ruby/core/kernel/inspect_spec.rb
+++ b/spec/ruby/core/kernel/inspect_spec.rb
@@ -6,16 +6,6 @@ describe "Kernel#inspect" do
Object.new.inspect.should be_an_instance_of(String)
end
- ruby_version_is ''...'2.7' do
- it "returns a tainted string if self is tainted" do
- Object.new.taint.inspect.tainted?.should be_true
- end
-
- it "returns an untrusted string if self is untrusted" do
- Object.new.untrust.inspect.untrusted?.should be_true
- end
- end
-
it "does not call #to_s if it is defined" do
# We must use a bare Object here
obj = Object.new
diff --git a/spec/ruby/core/kernel/instance_variable_get_spec.rb b/spec/ruby/core/kernel/instance_variable_get_spec.rb
index bb6f03d3bf..f1d2a45df8 100644
--- a/spec/ruby/core/kernel/instance_variable_get_spec.rb
+++ b/spec/ruby/core/kernel/instance_variable_get_spec.rb
@@ -67,6 +67,12 @@ describe "Kernel#instance_variable_get when passed Symbol" do
it "raises a NameError when the passed Symbol is an invalid instance variable name" do
-> { @obj.instance_variable_get(:"@0") }.should raise_error(NameError)
end
+
+ it "returns nil or raises for frozen objects" do
+ nil.instance_variable_get(:@foo).should == nil
+ -> { nil.instance_variable_get(:foo) }.should raise_error(NameError)
+ :foo.instance_variable_get(:@foo).should == nil
+ end
end
describe "Kernel#instance_variable_get when passed String" do
diff --git a/spec/ruby/core/kernel/instance_variable_set_spec.rb b/spec/ruby/core/kernel/instance_variable_set_spec.rb
index 7fda30f72c..2c25f4366f 100644
--- a/spec/ruby/core/kernel/instance_variable_set_spec.rb
+++ b/spec/ruby/core/kernel/instance_variable_set_spec.rb
@@ -89,5 +89,17 @@ describe "Kernel#instance_variable_set" do
it "raises a FrozenError when passed replacement is different from stored object" do
-> { @frozen.instance_variable_set(:@ivar, :replacement) }.should raise_error(FrozenError)
end
+
+ it "accepts unicode instance variable names" do
+ o = Object.new
+ o.instance_variable_set(:@💙, 42)
+ o.instance_variable_get(:@💙).should == 42
+ end
+
+ it "raises for frozen objects" do
+ -> { nil.instance_variable_set(:@foo, 42) }.should raise_error(FrozenError)
+ -> { nil.instance_variable_set(:foo, 42) }.should raise_error(NameError)
+ -> { :foo.instance_variable_set(:@foo, 42) }.should raise_error(FrozenError)
+ end
end
end
diff --git a/spec/ruby/core/kernel/iterator_spec.rb b/spec/ruby/core/kernel/iterator_spec.rb
deleted file mode 100644
index 3fe8317f26..0000000000
--- a/spec/ruby/core/kernel/iterator_spec.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-
-ruby_version_is ""..."3.0" do
- describe "Kernel#iterator?" do
- it "is a private method" do
- Kernel.should have_private_instance_method(:iterator?)
- end
- end
-
- describe "Kernel.iterator?" do
- it "needs to be reviewed for spec completeness"
- end
-end
diff --git a/spec/ruby/core/kernel/lambda_spec.rb b/spec/ruby/core/kernel/lambda_spec.rb
index 2aa4d4f2fb..565536ac0d 100644
--- a/spec/ruby/core/kernel/lambda_spec.rb
+++ b/spec/ruby/core/kernel/lambda_spec.rb
@@ -26,42 +26,44 @@ describe "Kernel.lambda" do
l.lambda?.should be_true
end
- it "creates a lambda-style Proc if given a literal block via Kernel.public_send" do
- suppress_warning do
- l = Kernel.public_send(:lambda) { 42 }
- l.lambda?.should be_true
+ ruby_version_is ""..."3.3" do
+ it "creates a lambda-style Proc if given a literal block via Kernel.public_send" do
+ suppress_warning do
+ l = Kernel.public_send(:lambda) { 42 }
+ l.lambda?.should be_true
+ end
end
- end
- it "returns the passed Proc if given an existing Proc" do
- some_proc = proc {}
- l = suppress_warning {lambda(&some_proc)}
- l.should equal(some_proc)
- l.lambda?.should be_false
- end
+ it "returns the passed Proc if given an existing Proc" do
+ some_proc = proc {}
+ l = suppress_warning {lambda(&some_proc)}
+ l.should equal(some_proc)
+ l.lambda?.should be_false
+ end
- it "creates a lambda-style Proc when called with zsuper" do
- suppress_warning do
- l = KernelSpecs::LambdaSpecs::ForwardBlockWithZSuper.new.lambda { 42 }
- l.lambda?.should be_true
- l.call.should == 42
+ it "creates a lambda-style Proc when called with zsuper" do
+ suppress_warning do
+ l = KernelSpecs::LambdaSpecs::ForwardBlockWithZSuper.new.lambda { 42 }
+ l.lambda?.should be_true
+ l.call.should == 42
- lambda { l.call(:extra) }.should raise_error(ArgumentError)
+ lambda { l.call(:extra) }.should raise_error(ArgumentError)
+ end
end
- end
- it "returns the passed Proc if given an existing Proc through super" do
- some_proc = proc { }
- l = KernelSpecs::LambdaSpecs::SuperAmpersand.new.lambda(&some_proc)
- l.should equal(some_proc)
- l.lambda?.should be_false
- end
+ it "returns the passed Proc if given an existing Proc through super" do
+ some_proc = proc { }
+ l = KernelSpecs::LambdaSpecs::SuperAmpersand.new.lambda(&some_proc)
+ l.should equal(some_proc)
+ l.lambda?.should be_false
+ end
- it "does not create lambda-style Procs when captured with #method" do
- kernel_lambda = method(:lambda)
- l = suppress_warning {kernel_lambda.call { 42 }}
- l.lambda?.should be_false
- l.call(:extra).should == 42
+ it "does not create lambda-style Procs when captured with #method" do
+ kernel_lambda = method(:lambda)
+ l = suppress_warning {kernel_lambda.call { 42 }}
+ l.lambda?.should be_false
+ l.call(:extra).should == 42
+ end
end
it "checks the arity of the call when no args are specified" do
@@ -136,15 +138,21 @@ describe "Kernel.lambda" do
klass.new.ret.should == 1
end
- ruby_version_is "3.0" do
- context "when called without a literal block" do
+ context "when called without a literal block" do
+ ruby_version_is ""..."3.3" do
it "warns when proc isn't a lambda" do
-> { lambda(&proc{}) }.should complain("#{__FILE__}:#{__LINE__}: warning: lambda without a literal block is deprecated; use the proc without lambda instead\n")
end
+ end
- it "doesn't warn when proc is lambda" do
- -> { lambda(&lambda{}) }.should_not complain(verbose: true)
+ ruby_version_is "3.3" do
+ it "raises when proc isn't a lambda" do
+ -> { lambda(&proc{}) }.should raise_error(ArgumentError, /the lambda method requires a literal block/)
end
end
+
+ it "doesn't warn when proc is lambda" do
+ -> { lambda(&lambda{}) }.should_not complain(verbose: true)
+ end
end
end
diff --git a/spec/ruby/core/kernel/method_spec.rb b/spec/ruby/core/kernel/method_spec.rb
index 25c6691e10..3fc566d6a6 100644
--- a/spec/ruby/core/kernel/method_spec.rb
+++ b/spec/ruby/core/kernel/method_spec.rb
@@ -29,9 +29,52 @@ describe "Kernel#method" do
m.call.should == :defined
end
- it "can be called even if we only repond_to_missing? method, true" do
+ it "can be called even if we only respond_to_missing? method, true" do
m = KernelSpecs::RespondViaMissing.new.method(:handled_privately)
m.should be_an_instance_of(Method)
m.call(1, 2, 3).should == "Done handled_privately([1, 2, 3])"
end
+
+ it "can call a #method_missing accepting zero or one arguments" do
+ cls = Class.new do
+ def respond_to_missing?(name, *)
+ name == :foo or super
+ end
+ def method_missing
+ :no_args
+ end
+ end
+ m = cls.new.method(:foo)
+ -> { m.call }.should raise_error(ArgumentError)
+
+ cls = Class.new do
+ def respond_to_missing?(name, *)
+ name == :bar or super
+ end
+ def method_missing(m)
+ m
+ end
+ end
+ m = cls.new.method(:bar)
+ m.call.should == :bar
+ end
+
+ describe "converts the given name to a String using #to_str" do
+ it "calls #to_str to convert the given name to a String" do
+ name = mock("method-name")
+ name.should_receive(:to_str).and_return("hash")
+ Object.method(name).should == Object.method(:hash)
+ end
+
+ it "raises a TypeError if the given name can't be converted to a String" do
+ -> { Object.method(nil) }.should raise_error(TypeError)
+ -> { Object.method([]) }.should raise_error(TypeError)
+ end
+
+ it "raises a NoMethodError if the given argument raises a NoMethodError during type coercion to a String" do
+ name = mock("method-name")
+ name.should_receive(:to_str).and_raise(NoMethodError)
+ -> { Object.method(name) }.should raise_error(NoMethodError)
+ end
+ end
end
diff --git a/spec/ruby/core/kernel/not_match_spec.rb b/spec/ruby/core/kernel/not_match_spec.rb
index 906f18df2c..f8dd82fad8 100644
--- a/spec/ruby/core/kernel/not_match_spec.rb
+++ b/spec/ruby/core/kernel/not_match_spec.rb
@@ -14,6 +14,20 @@ 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
+ end
+
it 'can be overridden in subclasses' do
obj = KernelSpecs::NotMatch.new
(obj !~ :bar).should == :foo
diff --git a/spec/ruby/core/kernel/open_spec.rb b/spec/ruby/core/kernel/open_spec.rb
index 569f2f6a7f..bb42c31f31 100644
--- a/spec/ruby/core/kernel/open_spec.rb
+++ b/spec/ruby/core/kernel/open_spec.rb
@@ -27,9 +27,11 @@ describe "Kernel#open" do
open(@name, "r") { |f| f.gets }.should == @content
end
- platform_is_not :windows do
+ platform_is_not :windows, :wasi do
it "opens an io when path starts with a pipe" do
- @io = open("|date")
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ @io = open("|date")
+ end
begin
@io.should be_kind_of(IO)
@io.read
@@ -39,21 +41,27 @@ describe "Kernel#open" do
end
it "opens an io when called with a block" do
- @output = open("|date") { |f| f.read }
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ @output = open("|date") { |f| f.read }
+ end
@output.should_not == ''
end
it "opens an io for writing" do
- -> do
- bytes = open("|cat", "w") { |io| io.write(".") }
- bytes.should == 1
- end.should output_to_fd(".")
+ 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
platform_is :windows do
it "opens an io when path starts with a pipe" do
- @io = open("|date /t")
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ @io = open("|date /t")
+ end
begin
@io.should be_kind_of(IO)
@io.read
@@ -63,15 +71,36 @@ describe "Kernel#open" do
end
it "opens an io when called with a block" do
- @output = open("|date /t") { |f| f.read }
+ suppress_warning do # https://bugs.ruby-lang.org/issues/19630
+ @output = open("|date /t") { |f| f.read }
+ 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 '\|'/)
+ end
+ end
+
it "raises an ArgumentError if not passed one argument" do
-> { open }.should raise_error(ArgumentError)
end
+ it "accepts options as keyword arguments" do
+ @file = open(@name, "r", 0666, flags: File::CREAT)
+ @file.should be_kind_of(File)
+
+ -> {
+ open(@name, "r", 0666, {flags: File::CREAT})
+ }.should raise_error(ArgumentError, "wrong number of arguments (given 4, expected 1..3)")
+ end
+
describe "when given an object that responds to to_open" do
before :each do
ScratchPad.clear
@@ -109,11 +138,21 @@ describe "Kernel#open" do
it "passes its arguments onto #to_open" do
obj = mock('to_open')
- obj.should_receive(:to_open).with(1,2,3)
-
+ obj.should_receive(:to_open).with(1, 2, 3)
open(obj, 1, 2, 3)
end
+ it "passes keyword arguments onto #to_open as keyword arguments if to_open accepts them" do
+ obj = Object.new
+ def obj.to_open(*args, **kw)
+ ScratchPad << {args: args, kw: kw}
+ end
+
+ ScratchPad.record []
+ open(obj, 1, 2, 3, a: "b")
+ ScratchPad.recorded.should == [args: [1, 2, 3], kw: {a: "b"}]
+ end
+
it "passes the return value from #to_open to a block" do
obj = mock('to_open')
obj.should_receive(:to_open).and_return(:value)
@@ -137,28 +176,14 @@ describe "Kernel#open" do
open(@name, nil, nil) { |f| f.gets }.should == @content
end
- ruby_version_is ""..."3.0" do
- it "works correctly when redefined by open-uri" do
- code = <<~RUBY
+ it "is not redefined by open-uri" do
+ code = <<~RUBY
+ before = Kernel.instance_method(:open)
require 'open-uri'
- obj = Object.new
- def obj.to_open; self; end
- p open(obj) == obj
- RUBY
- ruby_exe(code, args: "2>&1").should == "true\n"
- end
- end
-
- ruby_version_is "3.0" do
- it "is not redefined by open-uri" do
- code = <<~RUBY
- before = Kernel.instance_method(:open)
- require 'open-uri'
- after = Kernel.instance_method(:open)
- p before == after
- RUBY
- ruby_exe(code, args: "2>&1").should == "true\n"
- end
+ after = Kernel.instance_method(:open)
+ p before == after
+ RUBY
+ ruby_exe(code, args: "2>&1").should == "true\n"
end
end
diff --git a/spec/ruby/core/kernel/p_spec.rb b/spec/ruby/core/kernel/p_spec.rb
index 1bdd1740ca..eae191aa54 100644
--- a/spec/ruby/core/kernel/p_spec.rb
+++ b/spec/ruby/core/kernel/p_spec.rb
@@ -76,10 +76,8 @@ describe "Kernel#p" do
-> { p(*[]) }.should output("")
end
-=begin Not sure how to spec this, but wanted to note the behavior here
- it "does not flush if receiver is not a TTY or a File" do
- end
-=end
+ # Not sure how to spec this, but wanted to note the behavior here
+ it "does not flush if receiver is not a TTY or a File"
end
describe "Kernel.p" do
diff --git a/spec/ruby/core/kernel/printf_spec.rb b/spec/ruby/core/kernel/printf_spec.rb
index d8f93ce429..61bf955c25 100644
--- a/spec/ruby/core/kernel/printf_spec.rb
+++ b/spec/ruby/core/kernel/printf_spec.rb
@@ -31,6 +31,13 @@ describe "Kernel.printf" do
object.should_receive(:write).with("string")
Kernel.printf(object, "%s", "string")
end
+
+ it "calls #to_str to convert the format object to a String" do
+ object = mock('format string')
+ object.should_receive(:to_str).and_return("to_str: %i")
+ $stdout.should_receive(:write).with("to_str: 42")
+ Kernel.printf($stdout, object, 42)
+ end
end
describe "Kernel.printf" do
diff --git a/spec/ruby/core/kernel/proc_spec.rb b/spec/ruby/core/kernel/proc_spec.rb
index dfe178420b..6553b8fd04 100644
--- a/spec/ruby/core/kernel/proc_spec.rb
+++ b/spec/ruby/core/kernel/proc_spec.rb
@@ -40,27 +40,9 @@ describe "Kernel#proc" do
proc
end
- ruby_version_is ""..."2.7" do
- it "uses the implicit block from an enclosing method" do
- prc = some_method { "hello" }
-
- prc.call.should == "hello"
- end
- end
-
- ruby_version_is "2.7"..."3.0" do
- it "can be created when called with no block" do
- -> {
- some_method { "hello" }
- }.should complain(/Capturing the given block using Kernel#proc is deprecated/)
- end
- end
-
- ruby_version_is "3.0" do
- it "raises an ArgumentError when passed no block" do
- -> {
- some_method { "hello" }
- }.should raise_error(ArgumentError, 'tried to create Proc object without a block')
- end
+ it "raises an ArgumentError when passed no block" do
+ -> {
+ some_method { "hello" }
+ }.should raise_error(ArgumentError, 'tried to create Proc object without a block')
end
end
diff --git a/spec/ruby/core/kernel/public_send_spec.rb b/spec/ruby/core/kernel/public_send_spec.rb
index 4dae419ff9..b684b1729c 100644
--- a/spec/ruby/core/kernel/public_send_spec.rb
+++ b/spec/ruby/core/kernel/public_send_spec.rb
@@ -105,11 +105,11 @@ describe "Kernel#public_send" do
end
it "includes `public_send` in the backtrace when passed not enough arguments" do
- -> { public_send() }.should raise_error(ArgumentError) { |e| e.backtrace[0].should.include?("`public_send'") }
+ -> { public_send() }.should raise_error(ArgumentError) { |e| e.backtrace[0].should =~ /[`'](?:Kernel#)?public_send'/ }
end
it "includes `public_send` in the backtrace when passed a single incorrect argument" do
- -> { public_send(Object.new) }.should raise_error(TypeError) { |e| e.backtrace[0].should.include?("`public_send'") }
+ -> { public_send(Object.new) }.should raise_error(TypeError) { |e| e.backtrace[0].should =~ /[`'](?:Kernel#)?public_send'/ }
end
it_behaves_like :basicobject_send, :public_send
diff --git a/spec/ruby/core/kernel/remove_instance_variable_spec.rb b/spec/ruby/core/kernel/remove_instance_variable_spec.rb
index e90efc8aed..4e5ba5e018 100644
--- a/spec/ruby/core/kernel/remove_instance_variable_spec.rb
+++ b/spec/ruby/core/kernel/remove_instance_variable_spec.rb
@@ -41,6 +41,19 @@ describe "Kernel#remove_instance_variable" do
end.should raise_error(TypeError)
end
+ it "raises a FrozenError if self is frozen" do
+ o = Object.new
+ o.freeze
+ -> { o.remove_instance_variable(:@foo) }.should raise_error(FrozenError)
+ -> { o.remove_instance_variable(:foo) }.should raise_error(NameError)
+ end
+
+ it "raises for frozen objects" do
+ -> { nil.remove_instance_variable(:@foo) }.should raise_error(FrozenError)
+ -> { nil.remove_instance_variable(:foo) }.should raise_error(NameError)
+ -> { :foo.remove_instance_variable(:@foo) }.should raise_error(FrozenError)
+ end
+
describe "when passed a String" do
it_behaves_like :kernel_remove_instance_variable, nil, "@greeting"
end
diff --git a/spec/ruby/core/kernel/require_relative_spec.rb b/spec/ruby/core/kernel/require_relative_spec.rb
index d4146eb3c8..6188d13a4e 100644
--- a/spec/ruby/core/kernel/require_relative_spec.rb
+++ b/spec/ruby/core/kernel/require_relative_spec.rb
@@ -5,9 +5,9 @@ describe "Kernel#require_relative with a relative path" do
before :each do
CodeLoadingSpecs.spec_setup
@dir = "../../fixtures/code"
- @abs_dir = File.realpath(@dir, File.dirname(__FILE__))
+ @abs_dir = File.realpath(@dir, __dir__)
@path = "#{@dir}/load_fixture.rb"
- @abs_path = File.realpath(@path, File.dirname(__FILE__))
+ @abs_path = File.realpath(@path, __dir__)
end
after :each do
@@ -92,7 +92,7 @@ describe "Kernel#require_relative with a relative path" do
it "raises a LoadError that includes the missing path" do
missing_path = "#{@dir}/nonexistent.rb"
- expanded_missing_path = File.expand_path(missing_path, File.dirname(__FILE__))
+ expanded_missing_path = File.expand_path(missing_path, __dir__)
-> { require_relative(missing_path) }.should raise_error(LoadError) { |e|
e.message.should include(expanded_missing_path)
e.path.should == expanded_missing_path
@@ -207,7 +207,7 @@ describe "Kernel#require_relative with a relative path" do
$LOADED_FEATURES.should include(@abs_path)
end
- platform_is_not :windows do
+ platform_is_not :windows, :wasi do
describe "with symlinks" do
before :each do
@symlink_to_code_dir = tmp("codesymlink")
@@ -277,7 +277,7 @@ end
describe "Kernel#require_relative with an absolute path" do
before :each do
CodeLoadingSpecs.spec_setup
- @dir = File.expand_path "../../fixtures/code", File.dirname(__FILE__)
+ @dir = File.expand_path "../../fixtures/code", __dir__
@abs_dir = @dir
@path = File.join @dir, "load_fixture.rb"
@abs_path = @path
diff --git a/spec/ruby/core/kernel/require_spec.rb b/spec/ruby/core/kernel/require_spec.rb
index dc3da4b7e6..4029e68725 100644
--- a/spec/ruby/core/kernel/require_spec.rb
+++ b/spec/ruby/core/kernel/require_spec.rb
@@ -16,6 +16,26 @@ describe "Kernel#require" do
Kernel.should have_private_instance_method(:require)
end
+ provided = %w[complex enumerator rational thread ruby2_keywords]
+ ruby_version_is "3.1" do
+ provided << "fiber"
+ end
+
+ it "#{provided.join(', ')} are already required" do
+ out = ruby_exe("puts $LOADED_FEATURES", options: '--disable-gems --disable-did-you-mean')
+ features = out.lines.map { |line| File.basename(line.chomp, '.*') }
+
+ # Ignore CRuby internals
+ features -= %w[encdb transdb windows_1252 windows_31j]
+ features.reject! { |feature| feature.end_with?('-fake') }
+
+ features.sort.should == provided.sort
+
+ code = provided.map { |f| "puts require #{f.inspect}\n" }.join
+ required = ruby_exe(code, options: '--disable-gems')
+ required.should == "false\n" * provided.size
+ end
+
it_behaves_like :kernel_require_basic, :require, CodeLoadingSpecs::Method.new
it_behaves_like :kernel_require, :require, CodeLoadingSpecs::Method.new
end
diff --git a/spec/ruby/core/kernel/shared/dup_clone.rb b/spec/ruby/core/kernel/shared/dup_clone.rb
index 84ad49cbde..4fac6006e1 100644
--- a/spec/ruby/core/kernel/shared/dup_clone.rb
+++ b/spec/ruby/core/kernel/shared/dup_clone.rb
@@ -52,18 +52,6 @@ describe :kernel_dup_clone, shared: true do
o2.original.should equal(o)
end
- ruby_version_is ''...'2.7' do
- it "preserves tainted state from the original" do
- o = ObjectSpecDupInitCopy.new
- o2 = o.send(@method)
- o.taint
- o3 = o.send(@method)
-
- o2.should_not.tainted?
- o3.should.tainted?
- end
- end
-
it "does not preserve the object_id" do
o1 = ObjectSpecDupInitCopy.new
old_object_id = o1.object_id
@@ -71,18 +59,6 @@ describe :kernel_dup_clone, shared: true do
o2.object_id.should_not == old_object_id
end
- ruby_version_is ''...'2.7' do
- it "preserves untrusted state from the original" do
- o = ObjectSpecDupInitCopy.new
- o2 = o.send(@method)
- o.untrust
- o3 = o.send(@method)
-
- o2.should_not.untrusted?
- o3.should.untrusted?
- end
- end
-
it "returns nil for NilClass" do
nil.send(@method).should == nil
end
diff --git a/spec/ruby/core/kernel/shared/load.rb b/spec/ruby/core/kernel/shared/load.rb
index 120619abef..0fe2d5ce16 100644
--- a/spec/ruby/core/kernel/shared/load.rb
+++ b/spec/ruby/core/kernel/shared/load.rb
@@ -1,5 +1,6 @@
main = self
+# The big difference is Kernel#load does not attempt to add an extension to the passed path, unlike Kernel#require
describe :kernel_load, shared: true do
before :each do
CodeLoadingSpecs.spec_setup
@@ -10,22 +11,31 @@ describe :kernel_load, shared: true do
CodeLoadingSpecs.spec_cleanup
end
- it "loads a non-extensioned file as a Ruby source file" do
- path = File.expand_path "load_fixture", CODE_LOADING_DIR
- @object.load(path).should be_true
- ScratchPad.recorded.should == [:no_ext]
- end
+ describe "(path resolution)" do
+ # This behavior is specific to Kernel#load, it differs for Kernel#require
+ it "loads a non-extensioned file as a Ruby source file" do
+ path = File.expand_path "load_fixture", CODE_LOADING_DIR
+ @object.load(path).should be_true
+ ScratchPad.recorded.should == [:no_ext]
+ end
- it "loads a non .rb extensioned file as a Ruby source file" do
- path = File.expand_path "load_fixture.ext", CODE_LOADING_DIR
- @object.load(path).should be_true
- ScratchPad.recorded.should == [:no_rb_ext]
- end
+ it "loads a non .rb extensioned file as a Ruby source file" do
+ path = File.expand_path "load_fixture.ext", CODE_LOADING_DIR
+ @object.load(path).should be_true
+ ScratchPad.recorded.should == [:no_rb_ext]
+ end
- it "loads from the current working directory" do
- Dir.chdir CODE_LOADING_DIR do
- @object.load("load_fixture.rb").should be_true
- ScratchPad.recorded.should == [:loaded]
+ it "loads from the current working directory" do
+ Dir.chdir CODE_LOADING_DIR do
+ @object.load("load_fixture.rb").should be_true
+ ScratchPad.recorded.should == [:loaded]
+ end
+ end
+
+ # This behavior is specific to Kernel#load, it differs for Kernel#require
+ it "does not look for a c-extension file when passed a path without extension (when no .rb is present)" do
+ path = File.join CODE_LOADING_DIR, "a", "load_fixture"
+ -> { @object.send(@method, path) }.should raise_error(LoadError)
end
end
@@ -88,12 +98,12 @@ describe :kernel_load, shared: true do
describe "when passed true for 'wrap'" do
it "loads from an existing path" do
- path = File.expand_path "wrap_fixture.rb", CODE_LOADING_DIR
+ path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
@object.load(path, true).should be_true
end
it "sets the enclosing scope to an anonymous module" do
- path = File.expand_path "wrap_fixture.rb", CODE_LOADING_DIR
+ path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
@object.load(path, true)
Object.const_defined?(:LoadSpecWrap).should be_false
@@ -103,14 +113,14 @@ describe :kernel_load, shared: true do
end
it "allows referencing outside namespaces" do
- path = File.expand_path "wrap_fixture.rb", CODE_LOADING_DIR
+ path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
@object.load(path, true)
ScratchPad.recorded[0].should equal(String)
end
it "sets self as a copy of the top-level main" do
- path = File.expand_path "wrap_fixture.rb", CODE_LOADING_DIR
+ path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
@object.load(path, true)
top_level = ScratchPad.recorded[2]
@@ -127,7 +137,7 @@ describe :kernel_load, shared: true do
main_ancestors = main.singleton_class.ancestors[1..-1]
main_ancestors.first.should == mod
- path = File.expand_path "wrap_fixture.rb", CODE_LOADING_DIR
+ path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
@object.load(path, true)
top_level = ScratchPad.recorded[2]
@@ -154,6 +164,41 @@ describe :kernel_load, shared: true do
end
end
+ describe "when passed a module for 'wrap'" do
+ ruby_version_is "3.1" do
+ it "sets the enclosing scope to the supplied module" do
+ path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
+ mod = Module.new
+ @object.load(path, mod)
+
+ Object.const_defined?(:LoadSpecWrap).should be_false
+ mod.const_defined?(:LoadSpecWrap).should be_true
+
+ wrap_module = ScratchPad.recorded[1]
+ wrap_module.should == mod
+ end
+
+ it "makes constants and instance methods in the source file reachable with the supplied module" do
+ path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
+ mod = Module.new
+ @object.load(path, mod)
+
+ mod::LOAD_WRAP_SPECS_TOP_LEVEL_CONSTANT.should == 1
+ obj = Object.new
+ obj.extend(mod)
+ obj.send(:load_wrap_specs_top_level_method).should == :load_wrap_specs_top_level_method
+ end
+
+ it "makes instance methods in the source file private" do
+ path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
+ mod = Module.new
+ @object.load(path, mod)
+
+ mod.private_instance_methods.include?(:load_wrap_specs_top_level_method).should == true
+ end
+ end
+ end
+
describe "(shell expansion)" do
before :each do
@env_home = ENV["HOME"]
diff --git a/spec/ruby/core/kernel/shared/require.rb b/spec/ruby/core/kernel/shared/require.rb
index 9a2c38be1a..250813191b 100644
--- a/spec/ruby/core/kernel/shared/require.rb
+++ b/spec/ruby/core/kernel/shared/require.rb
@@ -212,6 +212,34 @@ end
describe :kernel_require, shared: true do
describe "(path resolution)" do
+ it "loads .rb file when passed absolute path without extension" do
+ path = File.expand_path "load_fixture", CODE_LOADING_DIR
+ @object.send(@method, path).should be_true
+ # This should _not_ be [:no_ext]
+ ScratchPad.recorded.should == [:loaded]
+ end
+
+ platform_is :linux, :darwin do
+ it "loads c-extension file when passed absolute path without extension when no .rb is present" do
+ # the error message is specific to what dlerror() returns
+ path = File.join CODE_LOADING_DIR, "a", "load_fixture"
+ -> { @object.send(@method, path) }.should raise_error(Exception, /file too short|not a mach-o file/)
+ end
+ end
+
+ platform_is :darwin do
+ it "loads .bundle file when passed absolute path with .so" do
+ # the error message is specific to what dlerror() returns
+ path = File.join CODE_LOADING_DIR, "a", "load_fixture.so"
+ -> { @object.send(@method, path) }.should raise_error(Exception, /load_fixture\.bundle.+(file too short|not a mach-o file)/)
+ end
+ end
+
+ it "does not try an extra .rb if the path already ends in .rb" do
+ path = File.join CODE_LOADING_DIR, "d", "load_fixture.rb"
+ -> { @object.send(@method, path) }.should raise_error(LoadError)
+ end
+
# For reference see [ruby-core:24155] in which matz confirms this feature is
# intentional for security reasons.
it "does not load a bare filename unless the current working directory is in $LOAD_PATH" do
@@ -237,6 +265,17 @@ describe :kernel_require, shared: true do
}.should complain(/circular require considered harmful/, verbose: true)
ScratchPad.recorded.should == [:loaded]
end
+
+ ruby_bug "#17340", ''...'3.3' do
+ it "loads a file concurrently" do
+ path = File.expand_path "concurrent_require_fixture.rb", CODE_LOADING_DIR
+ ScratchPad.record(@object)
+ -> {
+ @object.require(path)
+ }.should_not complain(/circular require considered harmful/, verbose: true)
+ ScratchPad.recorded.join
+ end
+ end
end
describe "(non-extensioned path)" do
@@ -251,13 +290,11 @@ describe :kernel_require, shared: true do
ScratchPad.recorded.should == [:loaded]
end
- ruby_bug "#16926", "2.7"..."3.0" do
- it "does not load a feature twice when $LOAD_PATH has been modified" do
- $LOAD_PATH.replace [CODE_LOADING_DIR]
- @object.require("load_fixture").should be_true
- $LOAD_PATH.replace [File.expand_path("b", CODE_LOADING_DIR), CODE_LOADING_DIR]
- @object.require("load_fixture").should be_false
- end
+ it "does not load a feature twice when $LOAD_PATH has been modified" do
+ $LOAD_PATH.replace [CODE_LOADING_DIR]
+ @object.require("load_fixture").should be_true
+ $LOAD_PATH.replace [File.expand_path("b", CODE_LOADING_DIR), CODE_LOADING_DIR]
+ @object.require("load_fixture").should be_false
end
end
@@ -546,22 +583,6 @@ describe :kernel_require, shared: true do
ScratchPad.recorded.should == []
end
- provided = %w[complex enumerator rational thread]
- ruby_version_is "2.7" do
- provided << 'ruby2_keywords'
- end
-
- it "#{provided.join(', ')} are already required" do
- features = ruby_exe("puts $LOADED_FEATURES", options: '--disable-gems')
- provided.each { |feature|
- features.should =~ /\b#{feature}\.(rb|so|jar)$/
- }
-
- code = provided.map { |f| "puts require #{f.inspect}\n" }.join
- required = ruby_exe(code, options: '--disable-gems')
- required.should == "false\n" * provided.size
- end
-
it "unicode_normalize is part of core and not $LOADED_FEATURES" do
features = ruby_exe("puts $LOADED_FEATURES", options: '--disable-gems')
features.lines.each { |feature|
@@ -570,6 +591,23 @@ describe :kernel_require, shared: true do
-> { @object.require("unicode_normalize") }.should raise_error(LoadError)
end
+
+ it "does not load a file earlier on the $LOAD_PATH when other similar features were already loaded" do
+ Dir.chdir CODE_LOADING_DIR do
+ @object.send(@method, "../code/load_fixture").should be_true
+ end
+ ScratchPad.recorded.should == [:loaded]
+
+ $LOAD_PATH.unshift "#{CODE_LOADING_DIR}/b"
+ # This loads because the above load was not on the $LOAD_PATH
+ @object.send(@method, "load_fixture").should be_true
+ ScratchPad.recorded.should == [:loaded, :loaded]
+
+ $LOAD_PATH.unshift "#{CODE_LOADING_DIR}/c"
+ # This does not load because the above load was on the $LOAD_PATH
+ @object.send(@method, "load_fixture").should be_false
+ ScratchPad.recorded.should == [:loaded, :loaded]
+ end
end
describe "(shell expansion)" do
diff --git a/spec/ruby/core/kernel/shared/sprintf.rb b/spec/ruby/core/kernel/shared/sprintf.rb
index 84d472b0d1..13dc6e97f0 100644
--- a/spec/ruby/core/kernel/shared/sprintf.rb
+++ b/spec/ruby/core/kernel/shared/sprintf.rb
@@ -289,21 +289,80 @@ describe :kernel_sprintf, shared: true do
@method.call("%c", "a").should == "a"
end
- it "raises ArgumentError if argument is a string of several characters" do
+ ruby_version_is ""..."3.2" do
+ it "raises ArgumentError if argument is a string of several characters" do
+ -> {
+ @method.call("%c", "abc")
+ }.should raise_error(ArgumentError, /%c requires a character/)
+ end
+
+ it "raises ArgumentError if argument is an empty string" do
+ -> {
+ @method.call("%c", "")
+ }.should raise_error(ArgumentError, /%c requires a character/)
+ end
+ end
+
+ ruby_version_is "3.2" do
+ it "displays only the first character if argument is a string of several characters" do
+ @method.call("%c", "abc").should == "a"
+ end
+
+ it "displays no characters if argument is an empty string" do
+ @method.call("%c", "").should == ""
+ end
+ end
+
+ it "raises TypeError if argument is not String or Integer and cannot be converted to them" do
-> {
- @method.call("%c", "abc")
- }.should raise_error(ArgumentError)
+ @method.call("%c", [])
+ }.should raise_error(TypeError, /no implicit conversion of Array into Integer/)
end
- it "raises ArgumentError if argument is an empty string" do
+ it "raises TypeError if argument is nil" do
-> {
- @method.call("%c", "")
- }.should raise_error(ArgumentError)
+ @method.call("%c", nil)
+ }.should raise_error(TypeError, /no implicit conversion from nil to integer/)
+ end
+
+ it "tries to convert argument to String with to_str" do
+ obj = BasicObject.new
+ def obj.to_str
+ "a"
+ end
+
+ @method.call("%c", obj).should == "a"
end
- it "supports Unicode characters" do
- @method.call("%c", 1286).should == "Ԇ"
- @method.call("%c", "ش").should == "ش"
+ it "tries to convert argument to Integer with to_int" do
+ obj = BasicObject.new
+ def obj.to_int
+ 90
+ end
+
+ @method.call("%c", obj).should == "Z"
+ end
+
+ it "raises TypeError if converting to String with to_str returns non-String" do
+ obj = BasicObject.new
+ def obj.to_str
+ :foo
+ end
+
+ -> {
+ @method.call("%c", obj)
+ }.should raise_error(TypeError, /can't convert BasicObject to String/)
+ end
+
+ it "raises TypeError if converting to Integer with to_int returns non-Integer" do
+ obj = BasicObject.new
+ def obj.to_int
+ :foo
+ end
+
+ -> {
+ @method.call("%c", obj)
+ }.should raise_error(TypeError, /can't convert BasicObject to Integer/)
end
end
@@ -362,11 +421,11 @@ describe :kernel_sprintf, shared: true do
@method.call("%4.6s", "abcdefg").should == "abcdef"
end
- it "formats nli with width" do
+ it "formats nil with width" do
@method.call("%6s", nil).should == " "
end
- it "formats nli with precision" do
+ it "formats nil with precision" do
@method.call("%.6s", nil).should == ""
end
@@ -927,4 +986,8 @@ describe :kernel_sprintf, shared: true do
}
end
end
+
+ it "does not raise error when passed more arguments than needed" do
+ sprintf("%s %d %c", "string", 2, "c", []).should == "string 2 c"
+ end
end
diff --git a/spec/ruby/core/kernel/shared/sprintf_encoding.rb b/spec/ruby/core/kernel/shared/sprintf_encoding.rb
index 5ca66b9083..7ec0fe4c48 100644
--- a/spec/ruby/core/kernel/shared/sprintf_encoding.rb
+++ b/spec/ruby/core/kernel/shared/sprintf_encoding.rb
@@ -1,3 +1,5 @@
+# Keep encoding-related specs in a separate shared example to be able to skip them in IO/File/StringIO specs.
+# It's difficult to check result's encoding in the test after writing to a file/io buffer.
describe :kernel_sprintf_encoding, shared: true do
it "can produce a string with valid encoding" do
string = @method.call("good day %{valid}", valid: "e")
@@ -12,20 +14,20 @@ describe :kernel_sprintf_encoding, shared: true do
end
it "returns a String in the same encoding as the format String if compatible" do
- string = "%s".force_encoding(Encoding::KOI8_U)
+ string = "%s".dup.force_encoding(Encoding::KOI8_U)
result = @method.call(string, "dogs")
result.encoding.should equal(Encoding::KOI8_U)
end
it "returns a String in the argument's encoding if format encoding is more restrictive" do
- string = "foo %s".force_encoding(Encoding::US_ASCII)
- argument = "b\303\274r".force_encoding(Encoding::UTF_8)
+ string = "foo %s".dup.force_encoding(Encoding::US_ASCII)
+ argument = "b\303\274r".dup.force_encoding(Encoding::UTF_8)
result = @method.call(string, argument)
result.encoding.should equal(Encoding::UTF_8)
end
- it "raises Encoding::CompatibilityError if both encodings are ASCII compatible and there ano not ASCII characters" do
+ it "raises Encoding::CompatibilityError if both encodings are ASCII compatible and there are not ASCII characters" do
string = "Ä %s".encode('windows-1252')
argument = "Ђ".encode('windows-1251')
@@ -33,4 +35,33 @@ describe :kernel_sprintf_encoding, shared: true do
@method.call(string, argument)
}.should raise_error(Encoding::CompatibilityError)
end
+
+ describe "%c" do
+ it "supports Unicode characters" do
+ result = @method.call("%c", 1286)
+ result.should == "Ԇ"
+ result.bytes.should == [212, 134]
+
+ result = @method.call("%c", "ش")
+ result.should == "ش"
+ result.bytes.should == [216, 180]
+ end
+
+ it "raises error when a codepoint isn't representable in an encoding of a format string" do
+ format = "%c".encode("ASCII")
+
+ -> {
+ @method.call(format, 1286)
+ }.should raise_error(RangeError, /out of char range/)
+ end
+
+ it "uses the encoding of the format string to interpret codepoints" do
+ format = "%c".dup.force_encoding("euc-jp")
+ result = @method.call(format, 9415601)
+
+ result.encoding.should == Encoding::EUC_JP
+ result.should == "é".encode(Encoding::EUC_JP)
+ result.bytes.should == [143, 171, 177]
+ end
+ end
end
diff --git a/spec/ruby/core/kernel/singleton_class_spec.rb b/spec/ruby/core/kernel/singleton_class_spec.rb
index a8bcd916d1..23c400f9bd 100644
--- a/spec/ruby/core/kernel/singleton_class_spec.rb
+++ b/spec/ruby/core/kernel/singleton_class_spec.rb
@@ -1,3 +1,6 @@
+# truffleruby_primitives: true
+require_relative '../../spec_helper'
+
describe "Kernel#singleton_class" do
it "returns class extended from an object" do
x = Object.new
@@ -18,10 +21,54 @@ describe "Kernel#singleton_class" do
end
it "raises TypeError for Integer" do
- -> { 123.singleton_class }.should raise_error(TypeError)
+ -> { 123.singleton_class }.should raise_error(TypeError, "can't define singleton")
+ end
+
+ it "raises TypeError for Float" do
+ -> { 3.14.singleton_class }.should raise_error(TypeError, "can't define singleton")
end
it "raises TypeError for Symbol" do
- -> { :foo.singleton_class }.should raise_error(TypeError)
+ -> { :foo.singleton_class }.should raise_error(TypeError, "can't define singleton")
+ end
+
+ it "raises TypeError for a frozen deduplicated String" do
+ -> { (-"string").singleton_class }.should raise_error(TypeError, "can't define singleton")
+ -> { a = -"string"; a.singleton_class }.should raise_error(TypeError, "can't define singleton")
+ -> { a = "string"; (-a).singleton_class }.should raise_error(TypeError, "can't define singleton")
+ end
+
+ it "returns a frozen singleton class if object is frozen" do
+ obj = Object.new
+ obj.freeze
+ obj.singleton_class.frozen?.should be_true
+ end
+
+ context "for an IO object with a replaced singleton class" do
+ it "looks up singleton methods from the fresh singleton class after an object instance got a new one" do
+ proxy = -> io { io.foo }
+ if RUBY_ENGINE == 'truffleruby'
+ # We need an inline cache with only this object seen, the best way to do that is to use a Primitive
+ sclass = -> io { Primitive.singleton_class(io) }
+ else
+ sclass = -> io { io.singleton_class }
+ end
+
+ io = File.new(__FILE__)
+ io.define_singleton_method(:foo) { "old" }
+ sclass1 = sclass.call(io)
+ proxy.call(io).should == "old"
+
+ # IO#reopen is the only method which can replace an object's singleton class
+ io2 = File.new(__FILE__)
+ io.reopen(io2)
+ io.define_singleton_method(:foo) { "new" }
+ sclass2 = sclass.call(io)
+ sclass2.should_not.equal?(sclass1)
+ proxy.call(io).should == "new"
+ ensure
+ io2.close
+ io.close
+ end
end
end
diff --git a/spec/ruby/core/kernel/sleep_spec.rb b/spec/ruby/core/kernel/sleep_spec.rb
index 32da6344c1..0570629723 100644
--- a/spec/ruby/core/kernel/sleep_spec.rb
+++ b/spec/ruby/core/kernel/sleep_spec.rb
@@ -1,5 +1,4 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
describe "Kernel#sleep" do
it "is a private method" do
@@ -33,10 +32,6 @@ describe "Kernel#sleep" do
-> { sleep(-1) }.should raise_error(ArgumentError)
end
- it "raises a TypeError when passed nil" do
- -> { sleep(nil) }.should raise_error(TypeError)
- end
-
it "raises a TypeError when passed a String" do
-> { sleep('2') }.should raise_error(TypeError)
end
@@ -55,6 +50,29 @@ describe "Kernel#sleep" do
t.wakeup
t.value.should == 5
end
+
+ ruby_version_is ""..."3.3" do
+ it "raises a TypeError when passed nil" do
+ -> { sleep(nil) }.should raise_error(TypeError)
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "accepts a nil duration" do
+ running = false
+ t = Thread.new do
+ running = true
+ sleep(nil)
+ 5
+ end
+
+ Thread.pass until running
+ Thread.pass while t.status and t.status != "sleep"
+
+ t.wakeup
+ t.value.should == 5
+ end
+ end
end
describe "Kernel.sleep" do
diff --git a/spec/ruby/core/kernel/sprintf_spec.rb b/spec/ruby/core/kernel/sprintf_spec.rb
index 7adf71be76..9ef7f86f16 100644
--- a/spec/ruby/core/kernel/sprintf_spec.rb
+++ b/spec/ruby/core/kernel/sprintf_spec.rb
@@ -3,6 +3,14 @@ require_relative 'fixtures/classes'
require_relative 'shared/sprintf'
require_relative 'shared/sprintf_encoding'
+describe :kernel_sprintf_to_str, shared: true do
+ it "calls #to_str to convert the format object to a String" do
+ obj = mock('format string')
+ obj.should_receive(:to_str).and_return("to_str: %i")
+ @method.call(obj, 42).should == "to_str: 42"
+ end
+end
+
describe "Kernel#sprintf" do
it_behaves_like :kernel_sprintf, -> format, *args {
sprintf(format, *args)
@@ -11,6 +19,10 @@ describe "Kernel#sprintf" do
it_behaves_like :kernel_sprintf_encoding, -> format, *args {
sprintf(format, *args)
}
+
+ it_behaves_like :kernel_sprintf_to_str, -> format, *args {
+ sprintf(format, *args)
+ }
end
describe "Kernel.sprintf" do
@@ -21,4 +33,8 @@ describe "Kernel.sprintf" do
it_behaves_like :kernel_sprintf_encoding, -> format, *args {
Kernel.sprintf(format, *args)
}
+
+ it_behaves_like :kernel_sprintf_to_str, -> format, *args {
+ Kernel.sprintf(format, *args)
+ }
end
diff --git a/spec/ruby/core/kernel/system_spec.rb b/spec/ruby/core/kernel/system_spec.rb
index 9671a650cc..9bc03924dd 100644
--- a/spec/ruby/core/kernel/system_spec.rb
+++ b/spec/ruby/core/kernel/system_spec.rb
@@ -64,6 +64,23 @@ describe :kernel_system, shared: true do
end
end
+ platform_is_not :windows do
+ before :each do
+ require 'tmpdir'
+ @shell_command = File.join(Dir.mktmpdir, "noshebang.cmd")
+ File.write(@shell_command, %[echo "$PATH"\n], perm: 0o700)
+ end
+
+ after :each do
+ File.unlink(@shell_command)
+ Dir.rmdir(File.dirname(@shell_command))
+ end
+
+ it "executes with `sh` if the command is executable but not binary and there is no shebang" do
+ -> { @object.system(@shell_command) }.should output_to_fd(ENV['PATH'] + "\n")
+ end
+ end
+
before :each do
ENV['TEST_SH_EXPANSION'] = 'foo'
@shell_var = '$TEST_SH_EXPANSION'
diff --git a/spec/ruby/core/kernel/taint_spec.rb b/spec/ruby/core/kernel/taint_spec.rb
index 8ba9869af2..0c16b1dbbf 100644
--- a/spec/ruby/core/kernel/taint_spec.rb
+++ b/spec/ruby/core/kernel/taint_spec.rb
@@ -2,54 +2,13 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Kernel#taint" do
- ruby_version_is ''...'2.7' do
- it "returns self" do
- o = Object.new
- o.taint.should equal(o)
- end
-
- it "sets the tainted bit" do
- o = Object.new
- o.taint
- o.should.tainted?
- end
-
- it "raises FrozenError on an untainted, frozen object" do
- o = Object.new.freeze
- -> { o.taint }.should raise_error(FrozenError)
- end
-
- it "does not raise an error on a tainted, frozen object" do
- o = Object.new.taint.freeze
- o.taint.should equal(o)
- end
-
- it "has no effect on immediate values" do
- [nil, true, false].each do |v|
- v.taint
- v.should_not.tainted?
- end
- end
-
- it "no raises a RuntimeError on symbols" do
- v = :sym
- -> { v.taint }.should_not raise_error(RuntimeError)
- v.should_not.tainted?
- end
-
- it "no raises error on integer values" do
- [1].each do |v|
- -> { v.taint }.should_not raise_error(RuntimeError)
- v.should_not.tainted?
- end
- end
- end
-
- ruby_version_is "2.7"..."3.0" do
+ ruby_version_is ""..."3.2" do
it "is a no-op" do
- o = Object.new
- o.taint
- o.should_not.tainted?
+ suppress_warning do
+ o = Object.new
+ o.taint
+ o.should_not.tainted?
+ end
end
it "warns in verbose mode" do
@@ -59,4 +18,10 @@ describe "Kernel#taint" do
}.should complain(/Object#taint is deprecated and will be removed in Ruby 3.2/, verbose: true)
end
end
+
+ ruby_version_is "3.2" do
+ it "has been removed" do
+ Object.new.should_not.respond_to?(:taint)
+ end
+ end
end
diff --git a/spec/ruby/core/kernel/tainted_spec.rb b/spec/ruby/core/kernel/tainted_spec.rb
index 022938bfc1..fcae433069 100644
--- a/spec/ruby/core/kernel/tainted_spec.rb
+++ b/spec/ruby/core/kernel/tainted_spec.rb
@@ -2,23 +2,15 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Kernel#tainted?" do
- ruby_version_is ''...'2.7' do
- it "returns true if Object is tainted" do
- o = mock('o')
- p = mock('p')
- p.taint
- o.should_not.tainted?
- p.should.tainted?
- end
- end
-
- ruby_version_is "2.7"..."3.0" do
+ ruby_version_is ""..."3.2" do
it "is a no-op" do
- o = mock('o')
- p = mock('p')
- p.taint
- o.should_not.tainted?
- p.should_not.tainted?
+ 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
@@ -28,4 +20,10 @@ describe "Kernel#tainted?" do
}.should complain(/Object#tainted\? is deprecated and will be removed in Ruby 3.2/, verbose: true)
end
end
+
+ ruby_version_is "3.2" do
+ it "has been removed" do
+ Object.new.should_not.respond_to?(:tainted?)
+ end
+ end
end
diff --git a/spec/ruby/core/kernel/test_spec.rb b/spec/ruby/core/kernel/test_spec.rb
index abb365aed2..d26dc06361 100644
--- a/spec/ruby/core/kernel/test_spec.rb
+++ b/spec/ruby/core/kernel/test_spec.rb
@@ -3,8 +3,8 @@ require_relative 'fixtures/classes'
describe "Kernel#test" do
before :all do
- @file = File.dirname(__FILE__) + '/fixtures/classes.rb'
- @dir = File.dirname(__FILE__) + '/fixtures'
+ @file = __dir__ + '/fixtures/classes.rb'
+ @dir = __dir__ + '/fixtures'
end
it "is a private method" do
diff --git a/spec/ruby/core/kernel/to_s_spec.rb b/spec/ruby/core/kernel/to_s_spec.rb
index 64b40f46e5..ea4b00151e 100644
--- a/spec/ruby/core/kernel/to_s_spec.rb
+++ b/spec/ruby/core/kernel/to_s_spec.rb
@@ -5,14 +5,4 @@ describe "Kernel#to_s" do
it "returns a String containing the name of self's class" do
Object.new.to_s.should =~ /Object/
end
-
- ruby_version_is ''...'2.7' do
- it "returns a tainted result if self is tainted" do
- Object.new.taint.to_s.tainted?.should be_true
- end
-
- it "returns an untrusted result if self is untrusted" do
- Object.new.untrust.to_s.untrusted?.should be_true
- end
- end
end
diff --git a/spec/ruby/core/kernel/trust_spec.rb b/spec/ruby/core/kernel/trust_spec.rb
index 399983f74d..db6f17e0fb 100644
--- a/spec/ruby/core/kernel/trust_spec.rb
+++ b/spec/ruby/core/kernel/trust_spec.rb
@@ -2,35 +2,14 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Kernel#trust" do
- ruby_version_is ''...'2.7' do
- it "returns self" do
- o = Object.new
- o.trust.should equal(o)
- end
-
- it "clears the untrusted bit" do
- o = Object.new.untrust
- o.trust
- o.should_not.untrusted?
- end
-
- it "raises FrozenError on an untrusted, frozen object" do
- o = Object.new.untrust.freeze
- -> { o.trust }.should raise_error(FrozenError)
- end
-
- it "does not raise an error on a trusted, frozen object" do
- o = Object.new.freeze
- o.trust.should equal(o)
- end
- end
-
- ruby_version_is "2.7"..."3.0" do
+ ruby_version_is ""..."3.2" do
it "is a no-op" do
- o = Object.new.untrust
- o.should_not.untrusted?
- o.trust
- o.should_not.untrusted?
+ 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
@@ -40,4 +19,10 @@ describe "Kernel#trust" do
}.should complain(/Object#trust is deprecated and will be removed in Ruby 3.2/, verbose: true)
end
end
+
+ ruby_version_is "3.2" do
+ it "has been removed" do
+ Object.new.should_not.respond_to?(:trust)
+ end
+ end
end
diff --git a/spec/ruby/core/kernel/untaint_spec.rb b/spec/ruby/core/kernel/untaint_spec.rb
index 44d87da5d5..26b2aabbe9 100644
--- a/spec/ruby/core/kernel/untaint_spec.rb
+++ b/spec/ruby/core/kernel/untaint_spec.rb
@@ -2,35 +2,14 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Kernel#untaint" do
- ruby_version_is ''...'2.7' do
- it "returns self" do
- o = Object.new
- o.untaint.should equal(o)
- end
-
- it "clears the tainted bit" do
- o = Object.new.taint
- o.untaint
- o.should_not.tainted?
- end
-
- it "raises FrozenError on a tainted, frozen object" do
- o = Object.new.taint.freeze
- -> { o.untaint }.should raise_error(FrozenError)
- end
-
- it "does not raise an error on an untainted, frozen object" do
- o = Object.new.freeze
- o.untaint.should equal(o)
- end
- end
-
- ruby_version_is "2.7"..."3.0" do
+ ruby_version_is ""..."3.2" do
it "is a no-op" do
- o = Object.new.taint
- o.should_not.tainted?
- o.untaint
- o.should_not.tainted?
+ 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
@@ -40,4 +19,10 @@ describe "Kernel#untaint" do
}.should complain(/Object#untaint is deprecated and will be removed in Ruby 3.2/, verbose: true)
end
end
+
+ ruby_version_is "3.2" do
+ it "has been removed" do
+ Object.new.should_not.respond_to?(:untaint)
+ end
+ end
end
diff --git a/spec/ruby/core/kernel/untrust_spec.rb b/spec/ruby/core/kernel/untrust_spec.rb
index aff0fec57b..5310cd8eb4 100644
--- a/spec/ruby/core/kernel/untrust_spec.rb
+++ b/spec/ruby/core/kernel/untrust_spec.rb
@@ -2,34 +2,13 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Kernel#untrust" do
- ruby_version_is ''...'2.7' do
- it "returns self" do
- o = Object.new
- o.untrust.should equal(o)
- end
-
- it "sets the untrusted bit" do
- o = Object.new
- o.untrust
- o.should.untrusted?
- end
-
- it "raises FrozenError on a trusted, frozen object" do
- o = Object.new.freeze
- -> { o.untrust }.should raise_error(FrozenError)
- end
-
- it "does not raise an error on an untrusted, frozen object" do
- o = Object.new.untrust.freeze
- o.untrust.should equal(o)
- end
- end
-
- ruby_version_is "2.7"..."3.0" do
+ ruby_version_is ""..."3.2" do
it "is a no-op" do
- o = Object.new
- o.untrust
- o.should_not.untrusted?
+ suppress_warning do
+ o = Object.new
+ o.untrust
+ o.should_not.untrusted?
+ end
end
it "warns in verbose mode" do
@@ -39,4 +18,10 @@ describe "Kernel#untrust" do
}.should complain(/Object#untrust is deprecated and will be removed in Ruby 3.2/, verbose: true)
end
end
+
+ ruby_version_is "3.2" do
+ it "has been removed" do
+ Object.new.should_not.respond_to?(:untrust)
+ end
+ end
end
diff --git a/spec/ruby/core/kernel/untrusted_spec.rb b/spec/ruby/core/kernel/untrusted_spec.rb
index 5347c90093..ea36d6c98c 100644
--- a/spec/ruby/core/kernel/untrusted_spec.rb
+++ b/spec/ruby/core/kernel/untrusted_spec.rb
@@ -2,38 +2,14 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Kernel#untrusted?" do
- ruby_version_is ''...'2.7' do
- it "returns the untrusted status of an object" do
- o = mock('o')
- o.should_not.untrusted?
- o.untrust
- o.should.untrusted?
- end
-
- it "has no effect on immediate values" do
- a = nil
- b = true
- c = false
- a.untrust
- b.untrust
- c.untrust
- a.should_not.untrusted?
- b.should_not.untrusted?
- c.should_not.untrusted?
- end
-
- it "has effect on immediate values" do
- d = 1
- -> { d.untrust }.should_not raise_error(RuntimeError)
- end
- end
-
- ruby_version_is "2.7"..."3.0" do
+ ruby_version_is ""..."3.2" do
it "is a no-op" do
- o = mock('o')
- o.should_not.untrusted?
- o.untrust
- o.should_not.untrusted?
+ suppress_warning do
+ o = mock('o')
+ o.should_not.untrusted?
+ o.untrust
+ o.should_not.untrusted?
+ end
end
it "warns in verbose mode" do
@@ -43,4 +19,10 @@ describe "Kernel#untrusted?" do
}.should complain(/Object#untrusted\? is deprecated and will be removed in Ruby 3.2/, verbose: true)
end
end
+
+ ruby_version_is "3.2" do
+ it "has been removed" do
+ Object.new.should_not.respond_to?(:untrusted?)
+ end
+ end
end
diff --git a/spec/ruby/core/kernel/warn_spec.rb b/spec/ruby/core/kernel/warn_spec.rb
index 7df6fa72d1..00164ad90b 100644
--- a/spec/ruby/core/kernel/warn_spec.rb
+++ b/spec/ruby/core/kernel/warn_spec.rb
@@ -128,36 +128,34 @@ describe "Kernel#warn" do
end
end
- ruby_version_is "3.0" do
- it "accepts :category keyword with a symbol" do
- -> {
- $VERBOSE = true
- warn("message", category: :deprecated)
- }.should output(nil, "message\n")
- end
+ it "accepts :category keyword with a symbol" do
+ -> {
+ $VERBOSE = true
+ warn("message", category: :deprecated)
+ }.should output(nil, "message\n")
+ end
- it "accepts :category keyword with nil" do
- -> {
- $VERBOSE = true
- warn("message", category: nil)
- }.should output(nil, "message\n")
- end
+ it "accepts :category keyword with nil" do
+ -> {
+ $VERBOSE = true
+ warn("message", category: nil)
+ }.should output(nil, "message\n")
+ end
- it "accepts :category keyword with object convertible to symbol" do
- o = Object.new
- def o.to_sym; :deprecated; end
- -> {
- $VERBOSE = true
- warn("message", category: o)
- }.should output(nil, "message\n")
- end
+ it "accepts :category keyword with object convertible to symbol" do
+ o = Object.new
+ def o.to_sym; :deprecated; end
+ -> {
+ $VERBOSE = true
+ warn("message", category: o)
+ }.should output(nil, "message\n")
+ end
- it "raises if :category keyword is not nil and not convertible to symbol" do
- -> {
- $VERBOSE = true
- warn("message", category: Object.new)
- }.should raise_error(TypeError)
- end
+ it "raises if :category keyword is not nil and not convertible to symbol" do
+ -> {
+ $VERBOSE = true
+ warn("message", category: Object.new)
+ }.should raise_error(TypeError)
end
it "converts first arg using to_s" do
@@ -212,67 +210,52 @@ describe "Kernel#warn" do
-> { warn('foo', **h) }.should complain("foo\n")
end
- ruby_version_is '3.0' do
- it "calls Warning.warn without keyword arguments if Warning.warn does not accept keyword arguments" do
- verbose = $VERBOSE
- $VERBOSE = false
- class << Warning
- alias_method :_warn, :warn
- def warn(message)
- ScratchPad.record(message)
- end
- end
-
- begin
- ScratchPad.clear
- Kernel.warn("Chunky bacon!")
- ScratchPad.recorded.should == "Chunky bacon!\n"
-
- Kernel.warn("Deprecated bacon!", category: :deprecated)
- ScratchPad.recorded.should == "Deprecated bacon!\n"
- ensure
- class << Warning
- remove_method :warn
- alias_method :warn, :_warn
- remove_method :_warn
- end
- $VERBOSE = verbose
+ it "calls Warning.warn without keyword arguments if Warning.warn does not accept keyword arguments" do
+ verbose = $VERBOSE
+ $VERBOSE = false
+ class << Warning
+ alias_method :_warn, :warn
+ def warn(message)
+ ScratchPad.record(message)
end
end
- it "calls Warning.warn with category: nil if Warning.warn accepts keyword arguments" do
- Warning.should_receive(:warn).with("Chunky bacon!\n", category: nil)
- verbose = $VERBOSE
- $VERBOSE = false
- begin
- Kernel.warn("Chunky bacon!")
- ensure
- $VERBOSE = verbose
+ begin
+ ScratchPad.clear
+ Kernel.warn("Chunky bacon!")
+ ScratchPad.recorded.should == "Chunky bacon!\n"
+
+ Kernel.warn("Deprecated bacon!", category: :deprecated)
+ ScratchPad.recorded.should == "Deprecated bacon!\n"
+ ensure
+ class << Warning
+ remove_method :warn
+ alias_method :warn, :_warn
+ remove_method :_warn
end
+ $VERBOSE = verbose
end
+ end
- it "calls Warning.warn with given category keyword converted to a symbol" do
- Warning.should_receive(:warn).with("Chunky bacon!\n", category: :deprecated)
- verbose = $VERBOSE
- $VERBOSE = false
- begin
- Kernel.warn("Chunky bacon!", category: 'deprecated')
- ensure
- $VERBOSE = verbose
- end
+ it "calls Warning.warn with category: nil if Warning.warn accepts keyword arguments" do
+ Warning.should_receive(:warn).with("Chunky bacon!\n", category: nil)
+ verbose = $VERBOSE
+ $VERBOSE = false
+ begin
+ Kernel.warn("Chunky bacon!")
+ ensure
+ $VERBOSE = verbose
end
end
- ruby_version_is ''...'3.0' do
- it "calls Warning.warn with no keyword arguments" do
- Warning.should_receive(:warn).with("Chunky bacon!\n")
- verbose = $VERBOSE
- $VERBOSE = false
- begin
- Kernel.warn("Chunky bacon!")
- ensure
- $VERBOSE = verbose
- end
+ it "calls Warning.warn with given category keyword converted to a symbol" do
+ Warning.should_receive(:warn).with("Chunky bacon!\n", category: :deprecated)
+ verbose = $VERBOSE
+ $VERBOSE = false
+ begin
+ Kernel.warn("Chunky bacon!", category: 'deprecated')
+ ensure
+ $VERBOSE = verbose
end
end
diff --git a/spec/ruby/core/main/fixtures/using.rb b/spec/ruby/core/main/fixtures/using.rb
new file mode 100644
index 0000000000..30713ef309
--- /dev/null
+++ b/spec/ruby/core/main/fixtures/using.rb
@@ -0,0 +1 @@
+using Module.new
diff --git a/spec/ruby/core/main/fixtures/using_in_main.rb b/spec/ruby/core/main/fixtures/using_in_main.rb
new file mode 100644
index 0000000000..a4a71c89cc
--- /dev/null
+++ b/spec/ruby/core/main/fixtures/using_in_main.rb
@@ -0,0 +1,5 @@
+MAIN = self
+
+module X
+ MAIN.send(:using, Module.new)
+end
diff --git a/spec/ruby/core/main/fixtures/using_in_method.rb b/spec/ruby/core/main/fixtures/using_in_method.rb
new file mode 100644
index 0000000000..d9ea2e9ef0
--- /dev/null
+++ b/spec/ruby/core/main/fixtures/using_in_method.rb
@@ -0,0 +1,5 @@
+def foo
+ using Module.new
+end
+
+foo
diff --git a/spec/ruby/core/main/private_spec.rb b/spec/ruby/core/main/private_spec.rb
index cac0645b40..e8c1f3f44c 100644
--- a/spec/ruby/core/main/private_spec.rb
+++ b/spec/ruby/core/main/private_spec.rb
@@ -22,13 +22,11 @@ describe "main#private" do
end
end
- ruby_version_is "3.0" do
- context "when single argument is passed and is an array" do
- it "sets the visibility of the given methods to private" do
- eval "private [:main_public_method, :main_public_method2]", TOPLEVEL_BINDING
- Object.should have_private_method(:main_public_method)
- Object.should have_private_method(:main_public_method2)
- end
+ context "when single argument is passed and is an array" do
+ it "sets the visibility of the given methods to private" do
+ eval "private [:main_public_method, :main_public_method2]", TOPLEVEL_BINDING
+ Object.should have_private_method(:main_public_method)
+ Object.should have_private_method(:main_public_method2)
end
end
diff --git a/spec/ruby/core/main/public_spec.rb b/spec/ruby/core/main/public_spec.rb
index 91f045dbab..31baad4583 100644
--- a/spec/ruby/core/main/public_spec.rb
+++ b/spec/ruby/core/main/public_spec.rb
@@ -22,13 +22,11 @@ describe "main#public" do
end
end
- ruby_version_is "3.0" do
- context "when single argument is passed and is an array" do
- it "sets the visibility of the given methods to public" do
- eval "public [:main_private_method, :main_private_method2]", TOPLEVEL_BINDING
- Object.should_not have_private_method(:main_private_method)
- Object.should_not have_private_method(:main_private_method2)
- end
+ context "when single argument is passed and is an array" do
+ it "sets the visibility of the given methods to public" do
+ eval "public [:main_private_method, :main_private_method2]", TOPLEVEL_BINDING
+ Object.should_not have_private_method(:main_private_method)
+ Object.should_not have_private_method(:main_private_method2)
end
end
diff --git a/spec/ruby/core/main/ruby2_keywords_spec.rb b/spec/ruby/core/main/ruby2_keywords_spec.rb
index 0999cddeed..27ceae3253 100644
--- a/spec/ruby/core/main/ruby2_keywords_spec.rb
+++ b/spec/ruby/core/main/ruby2_keywords_spec.rb
@@ -1,11 +1,9 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-ruby_version_is "2.7" do
- describe "main.ruby2_keywords" do
- it "is the same as Object.ruby2_keywords" do
- main = TOPLEVEL_BINDING.receiver
- main.should have_private_method(:ruby2_keywords)
- end
+describe "main.ruby2_keywords" do
+ it "is the same as Object.ruby2_keywords" do
+ main = TOPLEVEL_BINDING.receiver
+ main.should have_private_method(:ruby2_keywords)
end
end
diff --git a/spec/ruby/core/main/using_spec.rb b/spec/ruby/core/main/using_spec.rb
index f9f709f7dc..8a23970c4b 100644
--- a/spec/ruby/core/main/using_spec.rb
+++ b/spec/ruby/core/main/using_spec.rb
@@ -129,4 +129,24 @@ describe "main.using" do
x.call_bar(cls2.new).should == 'bar'
end
+
+ it "raises error when called from method in wrapped script" do
+ -> do
+ load File.expand_path('../fixtures/using_in_method.rb', __FILE__), true
+ end.should raise_error(RuntimeError)
+ end
+
+ it "raises error when called on toplevel from module" do
+ -> do
+ load File.expand_path('../fixtures/using_in_main.rb', __FILE__), true
+ end.should raise_error(RuntimeError)
+ end
+
+ ruby_version_is "3.2" do
+ it "does not raise error when wrapped with module" do
+ -> do
+ load File.expand_path('../fixtures/using.rb', __FILE__), true
+ end.should_not raise_error
+ end
+ end
end
diff --git a/spec/ruby/core/marshal/dump_spec.rb b/spec/ruby/core/marshal/dump_spec.rb
index a54a4c6735..0f77279a4f 100644
--- a/spec/ruby/core/marshal/dump_spec.rb
+++ b/spec/ruby/core/marshal/dump_spec.rb
@@ -1,5 +1,6 @@
# -*- encoding: binary -*-
require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
require_relative 'fixtures/marshal_data'
describe "Marshal.dump" do
@@ -75,7 +76,7 @@ describe "Marshal.dump" do
end
it "dumps a binary encoded Symbol" do
- s = "\u2192".force_encoding("binary").to_sym
+ s = "\u2192".dup.force_encoding("binary").to_sym
Marshal.dump(s).should == "\x04\b:\b\xE2\x86\x92"
end
@@ -84,8 +85,8 @@ describe "Marshal.dump" do
symbol1 = "I:\t\xE2\x82\xACa\x06:\x06ET"
symbol2 = "I:\t\xE2\x82\xACb\x06;\x06T"
value = [
- "€a".force_encoding(Encoding::UTF_8).to_sym,
- "€b".force_encoding(Encoding::UTF_8).to_sym
+ "€a".dup.force_encoding(Encoding::UTF_8).to_sym,
+ "€b".dup.force_encoding(Encoding::UTF_8).to_sym
]
Marshal.dump(value).should == "\x04\b[\a#{symbol1}#{symbol2}"
@@ -103,25 +104,76 @@ describe "Marshal.dump" do
UserMarshal.should_not_receive(:name)
Marshal.dump(UserMarshal.new)
end
+
+ it "raises TypeError if an Object is an instance of an anonymous class" do
+ -> { Marshal.dump(Class.new(UserMarshal).new) }.should raise_error(TypeError, /can't dump anonymous class/)
+ end
end
describe "with an object responding to #_dump" do
- it "dumps the object returned by #marshal_dump" do
+ it "dumps the String returned by #_dump" do
Marshal.dump(UserDefined.new).should == "\004\bu:\020UserDefined\022\004\b[\a:\nstuff;\000"
end
+ it "dumps the String in non US-ASCII and non UTF-8 encoding" do
+ object = UserDefinedString.new("a".encode("windows-1251"))
+ Marshal.dump(object).should == "\x04\bIu:\x16UserDefinedString\x06a\x06:\rencoding\"\x11Windows-1251"
+ end
+
+ it "dumps the String in multibyte encoding" do
+ object = UserDefinedString.new("a".encode("utf-32le"))
+ Marshal.dump(object).should == "\x04\bIu:\x16UserDefinedString\ta\x00\x00\x00\x06:\rencoding\"\rUTF-32LE"
+ end
+
+ it "ignores overridden name method" do
+ obj = MarshalSpec::UserDefinedWithOverriddenName.new
+ Marshal.dump(obj).should == "\x04\bu:/MarshalSpec::UserDefinedWithOverriddenName\x12\x04\b[\a:\nstuff;\x00"
+ end
+
it "raises a TypeError if _dump returns a non-string" do
m = mock("marshaled")
m.should_receive(:_dump).and_return(0)
-> { Marshal.dump(m) }.should raise_error(TypeError)
end
+ it "raises TypeError if an Object is an instance of an anonymous class" do
+ -> { Marshal.dump(Class.new(UserDefined).new) }.should raise_error(TypeError, /can't dump anonymous class/)
+ end
+
it "favors marshal_dump over _dump" do
m = mock("marshaled")
m.should_receive(:marshal_dump).and_return(0)
m.should_not_receive(:_dump)
Marshal.dump(m)
end
+
+ it "indexes instance variables of a String returned by #_dump at first and then indexes the object itself" do
+ class MarshalSpec::M1::A
+ def _dump(level)
+ s = +"<dump>"
+ s.instance_variable_set(:@foo, "bar")
+ s
+ end
+ end
+
+ a = MarshalSpec::M1::A.new
+
+ # 0-based index of the object a = 2, that is encoded as \x07 and printed as "\a" character.
+ # Objects are serialized in the following order: Array, a, "bar".
+ # But they are indexed in different order: Array (index=0), "bar" (index=1), a (index=2)
+ # So the second occurenc of the object a is encoded as an index 2.
+ reference = "@\a"
+ Marshal.dump([a, a]).should == "\x04\b[\aIu:\x17MarshalSpec::M1::A\v<dump>\x06:\t@foo\"\bbar#{reference}"
+ end
+
+ describe "Core library classes with #_dump returning a String with instance variables" do
+ it "indexes instance variables and then a Time object itself" do
+ t = Time.utc(2022)
+ reference = "@\a"
+
+ Marshal.dump([t, t]).should == "\x04\b[\aIu:\tTime\r \x80\x1E\xC0\x00\x00\x00\x00\x06:\tzoneI\"\bUTC\x06:\x06EF#{reference}"
+ end
+ end
end
describe "with a Class" do
@@ -137,8 +189,17 @@ describe "Marshal.dump" do
Marshal.dump(UserDefined::Nested).should == "\004\bc\030UserDefined::Nested"
end
+ it "ignores overridden name method" do
+ Marshal.dump(MarshalSpec::ClassWithOverriddenName).should == "\x04\bc)MarshalSpec::ClassWithOverriddenName"
+ end
+
+ it "dumps a class with multibyte characters in name" do
+ source_object = eval("MarshalSpec::MultibyteぁあぃいClass".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"
+ end
+
it "raises TypeError with an anonymous Class" do
- -> { Marshal.dump(Class.new) }.should raise_error(TypeError)
+ -> { Marshal.dump(Class.new) }.should raise_error(TypeError, /can't dump anonymous class/)
end
it "raises TypeError with a singleton Class" do
@@ -151,8 +212,17 @@ describe "Marshal.dump" do
Marshal.dump(Marshal).should == "\004\bm\fMarshal"
end
+ it "ignores overridden name method" do
+ Marshal.dump(MarshalSpec::ModuleWithOverriddenName).should == "\x04\bc*MarshalSpec::ModuleWithOverriddenName"
+ end
+
+ it "dumps a module with multibyte characters in name" do
+ source_object = eval("MarshalSpec::MultibyteけげこごModule".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"
+ end
+
it "raises TypeError with an anonymous Module" do
- -> { Marshal.dump(Module.new) }.should raise_error(TypeError)
+ -> { Marshal.dump(Module.new) }.should raise_error(TypeError, /can't dump anonymous module/)
end
end
@@ -185,15 +255,41 @@ describe "Marshal.dump" do
[Marshal, -2**64, "\004\bl-\n\000\000\000\000\000\000\000\000\001\000"],
].should be_computed_by(:dump)
end
+
+ it "increases the object links counter" do
+ obj = Object.new
+ object_1_link = "\x06" # representing of (0-based) index=1 (by adding 5 for small Integers)
+ object_2_link = "\x07" # representing of index=2
+
+ # objects: Array, Object, Object
+ Marshal.dump([obj, obj]).should == "\x04\b[\ao:\vObject\x00@#{object_1_link}"
+
+ # objects: Array, Bignum, Object, Object
+ Marshal.dump([2**64, obj, obj]).should == "\x04\b[\bl+\n\x00\x00\x00\x00\x00\x00\x00\x00\x01\x00o:\vObject\x00@#{object_2_link}"
+ Marshal.dump([2**48, obj, obj]).should == "\x04\b[\bl+\t\x00\x00\x00\x00\x00\x00\x01\x00o:\vObject\x00@#{object_2_link}"
+ Marshal.dump([2**32, obj, obj]).should == "\x04\b[\bl+\b\x00\x00\x00\x00\x01\x00o:\vObject\x00@#{object_2_link}"
+ end
+ end
+
+ describe "with a Rational" do
+ it "dumps a Rational" do
+ Marshal.dump(Rational(2, 3)).should == "\x04\bU:\rRational[\ai\ai\b"
+ end
+ end
+
+ describe "with a Complex" do
+ it "dumps a Complex" do
+ Marshal.dump(Complex(2, 3)).should == "\x04\bU:\fComplex[\ai\ai\b"
+ end
end
describe "with a String" do
it "dumps a blank String" do
- Marshal.dump("".force_encoding("binary")).should == "\004\b\"\000"
+ Marshal.dump("".dup.force_encoding("binary")).should == "\004\b\"\000"
end
it "dumps a short String" do
- Marshal.dump("short".force_encoding("binary")).should == "\004\b\"\012short"
+ Marshal.dump("short".dup.force_encoding("binary")).should == "\004\b\"\012short"
end
it "dumps a long String" do
@@ -201,7 +297,7 @@ describe "Marshal.dump" do
end
it "dumps a String extended with a Module" do
- Marshal.dump("".extend(Meths).force_encoding("binary")).should == "\004\be:\nMeths\"\000"
+ Marshal.dump("".dup.extend(Meths).force_encoding("binary")).should == "\004\be:\nMeths\"\000"
end
it "dumps a String subclass" do
@@ -212,24 +308,29 @@ describe "Marshal.dump" do
Marshal.dump(UserString.new.extend(Meths).force_encoding("binary")).should == "\004\be:\nMethsC:\017UserString\"\000"
end
+ it "ignores overridden name method when dumps a String subclass" do
+ obj = MarshalSpec::StringWithOverriddenName.new
+ Marshal.dump(obj).should == "\x04\bC:*MarshalSpec::StringWithOverriddenName\"\x00"
+ end
+
it "dumps a String with instance variables" do
- str = ""
+ str = +""
str.instance_variable_set("@foo", "bar")
Marshal.dump(str.force_encoding("binary")).should == "\x04\bI\"\x00\x06:\t@foo\"\bbar"
end
it "dumps a US-ASCII String" do
- str = "abc".force_encoding("us-ascii")
+ str = "abc".dup.force_encoding("us-ascii")
Marshal.dump(str).should == "\x04\bI\"\babc\x06:\x06EF"
end
it "dumps a UTF-8 String" do
- str = "\x6d\xc3\xb6\x68\x72\x65".force_encoding("utf-8")
+ str = "\x6d\xc3\xb6\x68\x72\x65".dup.force_encoding("utf-8")
Marshal.dump(str).should == "\x04\bI\"\vm\xC3\xB6hre\x06:\x06ET"
end
it "dumps a String in another encoding" do
- str = "\x6d\x00\xf6\x00\x68\x00\x72\x00\x65\x00".force_encoding("utf-16le")
+ str = "\x6d\x00\xf6\x00\x68\x00\x72\x00\x65\x00".dup.force_encoding("utf-16le")
result = "\x04\bI\"\x0Fm\x00\xF6\x00h\x00r\x00e\x00\x06:\rencoding\"\rUTF-16LE"
Marshal.dump(str).should == result
end
@@ -263,18 +364,46 @@ describe "Marshal.dump" do
end
it "dumps a binary Regexp" do
- o = Regexp.new("".force_encoding("binary"), Regexp::FIXEDENCODING)
+ o = Regexp.new("".dup.force_encoding("binary"), Regexp::FIXEDENCODING)
Marshal.dump(o).should == "\x04\b/\x00\x10"
end
+ it "dumps an ascii-compatible Regexp" do
+ o = Regexp.new("a".encode("us-ascii"), Regexp::FIXEDENCODING)
+ Marshal.dump(o).should == "\x04\bI/\x06a\x10\x06:\x06EF"
+
+ o = Regexp.new("a".encode("us-ascii"))
+ Marshal.dump(o).should == "\x04\bI/\x06a\x00\x06:\x06EF"
+
+ o = Regexp.new("a".encode("windows-1251"), Regexp::FIXEDENCODING)
+ Marshal.dump(o).should == "\x04\bI/\x06a\x10\x06:\rencoding\"\x11Windows-1251"
+
+ o = Regexp.new("a".encode("windows-1251"))
+ Marshal.dump(o).should == "\x04\bI/\x06a\x00\x06:\x06EF"
+ end
+
it "dumps a UTF-8 Regexp" do
- o = Regexp.new("".force_encoding("utf-8"), Regexp::FIXEDENCODING)
+ o = Regexp.new("".dup.force_encoding("utf-8"), Regexp::FIXEDENCODING)
Marshal.dump(o).should == "\x04\bI/\x00\x10\x06:\x06ET"
+
+ o = Regexp.new("a".dup.force_encoding("utf-8"), Regexp::FIXEDENCODING)
+ Marshal.dump(o).should == "\x04\bI/\x06a\x10\x06:\x06ET"
+
+ o = Regexp.new("\u3042".dup.force_encoding("utf-8"), Regexp::FIXEDENCODING)
+ Marshal.dump(o).should == "\x04\bI/\b\xE3\x81\x82\x10\x06:\x06ET"
end
it "dumps a Regexp in another encoding" do
- o = Regexp.new("".force_encoding("utf-16le"), Regexp::FIXEDENCODING)
+ o = Regexp.new("".dup.force_encoding("utf-16le"), Regexp::FIXEDENCODING)
Marshal.dump(o).should == "\x04\bI/\x00\x10\x06:\rencoding\"\rUTF-16LE"
+
+ o = Regexp.new("a".encode("utf-16le"), Regexp::FIXEDENCODING)
+ Marshal.dump(o).should == "\x04\bI/\aa\x00\x10\x06:\rencoding\"\rUTF-16LE"
+ end
+
+ it "ignores overridden name method when dumps a Regexp subclass" do
+ obj = MarshalSpec::RegexpWithOverriddenName.new("")
+ Marshal.dump(obj).should == "\x04\bIC:*MarshalSpec::RegexpWithOverriddenName/\x00\x00\x06:\x06EF"
end
end
@@ -306,6 +435,11 @@ describe "Marshal.dump" do
it "dumps an extended Array" do
Marshal.dump([].extend(Meths)).should == "\004\be:\nMeths[\000"
end
+
+ it "ignores overridden name method when dumps an Array subclass" do
+ obj = MarshalSpec::ArrayWithOverriddenName.new
+ Marshal.dump(obj).should == "\x04\bC:)MarshalSpec::ArrayWithOverriddenName[\x00"
+ end
end
describe "with a Hash" do
@@ -313,6 +447,10 @@ describe "Marshal.dump" do
Marshal.dump({}).should == "\004\b{\000"
end
+ it "dumps a non-empty Hash" do
+ Marshal.dump({a: 1}).should == "\x04\b{\x06:\x06ai\x06"
+ end
+
it "dumps a Hash subclass" do
Marshal.dump(UserHash.new).should == "\004\bC:\rUserHash{\000"
end
@@ -321,8 +459,24 @@ describe "Marshal.dump" do
Marshal.dump(Hash.new(1)).should == "\004\b}\000i\006"
end
+ ruby_version_is "3.1" do
+ it "dumps a Hash with compare_by_identity" do
+ h = {}
+ h.compare_by_identity
+
+ Marshal.dump(h).should == "\004\bC:\tHash{\x00"
+ end
+
+ it "dumps a Hash subclass with compare_by_identity" do
+ h = UserHash.new
+ h.compare_by_identity
+
+ Marshal.dump(h).should == "\x04\bC:\rUserHashC:\tHash{\x00"
+ end
+ end
+
it "raises a TypeError with hash having default proc" do
- -> { Marshal.dump(Hash.new {}) }.should raise_error(TypeError)
+ -> { Marshal.dump(Hash.new {}) }.should raise_error(TypeError, "can't dump hash with default proc")
end
it "dumps a Hash with instance variables" do
@@ -338,6 +492,11 @@ describe "Marshal.dump" do
it "dumps an Hash subclass with a parameter to initialize" do
Marshal.dump(UserHashInitParams.new(1)).should == "\004\bIC:\027UserHashInitParams{\000\006:\a@ai\006"
end
+
+ it "ignores overridden name method when dumps a Hash subclass" do
+ obj = MarshalSpec::HashWithOverriddenName.new
+ Marshal.dump(obj).should == "\x04\bC:(MarshalSpec::HashWithOverriddenName{\x00"
+ end
end
describe "with a Struct" do
@@ -366,6 +525,15 @@ describe "Marshal.dump" do
Marshal.dump(obj).should == "\004\be:\nMethsS:\025Struct::Extended\a:\006a[\a;\a\"\ahi:\006b[\a;\000@\a"
Struct.send(:remove_const, :Extended)
end
+
+ it "ignores overridden name method" do
+ obj = MarshalSpec::StructWithOverriddenName.new("member")
+ Marshal.dump(obj).should == "\x04\bS:*MarshalSpec::StructWithOverriddenName\x06:\x06a\"\vmember"
+ end
+
+ it "raises TypeError with an anonymous Struct" do
+ -> { Marshal.dump(Struct.new(:a).new(1)) }.should raise_error(TypeError, /can't dump anonymous class/)
+ end
end
describe "with an Object" do
@@ -385,7 +553,7 @@ describe "Marshal.dump" do
it "dumps an Object with a non-US-ASCII instance variable" do
obj = Object.new
- ivar = "@é".force_encoding(Encoding::UTF_8).to_sym
+ ivar = "@é".dup.force_encoding(Encoding::UTF_8).to_sym
obj.instance_variable_set(ivar, 1)
Marshal.dump(obj).should == "\x04\bo:\vObject\x06I:\b@\xC3\xA9\x06:\x06ETi\x06"
end
@@ -397,13 +565,18 @@ describe "Marshal.dump" do
Marshal.dump(obj).should == "\004\bo:\x0BObject\x00"
end
- it "dumps an Object if it has a singleton class but no singleton methods" do
+ it "dumps an Object if it has a singleton class but no singleton methods and no singleton instance variables" do
obj = Object.new
obj.singleton_class
Marshal.dump(obj).should == "\004\bo:\x0BObject\x00"
end
- it "raises if an Object has a singleton class and singleton methods" do
+ it "ignores overridden name method" do
+ obj = MarshalSpec::ClassWithOverriddenName.new
+ Marshal.dump(obj).should == "\x04\bo:)MarshalSpec::ClassWithOverriddenName\x00"
+ end
+
+ it "raises TypeError if an Object has a singleton class and singleton methods" do
obj = Object.new
def obj.foo; end
-> {
@@ -411,10 +584,45 @@ describe "Marshal.dump" do
}.should raise_error(TypeError, "singleton can't be dumped")
end
+ it "raises TypeError if an Object has a singleton class and singleton instance variables" do
+ obj = Object.new
+ class << obj
+ @v = 1
+ end
+
+ -> {
+ Marshal.dump(obj)
+ }.should raise_error(TypeError, "singleton can't be dumped")
+ end
+
+ it "raises TypeError if an Object is an instance of an anonymous class" do
+ anonymous_class = Class.new
+ obj = anonymous_class.new
+
+ -> { Marshal.dump(obj) }.should raise_error(TypeError, /can't dump anonymous class/)
+ end
+
+ it "raises TypeError if an Object extends an anonymous module" do
+ anonymous_module = Module.new
+ obj = Object.new
+ obj.extend(anonymous_module)
+
+ -> { Marshal.dump(obj) }.should raise_error(TypeError, /can't dump anonymous class/)
+ end
+
it "dumps a BasicObject subclass if it defines respond_to?" do
obj = MarshalSpec::BasicObjectSubWithRespondToFalse.new
Marshal.dump(obj).should == "\x04\bo:2MarshalSpec::BasicObjectSubWithRespondToFalse\x00"
end
+
+ it "dumps without marshaling any attached finalizer" do
+ obj = Object.new
+ finalizer = Object.new
+ def finalizer.noop(_)
+ end
+ ObjectSpace.define_finalizer(obj, finalizer.method(:noop))
+ Marshal.load(Marshal.dump(obj)).class.should == Object
+ end
end
describe "with a Range" do
@@ -430,15 +638,8 @@ describe "Marshal.dump" do
load.should == (1...2)
end
- ruby_version_is ""..."3.0" do
- it "dumps a Range with extra instance variables" do
- range = (1...3)
- range.instance_variable_set :@foo, 42
- dump = Marshal.dump(range)
- load = Marshal.load(dump)
- load.should == range
- load.instance_variable_get(:@foo).should == 42
- end
+ 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
end
@@ -477,6 +678,20 @@ describe "Marshal.dump" do
zone = ":\tzoneI\"\bUTC\x06:\x06EF" # Last is 'F' (US-ASCII)
dump.should == "\x04\bIu:\tTime\r#{@utc_dump}\x06#{zone}"
end
+
+ it "ignores overridden name method" do
+ obj = MarshalSpec::TimeWithOverriddenName.new
+ Marshal.dump(obj).should include("MarshalSpec::TimeWithOverriddenName")
+ end
+
+ it "dumps a Time subclass with multibyte characters in name" do
+ source_object = eval("MarshalSpec::MultibyteぁあぃいTime".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"
+ end
+
+ it "raises TypeError with an anonymous Time subclass" do
+ -> { Marshal.dump(Class.new(Time).now) }.should raise_error(TypeError)
+ end
end
describe "with an Exception" do
@@ -517,6 +732,23 @@ describe "Marshal.dump" do
reloaded.cause.should be_an_instance_of(StandardError)
reloaded.cause.message.should == "the cause"
end
+
+ # NoMethodError uses an exception formatter on TruffleRuby and computes a message lazily
+ it "dumps the message for the raised NoMethodError exception" do
+ begin
+ "".foo
+ rescue => e
+ end
+
+ Marshal.dump(e).should =~ /undefined method [`']foo' for ("":String|an instance of String)/
+ end
+
+ it "raises TypeError if an Object is an instance of an anonymous class" do
+ anonymous_class = Class.new(Exception)
+ obj = anonymous_class.new
+
+ -> { Marshal.dump(obj) }.should raise_error(TypeError, /can't dump anonymous class/)
+ end
end
it "dumps subsequent appearances of a symbol as a link" do
@@ -549,7 +781,6 @@ describe "Marshal.dump" do
end
describe "when passed an IO" do
-
it "writes the serialized data to the IO-Object" do
(obj = mock('test')).should_receive(:write).at_least(1)
Marshal.dump("test", obj)
@@ -572,8 +803,6 @@ describe "Marshal.dump" do
obj.should_receive(:binmode).at_least(1)
Marshal.dump("test", obj)
end
-
-
end
describe "when passed a StringIO" do
@@ -604,30 +833,4 @@ describe "Marshal.dump" do
m = Mutex.new
-> { Marshal.dump(m) }.should raise_error(TypeError)
end
-
- ruby_version_is ''...'2.7' do
- it "returns an untainted string if object is untainted" do
- Marshal.dump(Object.new).tainted?.should be_false
- end
-
- it "returns a tainted string if object is tainted" do
- Marshal.dump(Object.new.taint).tainted?.should be_true
- end
-
- it "returns a tainted string if nested object is tainted" do
- Marshal.dump([[Object.new.taint]]).tainted?.should be_true
- end
-
- it "returns a trusted string if object is trusted" do
- Marshal.dump(Object.new).untrusted?.should be_false
- end
-
- it "returns an untrusted string if object is untrusted" do
- Marshal.dump(Object.new.untrust).untrusted?.should be_true
- end
-
- it "returns an untrusted string if nested object is untrusted" do
- Marshal.dump([[Object.new.untrust]]).untrusted?.should be_true
- end
- end
end
diff --git a/spec/ruby/core/marshal/fixtures/classes.rb b/spec/ruby/core/marshal/fixtures/classes.rb
new file mode 100644
index 0000000000..7c81c64927
--- /dev/null
+++ b/spec/ruby/core/marshal/fixtures/classes.rb
@@ -0,0 +1,4 @@
+module MarshalSpec
+ # empty modules
+ module M1 end
+end
diff --git a/spec/ruby/core/marshal/fixtures/marshal_data.rb b/spec/ruby/core/marshal/fixtures/marshal_data.rb
index 9373ef7ba8..a508b6bea1 100644
--- a/spec/ruby/core/marshal/fixtures/marshal_data.rb
+++ b/spec/ruby/core/marshal/fixtures/marshal_data.rb
@@ -38,7 +38,7 @@ class UserDefinedWithIvar
attr_reader :a, :b, :c
def initialize
- @a = 'stuff'
+ @a = +'stuff'
@a.instance_variable_set :@foo, :UserDefinedWithIvar
@b = 'more'
@c = @b
@@ -78,6 +78,22 @@ class UserDefinedImmediate
end
end
+class UserDefinedString
+ attr_reader :string
+
+ def initialize(string)
+ @string = string
+ end
+
+ def _dump(depth)
+ @string
+ end
+
+ def self._load(data)
+ new(data)
+ end
+end
+
class UserPreviouslyDefinedWithInitializedIvar
attr_accessor :field1, :field2
end
@@ -167,12 +183,17 @@ module MarshalSpec
end
end
+ StructToDump = Struct.new(:a, :b)
+
class BasicObjectSubWithRespondToFalse < BasicObject
def respond_to?(method_name, include_all=false)
false
end
end
+ module ModuleToExtendBy
+ end
+
def self.random_data
randomizer = Random.new(42)
1000.times{randomizer.rand} # Make sure we exhaust his first state of 624 random words
@@ -192,6 +213,81 @@ module MarshalSpec
set_swapped_class(nil)
end
+ class ClassWithOverriddenName
+ def self.name
+ "Foo"
+ end
+ end
+
+ class ModuleWithOverriddenName
+ def self.name
+ "Foo"
+ end
+ end
+
+ class TimeWithOverriddenName < Time
+ def self.name
+ "Foo"
+ end
+ end
+
+ class StructWithOverriddenName < Struct.new(:a)
+ def self.name
+ "Foo"
+ end
+ end
+
+ class UserDefinedWithOverriddenName < UserDefined
+ def self.name
+ "Foo"
+ end
+ end
+
+ class StringWithOverriddenName < String
+ def self.name
+ "Foo"
+ end
+ end
+
+ class ArrayWithOverriddenName < Array
+ def self.name
+ "Foo"
+ end
+ end
+
+ class HashWithOverriddenName < Hash
+ def self.name
+ "Foo"
+ end
+ end
+
+ class RegexpWithOverriddenName < Regexp
+ def self.name
+ "Foo"
+ end
+ end
+
+ module_eval(<<~ruby.dup.force_encoding(Encoding::UTF_8))
+ class MultibyteぁあぃいClass
+ end
+
+ module MultibyteけげこごModule
+ end
+
+ class MultibyteぁあぃいTime < Time
+ end
+ ruby
+
+ class ObjectWithFreezeRaisingException < Object
+ def freeze
+ raise
+ end
+ end
+
+ class ObjectWithoutFreeze < Object
+ undef freeze
+ end
+
DATA = {
"nil" => [nil, "\004\b0"],
"1..2" => [(1..2),
@@ -217,7 +313,7 @@ module MarshalSpec
"\004\b\"\012small"],
"String big" => ['big' * 100,
"\004\b\"\002,\001#{'big' * 100}"],
- "String extended" => [''.extend(Meths), # TODO: check for module on load
+ "String extended" => [''.dup.extend(Meths), # TODO: check for module on load
"\004\be:\nMeths\"\000"],
"String subclass" => [UserString.new,
"\004\bC:\017UserString\"\000"],
@@ -324,7 +420,7 @@ module MarshalSpec
"\x04\bI\"\nsmall\x06:\x06EF"],
"String big" => ['big' * 100,
"\x04\bI\"\x02,\x01bigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbigbig\x06:\x06EF"],
- "String extended" => [''.extend(Meths), # TODO: check for module on load
+ "String extended" => [''.dup.extend(Meths), # TODO: check for module on load
"\x04\bIe:\nMeths\"\x00\x06:\x06EF"],
"String subclass" => [UserString.new,
"\004\bC:\017UserString\"\000"],
diff --git a/spec/ruby/core/marshal/shared/load.rb b/spec/ruby/core/marshal/shared/load.rb
index b70bca55bf..f599042529 100644
--- a/spec/ruby/core/marshal/shared/load.rb
+++ b/spec/ruby/core/marshal/shared/load.rb
@@ -8,7 +8,11 @@ describe :marshal_load, shared: true do
it "raises an ArgumentError when the dumped data is truncated" do
obj = {first: 1, second: 2, third: 3}
- -> { Marshal.send(@method, Marshal.dump(obj)[0, 5]) }.should raise_error(ArgumentError)
+ -> { Marshal.send(@method, Marshal.dump(obj)[0, 5]) }.should raise_error(ArgumentError, "marshal data too short")
+ end
+
+ it "raises an ArgumentError when the argument is empty String" do
+ -> { Marshal.send(@method, "") }.should raise_error(ArgumentError, "marshal data too short")
end
it "raises an ArgumentError when the dumped class is missing" do
@@ -50,29 +54,136 @@ describe :marshal_load, shared: true do
regexp.should.frozen?
end
+ it "returns frozen structs" do
+ struct = Marshal.send(@method, Marshal.dump(MarshalSpec::StructToDump.new(1, 2)), freeze: true)
+ struct.should == MarshalSpec::StructToDump.new(1, 2)
+ struct.should.frozen?
+ end
+
it "returns frozen objects" do
source_object = Object.new
- source_object.instance_variable_set(:@foo, "bar")
object = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
object.should.frozen?
- object.instance_variable_get(:@foo).should.frozen?
+ end
+
+ describe "deep freezing" do
+ it "returns hashes with frozen keys and values" do
+ key = Object.new
+ value = Object.new
+ source_object = {key => value}
+
+ hash = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
+ hash.size.should == 1
+ hash.keys[0].should.frozen?
+ hash.values[0].should.frozen?
+ end
+
+ it "returns arrays with frozen elements" do
+ object = Object.new
+ source_object = [object]
+
+ array = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
+ array.size.should == 1
+ array[0].should.frozen?
+ end
+
+ it "returns structs with frozen members" do
+ object1 = Object.new
+ object2 = Object.new
+ source_object = MarshalSpec::StructToDump.new(object1, object2)
+
+ struct = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
+ struct.a.should.frozen?
+ struct.b.should.frozen?
+ end
+
+ it "returns objects with frozen instance variables" do
+ source_object = Object.new
+ instance_variable = Object.new
+ source_object.instance_variable_set(:@a, instance_variable)
+
+ object = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
+ object.instance_variable_get(:@a).should != nil
+ object.instance_variable_get(:@a).should.frozen?
+ end
+
+ it "deduplicates frozen strings" do
+ source_object = ["foo" + "bar", "foobar"]
+ object = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
+
+ object[0].should equal(object[1])
+ end
end
it "does not freeze modules" do
- Marshal.send(@method, Marshal.dump(Kernel), freeze: true)
+ object = Marshal.send(@method, Marshal.dump(Kernel), freeze: true)
+ object.should_not.frozen?
Kernel.should_not.frozen?
end
it "does not freeze classes" do
- Marshal.send(@method, Marshal.dump(Object), freeze: true)
+ object = Marshal.send(@method, Marshal.dump(Object), freeze: true)
+ object.should_not.frozen?
Object.should_not.frozen?
end
+ ruby_bug "#19427", ""..."3.3" do
+ it "does freeze extended objects" do
+ object = Marshal.load("\x04\be:\x0FEnumerableo:\vObject\x00", freeze: true)
+ object.should.frozen?
+ end
+
+ it "does freeze extended objects with instance variables" do
+ object = Marshal.load("\x04\be:\x0FEnumerableo:\vObject\x06:\n@ivarT", freeze: true)
+ object.should.frozen?
+ end
+ end
+
+ ruby_bug "#19427", "3.1"..."3.3" do
+ it "returns frozen object having #_dump method" do
+ object = Marshal.send(@method, Marshal.dump(UserDefined.new), freeze: true)
+ object.should.frozen?
+ end
+
+ it "returns frozen object responding to #marshal_dump and #marshal_load" do
+ object = Marshal.send(@method, Marshal.dump(UserMarshal.new), freeze: true)
+ object.should.frozen?
+ end
+
+ it "returns frozen object extended by a module" do
+ object = Object.new
+ object.extend(MarshalSpec::ModuleToExtendBy)
+
+ object = Marshal.send(@method, Marshal.dump(object), freeze: true)
+ object.should.frozen?
+ end
+ end
+
+ it "does not call freeze method" do
+ object = MarshalSpec::ObjectWithFreezeRaisingException.new
+ object = Marshal.send(@method, Marshal.dump(object), freeze: true)
+ object.should.frozen?
+ end
+
+ it "returns frozen object even if object does not respond to freeze method" do
+ object = MarshalSpec::ObjectWithoutFreeze.new
+ object = Marshal.send(@method, Marshal.dump(object), freeze: true)
+ object.should.frozen?
+ end
+
+ it "returns a frozen object when is an instance of String/Array/Regexp/Hash subclass and has instance variables" do
+ source_object = UserString.new
+ source_object.instance_variable_set(:@foo, "bar")
+
+ object = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
+ object.should.frozen?
+ end
+
describe "when called with a proc" do
it "call the proc with frozen objects" do
arr = []
- s = 'hi'
+ s = +'hi'
s.instance_variable_set(:@foo, 5)
st = Struct.new("Brittle", :a).new
st.instance_variable_set(:@clue, 'none')
@@ -132,6 +243,14 @@ describe :marshal_load, shared: true do
end
end
+ ruby_bug "#19427", ""..."3.3" do
+ it "call the proc with extended objects" do
+ objs = []
+ obj = Marshal.load("\x04\be:\x0FEnumerableo:\vObject\x00", Proc.new { |o| objs << o; o })
+ objs.should == [obj]
+ end
+ end
+
it "returns the value of the proc" do
Marshal.send(@method, Marshal.dump([1,2]), proc { [3,4] }).should == [3,4]
end
@@ -149,7 +268,7 @@ describe :marshal_load, shared: true do
it "loads an Array with proc" do
arr = []
- s = 'hi'
+ s = +'hi'
s.instance_variable_set(:@foo, 5)
st = Struct.new("Brittle", :a).new
st.instance_variable_set(:@clue, 'none')
@@ -195,7 +314,19 @@ describe :marshal_load, shared: true do
marshaled_obj.field2.should be_nil
end
- describe "that return an immediate value" do
+ it "loads the String in non US-ASCII and non UTF-8 encoding" do
+ source_object = UserDefinedString.new("a".encode("windows-1251"))
+ object = Marshal.send(@method, Marshal.dump(source_object))
+ object.string.should == "a".encode("windows-1251")
+ end
+
+ it "loads the String in multibyte encoding" do
+ source_object = UserDefinedString.new("a".encode("utf-32le"))
+ object = Marshal.send(@method, Marshal.dump(source_object))
+ object.string.should == "a".encode("utf-32le")
+ end
+
+ describe "that returns an immediate value" do
it "loads an array containing an instance of the object, followed by multiple instances of another object" do
str = "string"
@@ -282,13 +413,13 @@ describe :marshal_load, shared: true do
end
it "raises a TypeError with bad Marshal version" do
- marshal_data = '\xff\xff'
+ marshal_data = +'\xff\xff'
marshal_data[0] = (Marshal::MAJOR_VERSION).chr
marshal_data[1] = (Marshal::MINOR_VERSION + 1).chr
-> { Marshal.send(@method, marshal_data) }.should raise_error(TypeError)
- marshal_data = '\xff\xff'
+ marshal_data = +'\xff\xff'
marshal_data[0] = (Marshal::MAJOR_VERSION - 1).chr
marshal_data[1] = (Marshal::MINOR_VERSION).chr
@@ -306,89 +437,6 @@ describe :marshal_load, shared: true do
end
end
- ruby_version_is ''...'2.7' do
- it "returns an untainted object if source is untainted" do
- x = Object.new
- y = Marshal.send(@method, Marshal.dump(x))
- y.tainted?.should be_false
- end
-
- describe "when source is tainted" do
- it "returns a tainted object" do
- x = Object.new
- x.taint
- s = Marshal.dump(x)
- y = Marshal.send(@method, s)
- y.tainted?.should be_true
-
- # note that round-trip via Marshal does not preserve
- # the taintedness at each level of the nested structure
- y = Marshal.send(@method, Marshal.dump([[x]]))
- y.tainted?.should be_true
- y.first.tainted?.should be_true
- y.first.first.tainted?.should be_true
- end
-
- it "does not taint Symbols" do
- x = [:x]
- y = Marshal.send(@method, Marshal.dump(x).taint)
- y.tainted?.should be_true
- y.first.tainted?.should be_false
- end
-
- it "does not taint Fixnums" do
- x = [1]
- y = Marshal.send(@method, Marshal.dump(x).taint)
- y.tainted?.should be_true
- y.first.tainted?.should be_false
- end
-
- it "does not taint Bignums" do
- x = [bignum_value]
- y = Marshal.send(@method, Marshal.dump(x).taint)
- y.tainted?.should be_true
- y.first.tainted?.should be_false
- end
-
- it "does not taint Floats" do
- x = [1.2]
- y = Marshal.send(@method, Marshal.dump(x).taint)
- y.tainted?.should be_true
- y.first.tainted?.should be_false
- end
- end
-
- it "preserves taintedness of nested structure" do
- x = Object.new
- a = [[x]]
- x.taint
- y = Marshal.send(@method, Marshal.dump(a))
- y.tainted?.should be_true
- y.first.tainted?.should be_true
- y.first.first.tainted?.should be_true
- end
-
- it "returns a trusted object if source is trusted" do
- x = Object.new
- y = Marshal.send(@method, Marshal.dump(x))
- y.untrusted?.should be_false
- end
-
- it "returns an untrusted object if source is untrusted" do
- x = Object.new
- x.untrust
- y = Marshal.send(@method, Marshal.dump(x))
- y.untrusted?.should be_true
-
- # note that round-trip via Marshal does not preserve
- # the untrustedness at each level of the nested structure
- y = Marshal.send(@method, Marshal.dump([[x]]))
- y.untrusted?.should be_true
- y.first.untrusted?.should be_true
- y.first.first.untrusted?.should be_true
- end
- end
-
# Note: Ruby 1.9 should be compatible with older marshal format
MarshalSpec::DATA.each do |description, (object, marshal, attributes)|
it "loads a #{description}" do
@@ -422,7 +470,7 @@ describe :marshal_load, shared: true do
end
it "loads an array having ivar" do
- s = 'well'
+ s = +'well'
s.instance_variable_set(:@foo, 10)
obj = ['5', s, 'hi'].extend(Meths, MethsMore)
obj.instance_variable_set(:@mix, s)
@@ -468,7 +516,7 @@ describe :marshal_load, shared: true do
end
it "preserves hash ivars when hash contains a string having ivar" do
- s = 'string'
+ s = +'string'
s.instance_variable_set :@string_ivar, 'string ivar'
h = { key: s }
h.instance_variable_set :@hash_ivar, 'hash ivar'
@@ -477,6 +525,38 @@ describe :marshal_load, shared: true do
unmarshalled.instance_variable_get(:@hash_ivar).should == 'hash ivar'
unmarshalled[:key].instance_variable_get(:@string_ivar).should == 'string ivar'
end
+
+ ruby_version_is "3.1" do
+ it "preserves compare_by_identity behaviour" do
+ h = { a: 1 }
+ h.compare_by_identity
+ unmarshalled = Marshal.send(@method, Marshal.dump(h))
+ unmarshalled.should.compare_by_identity?
+
+ h = { a: 1 }
+ unmarshalled = Marshal.send(@method, Marshal.dump(h))
+ unmarshalled.should_not.compare_by_identity?
+ end
+
+ it "preserves compare_by_identity behaviour for a Hash subclass" do
+ h = UserHash.new({ a: 1 })
+ h.compare_by_identity
+ unmarshalled = Marshal.send(@method, Marshal.dump(h))
+ unmarshalled.should.compare_by_identity?
+
+ h = UserHash.new({ a: 1 })
+ unmarshalled = Marshal.send(@method, Marshal.dump(h))
+ unmarshalled.should_not.compare_by_identity?
+ end
+ end
+
+ it "allocates an instance of the proper class when Hash subclass with compare_by_identity behaviour" do
+ h = UserHash.new({ a: 1 })
+ h.compare_by_identity
+
+ unmarshalled = Marshal.send(@method, Marshal.dump(h))
+ unmarshalled.should.kind_of?(UserHash)
+ end
end
describe "for a Symbol" do
@@ -520,7 +600,7 @@ describe :marshal_load, shared: true do
end
it "loads a binary encoded Symbol" do
- s = "\u2192".force_encoding("binary").to_sym
+ s = "\u2192".dup.force_encoding("binary").to_sym
sym = Marshal.send(@method, "\x04\b:\b\xE2\x86\x92")
sym.should == s
sym.encoding.should == Encoding::BINARY
@@ -534,8 +614,8 @@ describe :marshal_load, shared: true do
value = Marshal.send(@method, dump)
value.map(&:encoding).should == [Encoding::UTF_8, Encoding::UTF_8]
expected = [
- "€a".force_encoding(Encoding::UTF_8).to_sym,
- "€b".force_encoding(Encoding::UTF_8).to_sym
+ "€a".dup.force_encoding(Encoding::UTF_8).to_sym,
+ "€b".dup.force_encoding(Encoding::UTF_8).to_sym
]
value.should == expected
@@ -543,11 +623,19 @@ describe :marshal_load, shared: true do
value.map(&:encoding).should == [Encoding::UTF_8, Encoding::UTF_8, Encoding::UTF_8]
value.should == [*expected, expected[0]]
end
+
+ it "raises ArgumentError when end of byte sequence reached before symbol characters end" do
+ Marshal.dump(:hello).should == "\x04\b:\nhello"
+
+ -> {
+ Marshal.send(@method, "\x04\b:\nhel")
+ }.should raise_error(ArgumentError, "marshal data too short")
+ end
end
describe "for a String" do
it "loads a string having ivar with ref to self" do
- obj = 'hi'
+ obj = +'hi'
obj.instance_variable_set(:@self, obj)
Marshal.send(@method, "\004\bI\"\ahi\006:\n@self@\000").should == obj
end
@@ -558,6 +646,12 @@ describe :marshal_load, shared: true do
Marshal.send(@method, StringIO.new(Marshal.dump(obj))).should == obj
end
+ it "sets binmode if it is loading through StringIO stream" do
+ io = StringIO.new("\004\b:\vsymbol")
+ def io.binmode; raise "binmode"; end
+ -> { Marshal.load(io) }.should raise_error(RuntimeError, "binmode")
+ end
+
it "loads a string with an ivar" do
str = Marshal.send(@method, "\x04\bI\"\x00\x06:\t@fooI\"\bbar\x06:\x06EF")
str.instance_variable_get("@foo").should == "bar"
@@ -569,7 +663,7 @@ describe :marshal_load, shared: true do
end
it "loads a US-ASCII String" do
- str = "abc".force_encoding("us-ascii")
+ str = "abc".dup.force_encoding("us-ascii")
data = "\x04\bI\"\babc\x06:\x06EF"
result = Marshal.send(@method, data)
result.should == str
@@ -577,7 +671,7 @@ describe :marshal_load, shared: true do
end
it "loads a UTF-8 String" do
- str = "\x6d\xc3\xb6\x68\x72\x65".force_encoding("utf-8")
+ str = "\x6d\xc3\xb6\x68\x72\x65".dup.force_encoding("utf-8")
data = "\x04\bI\"\vm\xC3\xB6hre\x06:\x06ET"
result = Marshal.send(@method, data)
result.should == str
@@ -585,7 +679,7 @@ describe :marshal_load, shared: true do
end
it "loads a String in another encoding" do
- str = "\x6d\x00\xf6\x00\x68\x00\x72\x00\x65\x00".force_encoding("utf-16le")
+ str = "\x6d\x00\xf6\x00\x68\x00\x72\x00\x65\x00".dup.force_encoding("utf-16le")
data = "\x04\bI\"\x0Fm\x00\xF6\x00h\x00r\x00e\x00\x06:\rencoding\"\rUTF-16LE"
result = Marshal.send(@method, data)
result.should == str
@@ -593,12 +687,20 @@ describe :marshal_load, shared: true do
end
it "loads a String as BINARY if no encoding is specified at the end" do
- str = "\xC3\xB8".force_encoding("BINARY")
- data = "\x04\b\"\a\xC3\xB8".force_encoding("UTF-8")
+ str = "\xC3\xB8".dup.force_encoding("BINARY")
+ data = "\x04\b\"\a\xC3\xB8".dup.force_encoding("UTF-8")
result = Marshal.send(@method, data)
result.encoding.should == Encoding::BINARY
result.should == str
end
+
+ it "raises ArgumentError when end of byte sequence reached before string characters end" do
+ Marshal.dump("hello").should == "\x04\b\"\nhello"
+
+ -> {
+ Marshal.send(@method, "\x04\b\"\nhel")
+ }.should raise_error(ArgumentError, "marshal data too short")
+ end
end
describe "for a Struct" do
@@ -721,7 +823,7 @@ describe :marshal_load, shared: true do
end
it "loads an Object with a non-US-ASCII instance variable" do
- ivar = "@é".force_encoding(Encoding::UTF_8).to_sym
+ ivar = "@é".dup.force_encoding(Encoding::UTF_8).to_sym
obj = Marshal.send(@method, "\x04\bo:\vObject\x06I:\b@\xC3\xA9\x06:\x06ETi\x06")
obj.instance_variables.should == [ivar]
obj.instance_variables[0].encoding.should == Encoding::UTF_8
@@ -733,6 +835,14 @@ describe :marshal_load, shared: true do
Marshal.send(@method, "\x04\bo:\tFile\001\001:\001\005@path\"\x10/etc/passwd")
end.should raise_error(ArgumentError)
end
+
+ it "raises ArgumentError when end of byte sequence reached before class name end" do
+ Marshal.dump(Object.new).should == "\x04\bo:\vObject\x00"
+
+ -> {
+ Marshal.send(@method, "\x04\bo:\vObj")
+ }.should raise_error(ArgumentError, "marshal data too short")
+ end
end
describe "for an object responding to #marshal_dump and #marshal_load" do
@@ -791,7 +901,7 @@ describe :marshal_load, shared: true do
[Meths, MethsMore, Regexp]
end
- it "loads a extended_user_regexp having ivar" do
+ it "loads a Regexp subclass instance variables when it is extended with a module" do
obj = UserRegexp.new('').extend(Meths)
obj.instance_variable_set(:@noise, 'much')
@@ -803,6 +913,33 @@ describe :marshal_load, shared: true do
new_obj_metaclass_ancestors[@num_self_class, 3].should ==
[Meths, UserRegexp, Regexp]
end
+
+ ruby_bug "#19439", ""..."3.3" do
+ it "restore the regexp instance variables" do
+ obj = Regexp.new("hello")
+ obj.instance_variable_set(:@regexp_ivar, [42])
+
+ new_obj = Marshal.send(@method, "\x04\bI/\nhello\x00\a:\x06EF:\x11@regexp_ivar[\x06i/")
+ new_obj.instance_variables.should == [:@regexp_ivar]
+ new_obj.instance_variable_get(:@regexp_ivar).should == [42]
+ end
+ end
+
+ it "preserves Regexp encoding" do
+ source_object = Regexp.new("a".encode("utf-32le"))
+ regexp = Marshal.send(@method, Marshal.dump(source_object))
+
+ regexp.encoding.should == Encoding::UTF_32LE
+ regexp.source.should == "a".encode("utf-32le")
+ end
+
+ it "raises ArgumentError when end of byte sequence reached before source string end" do
+ Marshal.dump(/hello world/).should == "\x04\bI/\x10hello world\x00\x06:\x06EF"
+
+ -> {
+ Marshal.send(@method, "\x04\bI/\x10hel")
+ }.should raise_error(ArgumentError, "marshal data too short")
+ end
end
describe "for a Float" do
@@ -824,6 +961,14 @@ describe :marshal_load, shared: true do
obj = 1.1867345e+22
Marshal.send(@method, "\004\bf\0361.1867344999999999e+22\000\344@").should == obj
end
+
+ it "raises ArgumentError when end of byte sequence reached before float string representation end" do
+ Marshal.dump(1.3).should == "\x04\bf\b1.3"
+
+ -> {
+ Marshal.send(@method, "\004\bf\v1")
+ }.should raise_error(ArgumentError, "marshal data too short")
+ end
end
describe "for an Integer" do
@@ -889,13 +1034,17 @@ describe :marshal_load, shared: true do
describe "for a Rational" do
it "loads" do
- Marshal.send(@method, Marshal.dump(Rational(1, 3))).should == Rational(1, 3)
+ r = Marshal.send(@method, Marshal.dump(Rational(1, 3)))
+ r.should == Rational(1, 3)
+ r.should.frozen?
end
end
describe "for a Complex" do
it "loads" do
- Marshal.send(@method, Marshal.dump(Complex(4, 3))).should == Complex(4, 3)
+ c = Marshal.send(@method, Marshal.dump(Complex(4, 3)))
+ c.should == Complex(4, 3)
+ c.should.frozen?
end
end
@@ -936,17 +1085,47 @@ describe :marshal_load, shared: true do
t1.should equal t2
end
- it "loads the zone" do
+ it "keeps the local zone" do
with_timezone 'AST', 3 do
t = Time.local(2012, 1, 1)
Marshal.send(@method, Marshal.dump(t)).zone.should == t.zone
end
end
- it "loads nanoseconds" do
+ it "keeps UTC zone" do
+ t = Time.now.utc
+ t2 = Marshal.send(@method, Marshal.dump(t))
+ t2.should.utc?
+ end
+
+ it "keeps the zone" do
+ t = nil
+
+ with_timezone 'AST', 4 do
+ t = Time.local(2012, 1, 1)
+ end
+
+ with_timezone 'EET', -2 do
+ Marshal.send(@method, Marshal.dump(t)).zone.should == 'AST'
+ end
+ end
+
+ it "keeps utc offset" do
+ t = Time.new(2007,11,1,15,25,0, "+09:00")
+ t2 = Marshal.send(@method, Marshal.dump(t))
+ t2.utc_offset.should == 32400
+ end
+
+ it "keeps nanoseconds" do
t = Time.now
Marshal.send(@method, Marshal.dump(t)).nsec.should == t.nsec
end
+
+ it "does not add any additional instance variable" do
+ t = Time.now
+ t2 = Marshal.send(@method, Marshal.dump(t))
+ t2.instance_variables.should.empty?
+ end
end
describe "for nil" do
@@ -979,6 +1158,14 @@ describe :marshal_load, shared: true do
it "raises ArgumentError if given a nonexistent class" do
-> { Marshal.send(@method, "\x04\bc\vStrung") }.should raise_error(ArgumentError)
end
+
+ it "raises ArgumentError when end of byte sequence reached before class name end" do
+ Marshal.dump(String).should == "\x04\bc\vString"
+
+ -> {
+ Marshal.send(@method, "\x04\bc\vStr")
+ }.should raise_error(ArgumentError, "marshal data too short")
+ end
end
describe "for a Module" do
@@ -993,6 +1180,14 @@ describe :marshal_load, shared: true do
it "loads an old module" do
Marshal.send(@method, "\x04\bM\vKernel").should == Kernel
end
+
+ it "raises ArgumentError when end of byte sequence reached before module name end" do
+ Marshal.dump(Kernel).should == "\x04\bm\vKernel"
+
+ -> {
+ Marshal.send(@method, "\x04\bm\vKer")
+ }.should raise_error(ArgumentError, "marshal data too short")
+ end
end
describe "for a wrapped C pointer" do
diff --git a/spec/ruby/core/matchdata/allocate_spec.rb b/spec/ruby/core/matchdata/allocate_spec.rb
index 9f3ada4018..142ce639c2 100644
--- a/spec/ruby/core/matchdata/allocate_spec.rb
+++ b/spec/ruby/core/matchdata/allocate_spec.rb
@@ -1,10 +1,8 @@
require_relative '../../spec_helper'
describe "MatchData.allocate" do
- ruby_version_is "2.7" do
- it "is undefined" do
- # https://bugs.ruby-lang.org/issues/16294
- -> { MatchData.allocate }.should raise_error(NoMethodError)
- end
+ it "is undefined" do
+ # https://bugs.ruby-lang.org/issues/16294
+ -> { MatchData.allocate }.should raise_error(NoMethodError)
end
end
diff --git a/spec/ruby/core/matchdata/begin_spec.rb b/spec/ruby/core/matchdata/begin_spec.rb
index 85c454da56..54b4e0a33f 100644
--- a/spec/ruby/core/matchdata/begin_spec.rb
+++ b/spec/ruby/core/matchdata/begin_spec.rb
@@ -36,6 +36,18 @@ describe "MatchData#begin" do
match_data = /(.)(.)(\d+)(\d)/.match("THX1138.")
match_data.begin(obj).should == 2
end
+
+ it "raises IndexError if index is out of bounds" do
+ match_data = /(?<f>foo)(?<b>bar)/.match("foobar")
+
+ -> {
+ match_data.begin(-1)
+ }.should raise_error(IndexError, "index -1 out of matches")
+
+ -> {
+ match_data.begin(3)
+ }.should raise_error(IndexError, "index 3 out of matches")
+ end
end
context "when passed a String argument" do
@@ -68,6 +80,14 @@ describe "MatchData#begin" do
match_data = /(?<æ>.)(.)(?<b>\d+)(\d)/.match("THX1138.")
match_data.begin("æ").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.begin("y")
+ }.should raise_error(IndexError, "undefined group name reference: y")
+ end
end
context "when passed a Symbol argument" do
@@ -100,5 +120,13 @@ describe "MatchData#begin" do
match_data = /(?<æ>.)(.)(?<b>\d+)(\d)/.match("THX1138.")
match_data.begin(:æ).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.begin(:y)
+ }.should raise_error(IndexError, "undefined group name reference: y")
+ end
end
end
diff --git a/spec/ruby/core/matchdata/byteoffset_spec.rb b/spec/ruby/core/matchdata/byteoffset_spec.rb
new file mode 100644
index 0000000000..b27267fd0e
--- /dev/null
+++ b/spec/ruby/core/matchdata/byteoffset_spec.rb
@@ -0,0 +1,95 @@
+require_relative '../../spec_helper'
+
+describe "MatchData#byteoffset" do
+ ruby_version_is "3.2" do
+ it "returns beginning and ending byte-based offset of whole matched substring for 0 element" do
+ m = /(.)(.)(\d+)(\d)/.match("THX1138.")
+ m.byteoffset(0).should == [1, 7]
+ end
+
+ it "returns beginning and ending byte-based offset of n-th match, all the subsequent elements are capturing groups" do
+ m = /(.)(.)(\d+)(\d)/.match("THX1138.")
+
+ m.byteoffset(2).should == [2, 3]
+ m.byteoffset(3).should == [3, 6]
+ m.byteoffset(4).should == [6, 7]
+ end
+
+ it "accepts String as a reference to a named capture" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
+
+ m.byteoffset("f").should == [0, 3]
+ m.byteoffset("b").should == [3, 6]
+ end
+
+ it "accepts Symbol as a reference to a named capture" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
+
+ m.byteoffset(:f).should == [0, 3]
+ m.byteoffset(:b).should == [3, 6]
+ end
+
+ it "returns [nil, nil] if a capturing group is optional and doesn't match" do
+ m = /(?<x>q..)?/.match("foobarbaz")
+
+ m.byteoffset("x").should == [nil, nil]
+ m.byteoffset(1).should == [nil, nil]
+ end
+
+ it "returns correct beginning and ending byte-based offset for multi-byte strings" do
+ m = /\A\u3042(.)(.)?(.)\z/.match("\u3042\u3043\u3044")
+
+ m.byteoffset(1).should == [3, 6]
+ m.byteoffset(3).should == [6, 9]
+ end
+
+ it "returns [nil, nil] if a capturing group is optional and doesn't match for multi-byte string" do
+ m = /\A\u3042(.)(.)?(.)\z/.match("\u3042\u3043\u3044")
+
+ m.byteoffset(2).should == [nil, nil]
+ end
+
+ it "converts argument into integer if is not String nor Symbol" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
+
+ obj = Object.new
+ def obj.to_int; 2; end
+
+ m.byteoffset(1r).should == [0, 3]
+ m.byteoffset(1.1).should == [0, 3]
+ m.byteoffset(obj).should == [3, 6]
+ end
+
+ it "raises IndexError if there is no group with 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")
+ end
+
+ 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(3)
+ }.should raise_error(IndexError, "index 3 out of matches")
+ end
+
+ it "raises TypeError if can't convert argument into Integer" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
+
+ -> {
+ m.byteoffset([])
+ }.should raise_error(TypeError, "no implicit conversion of Array into Integer")
+ end
+ end
+end
diff --git a/spec/ruby/core/matchdata/captures_spec.rb b/spec/ruby/core/matchdata/captures_spec.rb
index 58d4620709..f829a25481 100644
--- a/spec/ruby/core/matchdata/captures_spec.rb
+++ b/spec/ruby/core/matchdata/captures_spec.rb
@@ -1,15 +1,6 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
+require_relative 'shared/captures'
describe "MatchData#captures" do
- it "returns an array of the match captures" do
- /(.)(.)(\d+)(\d)/.match("THX1138.").captures.should == ["H","X","113","8"]
- end
-
- ruby_version_is "3.0" do
- it "returns instances of String when given a String subclass" do
- str = MatchDataSpecs::MyString.new("THX1138: The Movie")
- /(.)(.)(\d+)(\d)/.match(str).captures.each { |c| c.should be_an_instance_of(String) }
- end
- end
+ it_behaves_like :matchdata_captures, :captures
end
diff --git a/spec/ruby/core/matchdata/deconstruct_keys_spec.rb b/spec/ruby/core/matchdata/deconstruct_keys_spec.rb
new file mode 100644
index 0000000000..5b68f886c7
--- /dev/null
+++ b/spec/ruby/core/matchdata/deconstruct_keys_spec.rb
@@ -0,0 +1,65 @@
+require_relative '../../spec_helper'
+
+describe "MatchData#deconstruct_keys" do
+ ruby_version_is "3.2" do
+ it "returns whole hash for nil as an argument" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
+
+ m.deconstruct_keys(nil).should == { f: "foo", b: "bar" }
+ end
+
+ it "returns only specified keys" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
+
+ m.deconstruct_keys([:f]).should == { f: "foo" }
+ end
+
+ it "requires one argument" do
+ m = /l/.match("l")
+
+ -> {
+ m.deconstruct_keys
+ }.should raise_error(ArgumentError, "wrong number of arguments (given 0, expected 1)")
+ end
+
+ it "it raises error when argument is neither nil nor array" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
+
+ -> { m.deconstruct_keys(1) }.should raise_error(TypeError, "wrong argument type Integer (expected Array)")
+ -> { m.deconstruct_keys("asd") }.should raise_error(TypeError, "wrong argument type String (expected Array)")
+ -> { m.deconstruct_keys(:x) }.should raise_error(TypeError, "wrong argument type Symbol (expected Array)")
+ -> { m.deconstruct_keys({}) }.should raise_error(TypeError, "wrong argument type Hash (expected Array)")
+ end
+
+ it "returns {} when passed []" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
+
+ m.deconstruct_keys([]).should == {}
+ end
+
+ it "does not accept non-Symbol keys" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
+
+ -> {
+ m.deconstruct_keys(['year', :foo])
+ }.should raise_error(TypeError, "wrong argument type String (expected Symbol)")
+ end
+
+ it "process keys till the first non-existing one" do
+ m = /(?<f>foo)(?<b>bar)(?<c>baz)/.match("foobarbaz")
+
+ m.deconstruct_keys([:f, :a, :b]).should == { f: "foo" }
+ end
+
+ it "returns {} when there are no named captured groups at all" do
+ m = /foo.+/.match("foobar")
+
+ m.deconstruct_keys(nil).should == {}
+ end
+
+ it "returns {} when passed more keys than named captured groups" do
+ m = /(?<f>foo)(?<b>bar)/.match("foobar")
+ m.deconstruct_keys([:f, :b, :c]).should == {}
+ end
+ end
+end
diff --git a/spec/ruby/core/matchdata/deconstruct_spec.rb b/spec/ruby/core/matchdata/deconstruct_spec.rb
new file mode 100644
index 0000000000..6af55113b6
--- /dev/null
+++ b/spec/ruby/core/matchdata/deconstruct_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../spec_helper'
+require_relative 'shared/captures'
+
+describe "MatchData#deconstruct" do
+ ruby_version_is "3.2" do
+ it_behaves_like :matchdata_captures, :deconstruct
+ end
+end
diff --git a/spec/ruby/core/matchdata/element_reference_spec.rb b/spec/ruby/core/matchdata/element_reference_spec.rb
index 3b976cb1c4..806db2d7b5 100644
--- a/spec/ruby/core/matchdata/element_reference_spec.rb
+++ b/spec/ruby/core/matchdata/element_reference_spec.rb
@@ -16,17 +16,41 @@ describe "MatchData#[]" do
it "supports accessors [start, length]" do
/(.)(.)(\d+)(\d)/.match("THX1138.")[1, 2].should == %w|H X|
/(.)(.)(\d+)(\d)/.match("THX1138.")[-3, 2].should == %w|X 113|
+
+ # negative index is larger than the number of match values
+ /(.)(.)(\d+)(\d)/.match("THX1138.")[-30, 2].should == nil
+
+ # length argument larger than number of match values is capped to match value length
+ /(.)(.)(\d+)(\d)/.match("THX1138.")[3, 10].should == %w|113 8|
+
+ /(.)(.)(\d+)(\d)/.match("THX1138.")[3, 0].should == []
+
+ /(.)(.)(\d+)(\d)/.match("THX1138.")[3, -1].should == nil
+ /(.)(.)(\d+)(\d)/.match("THX1138.")[3, -30].should == nil
end
it "supports ranges [start..end]" do
/(.)(.)(\d+)(\d)/.match("THX1138.")[1..3].should == %w|H X 113|
+ /(.)(.)(\d+)(\d)/.match("THX1138.")[3..10].should == %w|113 8|
+ /(.)(.)(\d+)(\d)/.match("THX1138.")[-30..2].should == nil
+ /(.)(.)(\d+)(\d)/.match("THX1138.")[3..1].should == []
+ end
+
+ it "supports endless ranges [start..]" do
+ /(.)(.)(\d+)(\d)/.match("THX1138.")[3..].should == %w|113 8|
+ end
+
+ it "supports beginningless ranges [..end]" do
+ /(.)(.)(\d+)(\d)/.match("THX1138.")[..1].should == %w|HX1138 H|
+ end
+
+ it "supports beginningless endless ranges [nil..nil]" do
+ /(.)(.)(\d+)(\d)/.match("THX1138.")[nil..nil].should == %w|HX1138 H X 113 8|
end
- ruby_version_is "3.0" do
- it "returns instances of String when given a String subclass" do
- str = MatchDataSpecs::MyString.new("THX1138.")
- /(.)(.)(\d+)(\d)/.match(str)[0..-1].each { |m| m.should be_an_instance_of(String) }
- end
+ it "returns instances of String when given a String subclass" do
+ str = MatchDataSpecs::MyString.new("THX1138.")
+ /(.)(.)(\d+)(\d)/.match(str)[0..-1].each { |m| m.should be_an_instance_of(String) }
end
end
@@ -89,7 +113,7 @@ describe "MatchData#[Symbol]" do
it "returns matches in the String's encoding" do
rex = /(?<t>t(?<a>ack))/u
- md = 'haystack'.force_encoding('euc-jp').match(rex)
+ md = 'haystack'.dup.force_encoding('euc-jp').match(rex)
md[:t].encoding.should == Encoding::EUC_JP
end
end
diff --git a/spec/ruby/core/matchdata/named_captures_spec.rb b/spec/ruby/core/matchdata/named_captures_spec.rb
index 9b1e324a24..5e4693d62d 100644
--- a/spec/ruby/core/matchdata/named_captures_spec.rb
+++ b/spec/ruby/core/matchdata/named_captures_spec.rb
@@ -12,4 +12,16 @@ describe 'MatchData#named_captures' do
it 'returns the latest matched capture, even if a later one that does not match exists' do
/\A(?<a>.)(?<b>.)(?<b>.)(?<a>.)?\z/.match('012').named_captures.should == { 'a' => '0', 'b' => '2' }
end
+
+ ruby_version_is "3.3" do
+ it 'returns a Hash with Symbol keys when symbolize_names is provided a true value' do
+ /(?<a>.)(?<b>.)?/.match('0').named_captures(symbolize_names: true).should == { a: '0', b: nil }
+ /(?<a>.)(?<b>.)?/.match('0').named_captures(symbolize_names: "truly").should == { a: '0', b: nil }
+ end
+
+ it 'returns a Hash with String keys when symbolize_names is provided a false value' do
+ /(?<a>.)(?<b>.)?/.match('02').named_captures(symbolize_names: false).should == { 'a' => '0', 'b' => '2' }
+ /(?<a>.)(?<b>.)?/.match('02').named_captures(symbolize_names: nil).should == { 'a' => '0', 'b' => '2' }
+ end
+ end
end
diff --git a/spec/ruby/core/matchdata/post_match_spec.rb b/spec/ruby/core/matchdata/post_match_spec.rb
index 1a4ca0a83f..7bfe6df119 100644
--- a/spec/ruby/core/matchdata/post_match_spec.rb
+++ b/spec/ruby/core/matchdata/post_match_spec.rb
@@ -7,38 +7,18 @@ describe "MatchData#post_match" do
$'.should == ': The Movie'
end
- ruby_version_is ''...'2.7' do
- it "keeps taint status from the source string" do
- str = "THX1138: The Movie"
- str.taint
- res = /(.)(.)(\d+)(\d)/.match(str).post_match
- res.tainted?.should be_true
- $'.tainted?.should be_true
- end
-
- it "keeps untrusted status from the source string" do
- str = "THX1138: The Movie"
- str.untrust
- res = /(.)(.)(\d+)(\d)/.match(str).post_match
- res.untrusted?.should be_true
- $'.untrusted?.should be_true
- end
- end
-
it "sets the encoding to the encoding of the source String" do
- str = "abc".force_encoding Encoding::EUC_JP
+ str = "abc".dup.force_encoding Encoding::EUC_JP
str.match(/b/).post_match.encoding.should equal(Encoding::EUC_JP)
end
it "sets an empty result to the encoding of the source String" do
- str = "abc".force_encoding Encoding::ISO_8859_1
+ str = "abc".dup.force_encoding Encoding::ISO_8859_1
str.match(/c/).post_match.encoding.should equal(Encoding::ISO_8859_1)
end
- ruby_version_is "3.0" do
- it "returns an instance of String when given a String subclass" do
- str = MatchDataSpecs::MyString.new("THX1138: The Movie")
- /(.)(.)(\d+)(\d)/.match(str).post_match.should be_an_instance_of(String)
- end
+ it "returns an instance of String when given a String subclass" do
+ str = MatchDataSpecs::MyString.new("THX1138: The Movie")
+ /(.)(.)(\d+)(\d)/.match(str).post_match.should be_an_instance_of(String)
end
end
diff --git a/spec/ruby/core/matchdata/pre_match_spec.rb b/spec/ruby/core/matchdata/pre_match_spec.rb
index 9b50336c7d..2f1ba9b8f6 100644
--- a/spec/ruby/core/matchdata/pre_match_spec.rb
+++ b/spec/ruby/core/matchdata/pre_match_spec.rb
@@ -7,38 +7,18 @@ describe "MatchData#pre_match" do
$`.should == 'T'
end
- ruby_version_is ''...'2.7' do
- it "keeps taint status from the source string" do
- str = "THX1138: The Movie"
- str.taint
- res = /(.)(.)(\d+)(\d)/.match(str).pre_match
- res.tainted?.should be_true
- $`.tainted?.should be_true
- end
-
- it "keeps untrusted status from the source string" do
- str = "THX1138: The Movie"
- str.untrust
- res = /(.)(.)(\d+)(\d)/.match(str).pre_match
- res.untrusted?.should be_true
- $`.untrusted?.should be_true
- end
- end
-
it "sets the encoding to the encoding of the source String" do
- str = "abc".force_encoding Encoding::EUC_JP
+ str = "abc".dup.force_encoding Encoding::EUC_JP
str.match(/b/).pre_match.encoding.should equal(Encoding::EUC_JP)
end
it "sets an empty result to the encoding of the source String" do
- str = "abc".force_encoding Encoding::ISO_8859_1
+ str = "abc".dup.force_encoding Encoding::ISO_8859_1
str.match(/a/).pre_match.encoding.should equal(Encoding::ISO_8859_1)
end
- ruby_version_is "3.0" do
- it "returns an instance of String when given a String subclass" do
- str = MatchDataSpecs::MyString.new("THX1138: The Movie")
- /(.)(.)(\d+)(\d)/.match(str).pre_match.should be_an_instance_of(String)
- end
+ it "returns an instance of String when given a String subclass" do
+ str = MatchDataSpecs::MyString.new("THX1138: The Movie")
+ /(.)(.)(\d+)(\d)/.match(str).pre_match.should be_an_instance_of(String)
end
end
diff --git a/spec/ruby/core/matchdata/shared/captures.rb b/spec/ruby/core/matchdata/shared/captures.rb
new file mode 100644
index 0000000000..33f834561a
--- /dev/null
+++ b/spec/ruby/core/matchdata/shared/captures.rb
@@ -0,0 +1,13 @@
+require_relative '../../../spec_helper'
+require_relative '../fixtures/classes'
+
+describe :matchdata_captures, shared: true do
+ it "returns an array of the match captures" do
+ /(.)(.)(\d+)(\d)/.match("THX1138.").send(@method).should == ["H","X","113","8"]
+ end
+
+ it "returns instances of String when given a String subclass" do
+ str = MatchDataSpecs::MyString.new("THX1138: The Movie")
+ /(.)(.)(\d+)(\d)/.match(str).send(@method).each { |c| c.should be_an_instance_of(String) }
+ end
+end
diff --git a/spec/ruby/core/matchdata/string_spec.rb b/spec/ruby/core/matchdata/string_spec.rb
index 420233e1f3..952e953318 100644
--- a/spec/ruby/core/matchdata/string_spec.rb
+++ b/spec/ruby/core/matchdata/string_spec.rb
@@ -17,8 +17,9 @@ describe "MatchData#string" do
md.string.should equal(md.string)
end
- it "returns a frozen copy of the matched string for gsub(String)" do
- 'he[[o'.gsub!('[', ']')
+ it "returns a frozen copy of the matched string for gsub!(String)" do
+ s = +'he[[o'
+ s.gsub!('[', ']')
$~.string.should == 'he[[o'
$~.string.should.frozen?
end
diff --git a/spec/ruby/core/matchdata/to_a_spec.rb b/spec/ruby/core/matchdata/to_a_spec.rb
index 50f5a161a5..4fa11ff604 100644
--- a/spec/ruby/core/matchdata/to_a_spec.rb
+++ b/spec/ruby/core/matchdata/to_a_spec.rb
@@ -6,10 +6,8 @@ describe "MatchData#to_a" do
/(.)(.)(\d+)(\d)/.match("THX1138.").to_a.should == ["HX1138", "H", "X", "113", "8"]
end
- ruby_version_is "3.0" do
- it "returns instances of String when given a String subclass" do
- str = MatchDataSpecs::MyString.new("THX1138.")
- /(.)(.)(\d+)(\d)/.match(str)[0..-1].to_a.each { |m| m.should be_an_instance_of(String) }
- end
+ it "returns instances of String when given a String subclass" do
+ str = MatchDataSpecs::MyString.new("THX1138.")
+ /(.)(.)(\d+)(\d)/.match(str)[0..-1].to_a.each { |m| m.should be_an_instance_of(String) }
end
end
diff --git a/spec/ruby/core/matchdata/to_s_spec.rb b/spec/ruby/core/matchdata/to_s_spec.rb
index aab0955ae1..cd1c4dbca2 100644
--- a/spec/ruby/core/matchdata/to_s_spec.rb
+++ b/spec/ruby/core/matchdata/to_s_spec.rb
@@ -6,10 +6,8 @@ describe "MatchData#to_s" do
/(.)(.)(\d+)(\d)/.match("THX1138.").to_s.should == "HX1138"
end
- ruby_version_is "3.0" do
- it "returns an instance of String when given a String subclass" do
- str = MatchDataSpecs::MyString.new("THX1138.")
- /(.)(.)(\d+)(\d)/.match(str).to_s.should be_an_instance_of(String)
- end
+ it "returns an instance of String when given a String subclass" do
+ str = MatchDataSpecs::MyString.new("THX1138.")
+ /(.)(.)(\d+)(\d)/.match(str).to_s.should be_an_instance_of(String)
end
end
diff --git a/spec/ruby/core/matchdata/values_at_spec.rb b/spec/ruby/core/matchdata/values_at_spec.rb
index 8f7fdf557c..535719a2ee 100644
--- a/spec/ruby/core/matchdata/values_at_spec.rb
+++ b/spec/ruby/core/matchdata/values_at_spec.rb
@@ -1,21 +1,76 @@
require_relative '../../spec_helper'
describe "MatchData#values_at" do
- it "returns an array of the matching value" do
- /(.)(.)(\d+)(\d)/.match("THX1138: The Movie").values_at(0, 2, -2).should == ["HX1138", "X", "113"]
+ # Should be synchronized with core/array/values_at_spec.rb and core/struct/values_at_spec.rb
+ #
+ # /(.)(.)(\d+)(\d)/.match("THX1138: The Movie").to_a # => ["HX1138", "H", "X", "113", "8"]
+
+ context "when passed a list of Integers" do
+ it "returns an array containing each value given by one of integers" do
+ /(.)(.)(\d+)(\d)/.match("THX1138: The Movie").values_at(0, 2, -2).should == ["HX1138", "X", "113"]
+ end
+
+ it "returns nil value for any integer that is out of range" do
+ /(.)(.)(\d+)(\d)/.match("THX1138: The Movie").values_at(5).should == [nil]
+ /(.)(.)(\d+)(\d)/.match("THX1138: The Movie").values_at(-6).should == [nil]
+ end
end
- describe "when passed a Range" do
- it "returns an array of the matching value" do
- /(.)(.)(\d+)(\d)/.match("THX1138: The Movie").values_at(2..4, 0..1).should == ["X", "113", "8", "HX1138", "H"]
+ context "when passed an integer Range" do
+ it "returns an array containing each value given by the elements of the range" do
+ /(.)(.)(\d+)(\d)/.match("THX1138: The Movie").values_at(0..2).should == ["HX1138", "H", "X"]
+ end
+
+ it "fills with nil values for range elements larger than the captured values number" do
+ /(.)(.)(\d+)(\d)/.match("THX1138: The Movie").values_at(0..5).should == ["HX1138", "H", "X", "113", "8", nil]
+ end
+
+ it "raises RangeError if any element of the range is negative and out of range" do
+ -> { /(.)(.)(\d+)(\d)/.match("THX1138: The Movie").values_at(-6..3) }.should raise_error(RangeError, "-6..3 out of range")
+ end
+
+ it "supports endless Range" do
+ /(.)(.)(\d+)(\d)/.match("THX1138: The Movie").values_at(0..).should == ["HX1138", "H", "X", "113", "8"]
+ end
+
+ it "supports beginningless Range" do
+ /(.)(.)(\d+)(\d)/.match("THX1138: The Movie").values_at(..2).should == ["HX1138", "H", "X"]
+ end
+
+ it "returns an empty Array when Range is empty" do
+ /(.)(.)(\d+)(\d)/.match("THX1138: The Movie").values_at(2..0).should == []
+ end
+ end
+
+ context "when passed names" do
+ it 'slices captures with the given names' do
+ /(?<a>.)(?<b>.)(?<c>.)/.match('012').values_at(:c, :a).should == ['2', '0']
+ end
+
+ it 'slices captures with the given String names' do
+ /(?<a>.)(?<b>.)(?<c>.)/.match('012').values_at('c', 'a').should == ['2', '0']
end
end
- it 'slices captures with the given names' do
- /(?<a>.)(?<b>.)(?<c>.)/.match('012').values_at(:c, :a).should == ['2', '0']
+ it "supports multiple integer Ranges" do
+ /(.)(.)(\d+)(\d)/.match("THX1138: The Movie").values_at(1..2, 2..3).should == ["H", "X", "X", "113"]
end
- it 'takes names and indices' do
+ it "supports mixing integer Ranges and Integers" do
+ /(.)(.)(\d+)(\d)/.match("THX1138: The Movie").values_at(1..2, 4).should == ["H", "X", "8"]
+ end
+
+ it 'supports mixing of names and indices' do
/\A(?<a>.)(?<b>.)\z/.match('01').values_at(0, 1, 2, :a, :b).should == ['01', '0', '1', '0', '1']
end
+
+ it "returns a new empty Array if no arguments given" do
+ /(.)(.)(\d+)(\d)/.match("THX1138: The Movie").values_at().should == []
+ end
+
+ it "fails when passed arguments of unsupported types" do
+ -> {
+ /(.)(.)(\d+)(\d)/.match("THX1138: The Movie").values_at(Object.new)
+ }.should raise_error(TypeError, "no implicit conversion of Object into Integer")
+ end
end
diff --git a/spec/ruby/core/math/cos_spec.rb b/spec/ruby/core/math/cos_spec.rb
index 3ba7a54c38..006afeb2cc 100644
--- a/spec/ruby/core/math/cos_spec.rb
+++ b/spec/ruby/core/math/cos_spec.rb
@@ -15,7 +15,6 @@ describe "Math.cos" do
Math.cos(2*Math::PI).should be_close(1.0, TOLERANCE)
end
-
it "raises a TypeError unless the argument is Numeric and has #to_f" do
-> { Math.cos("test") }.should raise_error(TypeError)
end
@@ -24,14 +23,23 @@ describe "Math.cos" do
Math.cos(nan_value).nan?.should be_true
end
- it "raises a TypeError if the argument is nil" do
- -> { Math.cos(nil) }.should raise_error(TypeError)
- end
-
- it "coerces its argument with #to_f" do
- f = mock_numeric('8.2')
- f.should_receive(:to_f).and_return(8.2)
- Math.cos(f).should == Math.cos(8.2)
+ describe "coerces its argument with #to_f" do
+ it "coerces its argument with #to_f" do
+ f = mock_numeric('8.2')
+ f.should_receive(:to_f).and_return(8.2)
+ Math.cos(f).should == Math.cos(8.2)
+ end
+
+ it "raises a TypeError if the given argument can't be converted to a Float" do
+ -> { Math.cos(nil) }.should raise_error(TypeError)
+ -> { Math.cos(:abc) }.should raise_error(TypeError)
+ end
+
+ it "raises a NoMethodError if the given argument raises a NoMethodError during type coercion to a Float" do
+ object = mock_numeric('mock-float')
+ object.should_receive(:to_f).and_raise(NoMethodError)
+ -> { Math.cos(object) }.should raise_error(NoMethodError)
+ end
end
end
diff --git a/spec/ruby/core/math/ldexp_spec.rb b/spec/ruby/core/math/ldexp_spec.rb
index fb7799cf26..6dcf94a663 100644
--- a/spec/ruby/core/math/ldexp_spec.rb
+++ b/spec/ruby/core/math/ldexp_spec.rb
@@ -45,6 +45,12 @@ describe "Math.ldexp" do
it "accepts any second argument that can be coerced with Integer()" do
Math.ldexp(3.23, MathSpecs::Integer.new).should be_close(12.92, TOLERANCE)
end
+
+ it "returns correct value that closes to the max value of double type" do
+ Math.ldexp(0.5122058490966879, 1024).should == 9.207889385574391e+307
+ Math.ldexp(0.9999999999999999, 1024).should == 1.7976931348623157e+308
+ Math.ldexp(0.99999999999999999, 1024).should == Float::INFINITY
+ end
end
describe "Math#ldexp" do
diff --git a/spec/ruby/core/math/sqrt_spec.rb b/spec/ruby/core/math/sqrt_spec.rb
index 779aea2a0a..918e7c3a17 100644
--- a/spec/ruby/core/math/sqrt_spec.rb
+++ b/spec/ruby/core/math/sqrt_spec.rb
@@ -27,6 +27,10 @@ describe "Math.sqrt" do
it "accepts any argument that can be coerced with Float()" do
Math.sqrt(MathSpecs::Float.new).should be_close(1.0, TOLERANCE)
end
+
+ it "raises a Math::DomainError when given a negative number" do
+ -> { Math.sqrt(-1) }.should raise_error(Math::DomainError)
+ end
end
describe "Math#sqrt" do
diff --git a/spec/ruby/core/method/clone_spec.rb b/spec/ruby/core/method/clone_spec.rb
index 3fe4000fb7..b0eb5751a9 100644
--- a/spec/ruby/core/method/clone_spec.rb
+++ b/spec/ruby/core/method/clone_spec.rb
@@ -1,14 +1,13 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
+require_relative 'shared/dup'
describe "Method#clone" do
- it "returns a copy of the method" do
- m1 = MethodSpecs::Methods.new.method(:foo)
- m2 = m1.clone
+ it_behaves_like :method_dup, :clone
- m1.should == m2
- m1.should_not equal(m2)
-
- m1.call.should == m2.call
+ it "preserves frozen status" do
+ method = Object.new.method(:method)
+ method.freeze
+ method.frozen?.should == true
+ method.clone.frozen?.should == true
end
end
diff --git a/spec/ruby/core/method/compose_spec.rb b/spec/ruby/core/method/compose_spec.rb
index 87cf61f7ad..7506e33ea8 100644
--- a/spec/ruby/core/method/compose_spec.rb
+++ b/spec/ruby/core/method/compose_spec.rb
@@ -38,8 +38,7 @@ describe "Method#<<" do
double = proc { |x| x + x }
(pow_2 << double).is_a?(Proc).should == true
- ruby_version_is(''...'3.0') { (pow_2 << double).should.lambda? }
- ruby_version_is('3.0') { (pow_2 << double).should_not.lambda? }
+ (pow_2 << double).should_not.lambda?
end
it "may accept multiple arguments" do
diff --git a/spec/ruby/core/method/dup_spec.rb b/spec/ruby/core/method/dup_spec.rb
new file mode 100644
index 0000000000..e3e29d8a68
--- /dev/null
+++ b/spec/ruby/core/method/dup_spec.rb
@@ -0,0 +1,15 @@
+require_relative '../../spec_helper'
+require_relative 'shared/dup'
+
+describe "Method#dup" do
+ ruby_version_is "3.4" do
+ it_behaves_like :method_dup, :dup
+
+ it "resets frozen status" do
+ method = Object.new.method(:method)
+ method.freeze
+ method.frozen?.should == true
+ method.dup.frozen?.should == false
+ end
+ end
+end
diff --git a/spec/ruby/core/method/fixtures/classes.rb b/spec/ruby/core/method/fixtures/classes.rb
index be96f65e25..464a519aea 100644
--- a/spec/ruby/core/method/fixtures/classes.rb
+++ b/spec/ruby/core/method/fixtures/classes.rb
@@ -84,6 +84,12 @@ module MethodSpecs
def two_req_one_opt_with_splat_and_block(a, b, c=nil, *d, &blk); end
def one_req_two_opt_with_splat_and_block(a, b=nil, c=nil, *d, &blk); end
+ def my_public_method; end
+ def my_protected_method; end
+ def my_private_method; end
+ protected :my_protected_method
+ private :my_private_method
+
define_method(:zero_defined_method, Proc.new {||})
define_method(:zero_with_splat_defined_method, Proc.new {|*x|})
define_method(:one_req_defined_method, Proc.new {|x|})
@@ -213,4 +219,28 @@ module MethodSpecs
n * m
end
end
+
+ module InheritedMethods
+ module A
+ private
+ def derp(message)
+ 'A'
+ end
+ end
+
+ module B
+ private
+ def derp
+ 'B' + super('superclass')
+ end
+ end
+
+ class C
+ include A
+ include B
+
+ public :derp
+ alias_method :meow, :derp
+ end
+ end
end
diff --git a/spec/ruby/core/method/owner_spec.rb b/spec/ruby/core/method/owner_spec.rb
index ca5dff7295..05422f1697 100644
--- a/spec/ruby/core/method/owner_spec.rb
+++ b/spec/ruby/core/method/owner_spec.rb
@@ -23,4 +23,10 @@ describe "Method#owner" do
@m.method(:handled_via_method_missing).owner.should == MethodSpecs::Methods
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
+ end
end
diff --git a/spec/ruby/core/method/parameters_spec.rb b/spec/ruby/core/method/parameters_spec.rb
index e6d51d1b4d..8495aef4d2 100644
--- a/spec/ruby/core/method/parameters_spec.rb
+++ b/spec/ruby/core/method/parameters_spec.rb
@@ -7,6 +7,7 @@ describe "Method#parameters" do
def one_keyrest(**a); end
def one_keyreq(a:); end
+ def one_nokey(**nil); end
def one_splat_one_req(*a,b); end
def one_splat_two_req(*a,b,c); end
@@ -15,11 +16,16 @@ describe "Method#parameters" do
def one_opt_with_stabby(a=-> b { true }); end
def one_unnamed_splat(*); end
+ def one_unnamed_keyrest(**); end
def one_splat_one_block(*args, &block)
local_is_not_parameter = {}
end
+ def forward_parameters(...) end
+
+ def underscore_parameters(_, _, _ = 1, *_, _:, _: 2, **_, &_); end
+
define_method(:one_optional_defined_method) {|x = 1|}
end
@@ -176,6 +182,11 @@ describe "Method#parameters" do
m.parameters.should == [[:keyreq,:a]]
end
+ it "returns [[:nokey]] for a method with a single **nil parameter" do
+ m = MethodSpecs::Methods.instance_method(:one_nokey)
+ m.parameters.should == [[:nokey]]
+ end
+
it "works with ->(){} as the value of an optional argument" do
m = MethodSpecs::Methods.instance_method(:one_opt_with_stabby)
m.parameters.should == [[:opt,:a]]
@@ -223,10 +234,15 @@ describe "Method#parameters" do
end
ruby_version_is '3.2' do
- it "adds * rest arg for \"star\" argument" do
+ it "adds rest arg with name * for \"star\" argument" do
m = MethodSpecs::Methods.new
m.method(:one_unnamed_splat).parameters.should == [[:rest, :*]]
end
+
+ it "adds keyrest arg with ** as a name for \"double star\" argument" do
+ m = MethodSpecs::Methods.new
+ m.method(:one_unnamed_keyrest).parameters.should == [[:keyrest, :**]]
+ end
end
ruby_version_is ''...'3.2' do
@@ -234,6 +250,37 @@ describe "Method#parameters" do
m = MethodSpecs::Methods.new
m.method(:one_unnamed_splat).parameters.should == [[:rest]]
end
+
+ it "adds nameless keyrest arg for \"double star\" argument" do
+ m = MethodSpecs::Methods.new
+ m.method(:one_unnamed_keyrest).parameters.should == [[:keyrest]]
+ end
+ end
+
+ ruby_version_is '3.1' do
+ it "adds block arg with name & for anonymous block argument" do
+ object = Object.new
+
+ eval(<<~RUBY).should == [[:block, :&]]
+ def object.foo(&)
+ end
+ object.method(:foo).parameters
+ RUBY
+ end
+ 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
+ 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
end
it "returns the args and block for a splat and block argument" do
@@ -251,6 +298,20 @@ describe "Method#parameters" do
m.method(:writer=).parameters.should == [[:req]]
end
+ it "returns all parameters defined with the name _ as _" do
+ m = MethodSpecs::Methods.instance_method(:underscore_parameters)
+ m.parameters.should == [
+ [:req, :_],
+ [:req, :_],
+ [:opt, :_],
+ [:rest, :_],
+ [:keyreq, :_],
+ [:key, :_],
+ [:keyrest, :_],
+ [:block, :_]
+ ]
+ end
+
it "returns [[:rest]] for core methods with variable-length argument lists" do
# delete! takes rest args
"foo".method(:delete!).parameters.should == [[:rest]]
diff --git a/spec/ruby/core/method/private_spec.rb b/spec/ruby/core/method/private_spec.rb
new file mode 100644
index 0000000000..fd550036a3
--- /dev/null
+++ b/spec/ruby/core/method/private_spec.rb
@@ -0,0 +1,28 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+
+describe "Method#private?" do
+ ruby_version_is "3.1"..."3.2" do
+ it "returns false when the method is public" do
+ obj = MethodSpecs::Methods.new
+ obj.method(:my_public_method).private?.should == false
+ end
+
+ it "returns false when the method is protected" do
+ obj = MethodSpecs::Methods.new
+ obj.method(:my_protected_method).private?.should == false
+ end
+
+ it "returns true when the method is private" do
+ obj = MethodSpecs::Methods.new
+ obj.method(:my_private_method).private?.should == true
+ end
+ end
+
+ ruby_version_is "3.2" do
+ it "has been removed" do
+ obj = MethodSpecs::Methods.new
+ obj.method(:my_private_method).should_not.respond_to?(:private?)
+ end
+ end
+end
diff --git a/spec/ruby/core/method/protected_spec.rb b/spec/ruby/core/method/protected_spec.rb
new file mode 100644
index 0000000000..8423e8c64c
--- /dev/null
+++ b/spec/ruby/core/method/protected_spec.rb
@@ -0,0 +1,28 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+
+describe "Method#protected?" do
+ ruby_version_is "3.1"..."3.2" do
+ it "returns false when the method is public" do
+ obj = MethodSpecs::Methods.new
+ obj.method(:my_public_method).protected?.should == false
+ end
+
+ it "returns true when the method is protected" do
+ obj = MethodSpecs::Methods.new
+ obj.method(:my_protected_method).protected?.should == true
+ end
+
+ it "returns false when the method is private" do
+ obj = MethodSpecs::Methods.new
+ obj.method(:my_private_method).protected?.should == false
+ end
+ end
+
+ ruby_version_is "3.2" do
+ it "has been removed" do
+ obj = MethodSpecs::Methods.new
+ obj.method(:my_protected_method).should_not.respond_to?(:protected?)
+ end
+ end
+end
diff --git a/spec/ruby/core/method/public_spec.rb b/spec/ruby/core/method/public_spec.rb
new file mode 100644
index 0000000000..20d0081a27
--- /dev/null
+++ b/spec/ruby/core/method/public_spec.rb
@@ -0,0 +1,28 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+
+describe "Method#public?" do
+ ruby_version_is "3.1"..."3.2" do
+ it "returns true when the method is public" do
+ obj = MethodSpecs::Methods.new
+ obj.method(:my_public_method).public?.should == true
+ end
+
+ it "returns false when the method is protected" do
+ obj = MethodSpecs::Methods.new
+ obj.method(:my_protected_method).public?.should == false
+ end
+
+ it "returns false when the method is private" do
+ obj = MethodSpecs::Methods.new
+ obj.method(:my_private_method).public?.should == false
+ end
+ end
+
+ ruby_version_is "3.2" do
+ it "has been removed" do
+ obj = MethodSpecs::Methods.new
+ obj.method(:my_public_method).should_not.respond_to?(:public?)
+ end
+ end
+end
diff --git a/spec/ruby/core/method/shared/dup.rb b/spec/ruby/core/method/shared/dup.rb
new file mode 100644
index 0000000000..1a10b90689
--- /dev/null
+++ b/spec/ruby/core/method/shared/dup.rb
@@ -0,0 +1,32 @@
+describe :method_dup, shared: true do
+ it "returns a copy of self" do
+ a = Object.new.method(:method)
+ b = a.send(@method)
+
+ a.should == b
+ a.should_not equal(b)
+ end
+
+ ruby_version_is "3.4" do
+ it "copies instance variables" do
+ method = Object.new.method(:method)
+ method.instance_variable_set(:@ivar, 1)
+ cl = method.send(@method)
+ cl.instance_variables.should == [:@ivar]
+ end
+
+ it "copies the finalizer" do
+ code = <<-RUBY
+ obj = Object.new.method(:method)
+
+ ObjectSpace.define_finalizer(obj, Proc.new { STDOUT.write "finalized\n" })
+
+ obj.clone
+
+ exit 0
+ RUBY
+
+ ruby_exe(code).lines.sort.should == ["finalized\n", "finalized\n"]
+ end
+ end
+end
diff --git a/spec/ruby/core/method/shared/to_s.rb b/spec/ruby/core/method/shared/to_s.rb
index 0dcae41b59..b2d27d370f 100644
--- a/spec/ruby/core/method/shared/to_s.rb
+++ b/spec/ruby/core/method/shared/to_s.rb
@@ -24,19 +24,17 @@ describe :method_to_s, shared: true do
@string.should =~ /\#bar/
end
- ruby_version_is "2.7" do
- it "returns a String containing method arguments" do
- obj = MethodSpecs::Methods.new
- obj.method(:zero).send(@method).should.include?("()")
- obj.method(:one_req).send(@method).should.include?("(a)")
- obj.method(:one_req_named).send(@method).should.include?("(a:)")
- obj.method(:zero_with_block).send(@method).should.include?("(&blk)")
- obj.method(:one_opt).send(@method).should.include?("(a=...)")
- obj.method(:one_opt_named).send(@method).should.include?("(a: ...)")
- obj.method(:zero_with_splat).send(@method).should.include?("(*a)")
- obj.method(:zero_with_double_splat).send(@method).should.include?("(**a)")
- obj.method(:one_req_one_opt_with_splat_and_block).send(@method).should.include?("(a, b=..., *c, &blk)")
- end
+ it "returns a String containing method arguments" do
+ obj = MethodSpecs::Methods.new
+ obj.method(:zero).send(@method).should.include?("()")
+ obj.method(:one_req).send(@method).should.include?("(a)")
+ obj.method(:one_req_named).send(@method).should.include?("(a:)")
+ obj.method(:zero_with_block).send(@method).should.include?("(&blk)")
+ obj.method(:one_opt).send(@method).should.include?("(a=...)")
+ obj.method(:one_opt_named).send(@method).should.include?("(a: ...)")
+ obj.method(:zero_with_splat).send(@method).should.include?("(*a)")
+ obj.method(:zero_with_double_splat).send(@method).should.include?("(**a)")
+ obj.method(:one_req_one_opt_with_splat_and_block).send(@method).should.include?("(a, b=..., *c, &blk)")
end
it "returns a String containing the Module the method is defined in" do
@@ -55,20 +53,18 @@ describe :method_to_s, shared: true do
MethodSpecs::A.new.method(:baz).send(@method).should.start_with? "#<Method: MethodSpecs::A#baz"
end
- ruby_version_is '3.0' do
- it "returns a String containing the Module containing the method if object has a singleton class but method is not defined in the singleton class" do
- obj = MethodSpecs::MySub.new
- obj.singleton_class
- @m = obj.method(:bar)
- @string = @m.send(@method)
- @string.should.start_with? "#<Method: MethodSpecs::MySub(MethodSpecs::MyMod)#bar"
+ it "returns a String containing the Module containing the method if object has a singleton class but method is not defined in the singleton class" do
+ obj = MethodSpecs::MySub.new
+ obj.singleton_class
+ @m = obj.method(:bar)
+ @string = @m.send(@method)
+ @string.should.start_with? "#<Method: MethodSpecs::MySub(MethodSpecs::MyMod)#bar"
- c = MethodSpecs::MySub.dup
- m = Module.new{def bar; end}
- c.extend(m)
- @string = c.method(:bar).send(@method)
- @string.should.start_with? "#<Method: #<Class:#{c.inspect}>(#{m.inspect})#bar"
- end
+ c = MethodSpecs::MySub.dup
+ m = Module.new{def bar; end}
+ c.extend(m)
+ @string = c.method(:bar).send(@method)
+ @string.should.start_with? "#<Method: #<Class:#{c.inspect}>(#{m.inspect})#bar"
end
it "returns a String containing the singleton class if method is defined in the singleton class" do
@@ -79,11 +75,7 @@ describe :method_to_s, shared: true do
@string.should.start_with? "#<Method: #<MethodSpecs::MySub:0xXXXXXX>.bar"
end
- ruby_version_is '2.7' do
- ruby_bug '#17428', '2.7'...'3.0' do
- it "shows the metaclass and the owner for a Module instance method retrieved from a class" do
- String.method(:include).inspect.should.start_with?("#<Method: #<Class:String>(Module)#include")
- end
- end
+ it "shows the metaclass and the owner for a Module instance method retrieved from a class" do
+ String.method(:include).inspect.should.start_with?("#<Method: #<Class:String>(Module)#include")
end
end
diff --git a/spec/ruby/core/method/source_location_spec.rb b/spec/ruby/core/method/source_location_spec.rb
index 1f476aaa9b..c5b296f6e2 100644
--- a/spec/ruby/core/method/source_location_spec.rb
+++ b/spec/ruby/core/method/source_location_spec.rb
@@ -13,7 +13,7 @@ describe "Method#source_location" do
it "sets the first value to the path of the file in which the method was defined" do
file = @method.source_location.first
file.should be_an_instance_of(String)
- file.should == File.realpath('../fixtures/classes.rb', __FILE__)
+ 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
@@ -104,6 +104,13 @@ describe "Method#source_location" do
end
end
+ it "works for eval with a given line" do
+ c = Class.new do
+ eval('def self.m; end', nil, "foo", 100)
+ end
+ c.method(:m).source_location.should == ["foo", 100]
+ end
+
describe "for a Method generated by respond_to_missing?" do
it "returns nil" do
m = MethodSpecs::Methods.new
diff --git a/spec/ruby/core/method/super_method_spec.rb b/spec/ruby/core/method/super_method_spec.rb
index e5d8b87a06..c63a7aaa0f 100644
--- a/spec/ruby/core/method/super_method_spec.rb
+++ b/spec/ruby/core/method/super_method_spec.rb
@@ -42,4 +42,23 @@ describe "Method#super_method" do
method.super_method.should == nil
end
+
+ # https://github.com/jruby/jruby/issues/7240
+ context "after changing an inherited methods visibility" do
+ it "calls the proper super method" do
+ MethodSpecs::InheritedMethods::C.new.derp.should == 'BA'
+ end
+
+ it "returns the expected super_method" do
+ method = MethodSpecs::InheritedMethods::C.new.method(:derp)
+ method.super_method.owner.should == MethodSpecs::InheritedMethods::A
+ end
+ end
+
+ context "after aliasing an inherited method" do
+ it "returns the expected super_method" do
+ method = MethodSpecs::InheritedMethods::C.new.method(:meow)
+ method.super_method.owner.should == MethodSpecs::InheritedMethods::A
+ end
+ end
end
diff --git a/spec/ruby/core/method/to_proc_spec.rb b/spec/ruby/core/method/to_proc_spec.rb
index 29b7bec2b3..4993cce239 100644
--- a/spec/ruby/core/method/to_proc_spec.rb
+++ b/spec/ruby/core/method/to_proc_spec.rb
@@ -35,7 +35,7 @@ describe "Method#to_proc" do
end
it "returns a proc that can be used by define_method" do
- x = 'test'
+ x = +'test'
to_s = class << x
define_method :foo, method(:to_s).to_proc
to_s
diff --git a/spec/ruby/core/method/unbind_spec.rb b/spec/ruby/core/method/unbind_spec.rb
index cdd3a808f2..bdedd513ce 100644
--- a/spec/ruby/core/method/unbind_spec.rb
+++ b/spec/ruby/core/method/unbind_spec.rb
@@ -27,8 +27,16 @@ describe "Method#unbind" do
@string.should =~ /MethodSpecs::MyMod/
end
- it "returns a String containing the Module the method is referenced from" do
- @string.should =~ /MethodSpecs::MySub/
+ 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
end
end
diff --git a/spec/ruby/core/module/alias_method_spec.rb b/spec/ruby/core/module/alias_method_spec.rb
index 5d3d0c23d9..c36dedd2d8 100644
--- a/spec/ruby/core/module/alias_method_spec.rb
+++ b/spec/ruby/core/module/alias_method_spec.rb
@@ -81,22 +81,20 @@ describe "Module#alias_method" do
-> { @class.make_alias mock('x'), :public_one }.should raise_error(TypeError)
end
+ it "raises a NoMethodError if the given name raises a NoMethodError during type coercion using to_str" do
+ obj = mock("mock-name")
+ obj.should_receive(:to_str).and_raise(NoMethodError)
+ -> { @class.make_alias obj, :public_one }.should raise_error(NoMethodError)
+ end
+
it "is a public method" do
Module.should have_public_instance_method(:alias_method, false)
end
describe "returned value" do
- ruby_version_is ""..."3.0" do
- it "returns self" do
- @class.send(:alias_method, :checking_return_value, :public_one).should equal(@class)
- end
- end
-
- ruby_version_is "3.0" do
- it "returns symbol of the defined method name" do
- @class.send(:alias_method, :checking_return_value, :public_one).should equal(:checking_return_value)
- @class.send(:alias_method, 'checking_return_value', :public_one).should equal(:checking_return_value)
- end
+ it "returns symbol of the defined method name" do
+ @class.send(:alias_method, :checking_return_value, :public_one).should equal(:checking_return_value)
+ @class.send(:alias_method, 'checking_return_value', :public_one).should equal(:checking_return_value)
end
end
diff --git a/spec/ruby/core/module/append_features_spec.rb b/spec/ruby/core/module/append_features_spec.rb
index d960798eef..1724cde5d6 100644
--- a/spec/ruby/core/module/append_features_spec.rb
+++ b/spec/ruby/core/module/append_features_spec.rb
@@ -47,20 +47,6 @@ describe "Module#append_features" do
end
- ruby_version_is ''...'2.7' do
- it "copies own tainted status to the given module" do
- other = Module.new
- Module.new.taint.send :append_features, other
- other.tainted?.should be_true
- end
-
- it "copies own untrusted status to the given module" do
- other = Module.new
- Module.new.untrust.send :append_features, other
- other.untrusted?.should be_true
- end
- end
-
describe "when other is frozen" do
before :each do
@receiver = Module.new
diff --git a/spec/ruby/core/module/attr_accessor_spec.rb b/spec/ruby/core/module/attr_accessor_spec.rb
index ba5289cbea..503dccc61e 100644
--- a/spec/ruby/core/module/attr_accessor_spec.rb
+++ b/spec/ruby/core/module/attr_accessor_spec.rb
@@ -1,5 +1,6 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
+require_relative 'shared/attr_added'
describe "Module#attr_accessor" do
it "creates a getter and setter for each given attribute name" do
@@ -80,19 +81,9 @@ describe "Module#attr_accessor" do
Module.should have_public_instance_method(:attr_accessor, false)
end
- ruby_version_is ""..."3.0" do
- it "returns nil" do
- Class.new do
- (attr_accessor :foo, 'bar').should == nil
- end
- end
- end
-
- ruby_version_is "3.0" do
- it "returns an array of defined method names as symbols" do
- Class.new do
- (attr_accessor :foo, 'bar').should == [:foo, :foo=, :bar, :bar=]
- end
+ it "returns an array of defined method names as symbols" do
+ Class.new do
+ (attr_accessor :foo, 'bar').should == [:foo, :foo=, :bar, :bar=]
end
end
@@ -116,4 +107,6 @@ describe "Module#attr_accessor" do
1.foobar.should be_nil
end
end
+
+ it_behaves_like :module_attr_added, :attr_accessor
end
diff --git a/spec/ruby/core/module/attr_reader_spec.rb b/spec/ruby/core/module/attr_reader_spec.rb
index b0ae906ab5..37fd537ff5 100644
--- a/spec/ruby/core/module/attr_reader_spec.rb
+++ b/spec/ruby/core/module/attr_reader_spec.rb
@@ -1,5 +1,6 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
+require_relative 'shared/attr_added'
describe "Module#attr_reader" do
it "creates a getter for each given attribute name" do
@@ -62,19 +63,11 @@ describe "Module#attr_reader" do
Module.should have_public_instance_method(:attr_reader, false)
end
- ruby_version_is ""..."3.0" do
- it "returns nil" do
- Class.new do
- (attr_reader :foo, 'bar').should == nil
- end
+ it "returns an array of defined method names as symbols" do
+ Class.new do
+ (attr_reader :foo, 'bar').should == [:foo, :bar]
end
end
- ruby_version_is "3.0" do
- it "returns an array of defined method names as symbols" do
- Class.new do
- (attr_reader :foo, 'bar').should == [:foo, :bar]
- end
- end
- end
+ it_behaves_like :module_attr_added, :attr_reader
end
diff --git a/spec/ruby/core/module/attr_spec.rb b/spec/ruby/core/module/attr_spec.rb
index 33e0eb8628..2f9f4e26dc 100644
--- a/spec/ruby/core/module/attr_spec.rb
+++ b/spec/ruby/core/module/attr_spec.rb
@@ -1,5 +1,6 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
+require_relative 'shared/attr_added'
describe "Module#attr" do
before :each do
@@ -146,23 +147,13 @@ describe "Module#attr" do
Module.should have_public_instance_method(:attr, false)
end
- ruby_version_is ""..."3.0" do
- it "returns nil" do
- Class.new do
- (attr :foo, 'bar').should == nil
- (attr :baz, false).should == nil
- (attr :qux, true).should == nil
- end
+ it "returns an array of defined method names as symbols" do
+ Class.new do
+ (attr :foo, 'bar').should == [:foo, :bar]
+ (attr :baz, false).should == [:baz]
+ (attr :qux, true).should == [:qux, :qux=]
end
end
- ruby_version_is "3.0" do
- it "returns an array of defined method names as symbols" do
- Class.new do
- (attr :foo, 'bar').should == [:foo, :bar]
- (attr :baz, false).should == [:baz]
- (attr :qux, true).should == [:qux, :qux=]
- end
- end
- end
+ it_behaves_like :module_attr_added, :attr
end
diff --git a/spec/ruby/core/module/attr_writer_spec.rb b/spec/ruby/core/module/attr_writer_spec.rb
index 0e9d201317..5b863ef88c 100644
--- a/spec/ruby/core/module/attr_writer_spec.rb
+++ b/spec/ruby/core/module/attr_writer_spec.rb
@@ -1,5 +1,6 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
+require_relative 'shared/attr_added'
describe "Module#attr_writer" do
it "creates a setter for each given attribute name" do
@@ -72,19 +73,11 @@ describe "Module#attr_writer" do
Module.should have_public_instance_method(:attr_writer, false)
end
- ruby_version_is ""..."3.0" do
- it "returns nil" do
- Class.new do
- (attr_writer :foo, 'bar').should == nil
- end
+ it "returns an array of defined method names as symbols" do
+ Class.new do
+ (attr_writer :foo, 'bar').should == [:foo=, :bar=]
end
end
- ruby_version_is "3.0" do
- it "returns an array of defined method names as symbols" do
- Class.new do
- (attr_writer :foo, 'bar').should == [:foo=, :bar=]
- end
- end
- end
+ it_behaves_like :module_attr_added, :attr_writer
end
diff --git a/spec/ruby/core/module/autoload_spec.rb b/spec/ruby/core/module/autoload_spec.rb
index 1d61646db5..45d18b8608 100644
--- a/spec/ruby/core/module/autoload_spec.rb
+++ b/spec/ruby/core/module/autoload_spec.rb
@@ -1,7 +1,6 @@
require_relative '../../spec_helper'
require_relative '../../fixtures/code_loading'
require_relative 'fixtures/classes'
-require 'thread'
describe "Module#autoload?" do
it "returns the name of the file that will be autoloaded" do
@@ -18,16 +17,14 @@ describe "Module#autoload?" do
ModuleSpecs::Autoload::Child.autoload?(:AnotherAutoload).should == "another_autoload.rb"
end
- ruby_version_is "2.7" do
- it "returns nil if an ancestor defined that autoload but recursion is disabled" do
- ModuleSpecs::Autoload::Parent.autoload :InheritedAutoload, "inherited_autoload.rb"
- ModuleSpecs::Autoload::Child.autoload?(:InheritedAutoload, false).should be_nil
- end
+ it "returns nil if an ancestor defined that autoload but recursion is disabled" do
+ ModuleSpecs::Autoload::Parent.autoload :InheritedAutoload, "inherited_autoload.rb"
+ ModuleSpecs::Autoload::Child.autoload?(:InheritedAutoload, false).should be_nil
+ end
- it "returns the name of the file that will be loaded if recursion is disabled but the autoload is defined on the class itself" do
- ModuleSpecs::Autoload::Child.autoload :ChildAutoload, "child_autoload.rb"
- ModuleSpecs::Autoload::Child.autoload?(:ChildAutoload, false).should == "child_autoload.rb"
- end
+ it "returns the name of the file that will be loaded if recursion is disabled but the autoload is defined on the class itself" do
+ ModuleSpecs::Autoload::Child.autoload :ChildAutoload, "child_autoload.rb"
+ ModuleSpecs::Autoload::Child.autoload?(:ChildAutoload, false).should == "child_autoload.rb"
end
end
@@ -345,6 +342,29 @@ describe "Module#autoload" do
end
end
+ def check_before_during_thread_after(const, &check)
+ before = check.call
+ to_autoload_thread, from_autoload_thread = Queue.new, Queue.new
+ ScratchPad.record -> {
+ from_autoload_thread.push check.call
+ to_autoload_thread.pop
+ }
+ t = Thread.new {
+ in_loading_thread = from_autoload_thread.pop
+ in_other_thread = check.call
+ to_autoload_thread.push :done
+ [in_loading_thread, in_other_thread]
+ }
+ in_loading_thread, in_other_thread = nil
+ begin
+ ModuleSpecs::Autoload.const_get(const)
+ ensure
+ in_loading_thread, in_other_thread = t.value
+ end
+ after = check.call
+ [before, in_loading_thread, in_other_thread, after]
+ end
+
describe "during the autoload before the constant is assigned" do
before :each do
@path = fixture(__FILE__, "autoload_during_autoload.rb")
@@ -353,58 +373,83 @@ describe "Module#autoload" do
raise unless ModuleSpecs::Autoload.autoload?(:DuringAutoload) == @path
end
- def check_before_during_thread_after(&check)
- before = check.call
- to_autoload_thread, from_autoload_thread = Queue.new, Queue.new
- ScratchPad.record -> {
- from_autoload_thread.push check.call
- to_autoload_thread.pop
- }
- t = Thread.new {
- in_loading_thread = from_autoload_thread.pop
- in_other_thread = check.call
- to_autoload_thread.push :done
- [in_loading_thread, in_other_thread]
- }
- in_loading_thread, in_other_thread = nil
- begin
- ModuleSpecs::Autoload::DuringAutoload
- ensure
- in_loading_thread, in_other_thread = t.value
- end
- after = check.call
- [before, in_loading_thread, in_other_thread, after]
- end
-
it "returns nil in autoload thread and 'constant' otherwise for defined?" do
- results = check_before_during_thread_after {
+ results = check_before_during_thread_after(:DuringAutoload) {
defined?(ModuleSpecs::Autoload::DuringAutoload)
}
results.should == ['constant', nil, 'constant', 'constant']
end
it "keeps the constant in Module#constants" do
- results = check_before_during_thread_after {
+ results = check_before_during_thread_after(:DuringAutoload) {
ModuleSpecs::Autoload.constants(false).include?(:DuringAutoload)
}
results.should == [true, true, true, true]
end
it "returns false in autoload thread and true otherwise for Module#const_defined?" do
- results = check_before_during_thread_after {
+ results = check_before_during_thread_after(:DuringAutoload) {
ModuleSpecs::Autoload.const_defined?(:DuringAutoload, false)
}
results.should == [true, false, true, true]
end
it "returns nil in autoload thread and returns the path in other threads for Module#autoload?" do
- results = check_before_during_thread_after {
+ results = check_before_during_thread_after(:DuringAutoload) {
ModuleSpecs::Autoload.autoload?(:DuringAutoload)
}
results.should == [@path, nil, @path, nil]
end
end
+ describe "during the autoload after the constant is assigned" do
+ before :each do
+ @path = fixture(__FILE__, "autoload_during_autoload_after_define.rb")
+ ModuleSpecs::Autoload.autoload :DuringAutoloadAfterDefine, @path
+ @autoload_location = [__FILE__, __LINE__ - 1]
+ @const_location = [@path, 2]
+ @remove << :DuringAutoloadAfterDefine
+ raise unless ModuleSpecs::Autoload.autoload?(:DuringAutoloadAfterDefine) == @path
+ end
+
+ it "returns 'constant' in both threads" do
+ results = check_before_during_thread_after(:DuringAutoloadAfterDefine) {
+ defined?(ModuleSpecs::Autoload::DuringAutoloadAfterDefine)
+ }
+ results.should == ['constant', 'constant', 'constant', 'constant']
+ end
+
+ it "Module#constants include the autoloaded in both threads" do
+ results = check_before_during_thread_after(:DuringAutoloadAfterDefine) {
+ ModuleSpecs::Autoload.constants(false).include?(:DuringAutoloadAfterDefine)
+ }
+ results.should == [true, true, true, true]
+ end
+
+ it "Module#const_defined? returns true in both threads" do
+ results = check_before_during_thread_after(:DuringAutoloadAfterDefine) {
+ ModuleSpecs::Autoload.const_defined?(:DuringAutoloadAfterDefine, false)
+ }
+ results.should == [true, true, true, true]
+ end
+
+ it "returns nil in autoload thread and returns the path in other threads for Module#autoload?" do
+ results = check_before_during_thread_after(:DuringAutoloadAfterDefine) {
+ ModuleSpecs::Autoload.autoload?(:DuringAutoloadAfterDefine)
+ }
+ results.should == [@path, nil, @path, nil]
+ end
+
+ ruby_bug("#20188", ""..."3.4") do
+ it "returns the real constant location in autoload thread and returns the autoload location in other threads for Module#const_source_location" do
+ results = check_before_during_thread_after(:DuringAutoloadAfterDefine) {
+ ModuleSpecs::Autoload.const_source_location(:DuringAutoloadAfterDefine)
+ }
+ results.should == [@autoload_location, @const_location, @autoload_location, @const_location]
+ end
+ end
+ end
+
it "does not remove the constant from Module#constants if load fails and keeps it as an autoload" do
ModuleSpecs::Autoload.autoload :Fail, @non_existent
@@ -514,9 +559,7 @@ describe "Module#autoload" do
it "does not load the file when accessing the constants table of the module" do
ModuleSpecs::Autoload.autoload :P, @non_existent
ModuleSpecs::Autoload.const_defined?(:P).should be_true
- ruby_bug "[Bug #15780]", ""..."2.7" do
- ModuleSpecs::Autoload.const_defined?("P").should be_true
- end
+ ModuleSpecs::Autoload.const_defined?("P").should be_true
end
it "loads the file when opening a module that is the autoloaded constant" do
@@ -581,6 +624,36 @@ describe "Module#autoload" do
end
end
+ ruby_version_is "3.2" do
+ it "warns once in verbose mode if the constant was defined in a parent scope" do
+ ScratchPad.record -> {
+ ModuleSpecs::DeclaredInCurrentDefinedInParent = :declared_in_current_defined_in_parent
+ }
+
+ module ModuleSpecs
+ module Autoload
+ autoload :DeclaredInCurrentDefinedInParent, fixture(__FILE__, "autoload_callback.rb")
+ self.autoload?(:DeclaredInCurrentDefinedInParent).should == fixture(__FILE__, "autoload_callback.rb")
+ const_defined?(:DeclaredInCurrentDefinedInParent).should == true
+
+ -> {
+ DeclaredInCurrentDefinedInParent
+ }.should complain(
+ /Expected .*autoload_callback.rb to define ModuleSpecs::Autoload::DeclaredInCurrentDefinedInParent but it didn't/,
+ verbose: true,
+ )
+
+ -> {
+ DeclaredInCurrentDefinedInParent
+ }.should_not complain(/.*/, verbose: true)
+ self.autoload?(:DeclaredInCurrentDefinedInParent).should == nil
+ const_defined?(:DeclaredInCurrentDefinedInParent).should == false
+ ModuleSpecs.const_defined?(:DeclaredInCurrentDefinedInParent).should == true
+ end
+ end
+ end
+ end
+
ruby_version_is "3.1" do
it "looks up in parent scope after failed autoload" do
@remove << :DeclaredInCurrentDefinedInParent
diff --git a/spec/ruby/core/module/class_variables_spec.rb b/spec/ruby/core/module/class_variables_spec.rb
index fd7aa93aa8..e155f1deac 100644
--- a/spec/ruby/core/module/class_variables_spec.rb
+++ b/spec/ruby/core/module/class_variables_spec.rb
@@ -23,4 +23,12 @@ describe "Module#class_variables" do
c.extend ModuleSpecs::MVars
c.class_variables.should_not include(:@@mvar)
end
+
+ it "returns the correct class variables when inherit is given" do
+ ModuleSpecs::SubCVars.class_variables(false).should == [:@@sub]
+ ModuleSpecs::SubCVars.new.singleton_class.class_variables(false).should == []
+
+ ModuleSpecs::SubCVars.class_variables(true).should == [:@@sub, :@@cls, :@@meta]
+ ModuleSpecs::SubCVars.new.singleton_class.class_variables(true).should == [:@@sub, :@@cls, :@@meta]
+ end
end
diff --git a/spec/ruby/core/module/const_added_spec.rb b/spec/ruby/core/module/const_added_spec.rb
index 31ac6eb105..f9edda3a07 100644
--- a/spec/ruby/core/module/const_added_spec.rb
+++ b/spec/ruby/core/module/const_added_spec.rb
@@ -121,5 +121,40 @@ describe "Module#const_added" do
ScratchPad.recorded.should == [line + 2, line + 4, line + 7, line + 11]
end
+
+ it "is called when the constant is already assigned a value" do
+ ScratchPad.record []
+
+ mod = Module.new do
+ def self.const_added(name)
+ ScratchPad.record const_get(name)
+ end
+ end
+
+ mod.module_eval(<<-RUBY, __FILE__, __LINE__ + 1)
+ TEST = 123
+ RUBY
+
+ ScratchPad.recorded.should == 123
+ end
+
+ it "records re-definition of existing constants" do
+ ScratchPad.record []
+
+ mod = Module.new do
+ def self.const_added(name)
+ ScratchPad << const_get(name)
+ end
+ end
+
+ -> {
+ mod.module_eval(<<-RUBY, __FILE__, __LINE__ + 1)
+ TEST = 123
+ TEST = 456
+ RUBY
+ }.should complain(/warning: already initialized constant .+::TEST/)
+
+ ScratchPad.recorded.should == [123, 456]
+ end
end
end
diff --git a/spec/ruby/core/module/const_defined_spec.rb b/spec/ruby/core/module/const_defined_spec.rb
index 75730395e8..027cf5a245 100644
--- a/spec/ruby/core/module/const_defined_spec.rb
+++ b/spec/ruby/core/module/const_defined_spec.rb
@@ -17,11 +17,16 @@ describe "Module#const_defined?" do
ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST4).should be_true
end
- it "returns true if the constant is defined in a mixed-in module of the receiver" do
+ it "returns true if the constant is defined in a mixed-in module of the receiver's parent" do
# CS_CONST10 is defined in a module included by ChildA
ConstantSpecs::ContainerA::ChildA.const_defined?(:CS_CONST10).should be_true
end
+ it "returns true if the constant is defined in a mixed-in module (with prepends) of the receiver" do
+ # CS_CONST11 is defined in the module included by ContainerPrepend
+ ConstantSpecs::ContainerPrepend.const_defined?(:CS_CONST11).should be_true
+ end
+
it "returns true if the constant is defined in Object and the receiver is a module" do
# CS_CONST1 is defined in Object
ConstantSpecs::ModuleA.const_defined?(:CS_CONST1).should be_true
@@ -75,10 +80,23 @@ describe "Module#const_defined?" do
ConstantSpecs::ClassA.const_defined?(:CS_CONSTX).should == false
end
- it "calls #to_str to convert the given name to a String" do
- name = mock("ClassA")
- name.should_receive(:to_str).and_return("ClassA")
- ConstantSpecs.const_defined?(name).should == true
+ describe "converts the given name to a String using #to_str" do
+ it "calls #to_str to convert the given name to a String" do
+ name = mock("ClassA")
+ name.should_receive(:to_str).and_return("ClassA")
+ ConstantSpecs.const_defined?(name).should == true
+ end
+
+ it "raises a TypeError if the given name can't be converted to a String" do
+ -> { ConstantSpecs.const_defined?(nil) }.should raise_error(TypeError)
+ -> { ConstantSpecs.const_defined?([]) }.should raise_error(TypeError)
+ end
+
+ it "raises a NoMethodError if the given argument raises a NoMethodError during type coercion to a String" do
+ name = mock("classA")
+ name.should_receive(:to_str).and_raise(NoMethodError)
+ -> { ConstantSpecs.const_defined?(name) }.should raise_error(NoMethodError)
+ end
end
it "special cases Object and checks it's included Modules" do
diff --git a/spec/ruby/core/module/const_get_spec.rb b/spec/ruby/core/module/const_get_spec.rb
index 9f9fafe5bb..0233118f4b 100644
--- a/spec/ruby/core/module/const_get_spec.rb
+++ b/spec/ruby/core/module/const_get_spec.rb
@@ -100,6 +100,16 @@ describe "Module#const_get" do
ConstantSpecs.const_get("::CS_CONST1").should == :const1
end
+ it "accepts a toplevel scope qualifier when inherit is false" do
+ ConstantSpecs.const_get("::CS_CONST1", false).should == :const1
+ -> { ConstantSpecs.const_get("CS_CONST1", false) }.should raise_error(NameError)
+ end
+
+ it "returns a constant whose module is defined the toplevel" do
+ ConstantSpecs.const_get("ConstantSpecsTwo::Foo").should == :cs_two_foo
+ ConstantSpecsThree.const_get("ConstantSpecsTwo::Foo").should == :cs_three_foo
+ end
+
it "accepts a scoped constant name" do
ConstantSpecs.const_get("ClassA::CS_CONST10").should == :const10_10
end
@@ -140,6 +150,10 @@ describe "Module#const_get" do
Object.const_get('CSAutoloadD::InnerModule').name.should == 'CSAutoloadD::InnerModule'
end
+ it "raises a NameError when the nested constant does not exist on the module but exists in Object" do
+ -> { Object.const_get('ConstantSpecs::CS_CONST1') }.should raise_error(NameError)
+ end
+
describe "with statically assigned constants" do
it "searches the immediate class or module first" do
ConstantSpecs::ClassA.const_get(:CS_CONST10).should == :const10_10
diff --git a/spec/ruby/core/module/const_set_spec.rb b/spec/ruby/core/module/const_set_spec.rb
index ba7810d17b..5bdfd7b68f 100644
--- a/spec/ruby/core/module/const_set_spec.rb
+++ b/spec/ruby/core/module/const_set_spec.rb
@@ -20,20 +20,10 @@ describe "Module#const_set" do
m.name.should == "ConstantSpecs::CS_CONST1000"
end
- ruby_version_is ""..."3.0" do
- it "does not set the name of a module scoped by an anonymous module" do
- a, b = Module.new, Module.new
- a.const_set :B, b
- b.name.should be_nil
- end
- end
-
- ruby_version_is "3.0" do
- it "sets the name of a module scoped by an anonymous module" do
- a, b = Module.new, Module.new
- a.const_set :B, b
- b.name.should.end_with? '::B'
- end
+ it "sets the name of a module scoped by an anonymous module" do
+ a, b = Module.new, Module.new
+ a.const_set :B, b
+ b.name.should.end_with? '::B'
end
it "sets the name of contained modules when assigning a toplevel anonymous module" do
diff --git a/spec/ruby/core/module/const_source_location_spec.rb b/spec/ruby/core/module/const_source_location_spec.rb
index 9e1f2c1c49..c194c9113f 100644
--- a/spec/ruby/core/module/const_source_location_spec.rb
+++ b/spec/ruby/core/module/const_source_location_spec.rb
@@ -6,214 +6,243 @@ describe "Module#const_source_location" do
@constants_fixture_path = File.expand_path('../../fixtures/constants.rb', __dir__)
end
- ruby_version_is "2.7" do
- describe "with dynamically assigned constants" do
- it "searches a path in the immediate class or module first" do
- ConstantSpecs::ClassA::CSL_CONST301 = :const301_1
- ConstantSpecs::ClassA.const_source_location(:CSL_CONST301).should == [__FILE__, __LINE__ - 1]
+ describe "with dynamically assigned constants" do
+ it "searches a path in the immediate class or module first" do
+ ConstantSpecs::ClassA::CSL_CONST301 = :const301_1
+ ConstantSpecs::ClassA.const_source_location(:CSL_CONST301).should == [__FILE__, __LINE__ - 1]
- ConstantSpecs::ModuleA::CSL_CONST301 = :const301_2
- ConstantSpecs::ModuleA.const_source_location(:CSL_CONST301).should == [__FILE__, __LINE__ - 1]
+ ConstantSpecs::ModuleA::CSL_CONST301 = :const301_2
+ ConstantSpecs::ModuleA.const_source_location(:CSL_CONST301).should == [__FILE__, __LINE__ - 1]
- ConstantSpecs::ParentA::CSL_CONST301 = :const301_3
- ConstantSpecs::ParentA.const_source_location(:CSL_CONST301).should == [__FILE__, __LINE__ - 1]
+ ConstantSpecs::ParentA::CSL_CONST301 = :const301_3
+ ConstantSpecs::ParentA.const_source_location(:CSL_CONST301).should == [__FILE__, __LINE__ - 1]
- ConstantSpecs::ContainerA::ChildA::CSL_CONST301 = :const301_5
- ConstantSpecs::ContainerA::ChildA.const_source_location(:CSL_CONST301).should == [__FILE__, __LINE__ - 1]
- end
-
- it "searches a path in a module included in the immediate class before the superclass" do
- ConstantSpecs::ParentB::CSL_CONST302 = :const302_1
- ConstantSpecs::ModuleF::CSL_CONST302 = :const302_2
- ConstantSpecs::ContainerB::ChildB.const_source_location(:CSL_CONST302).should == [__FILE__, __LINE__ - 1]
- end
-
- it "searches a path in the superclass before a module included in the superclass" do
- ConstantSpecs::ModuleE::CSL_CONST303 = :const303_1
- ConstantSpecs::ParentB::CSL_CONST303 = :const303_2
- ConstantSpecs::ContainerB::ChildB.const_source_location(:CSL_CONST303).should == [__FILE__, __LINE__ - 1]
- end
-
- it "searches a path in a module included in the superclass" do
- ConstantSpecs::ModuleA::CSL_CONST304 = :const304_1
- ConstantSpecs::ModuleE::CSL_CONST304 = :const304_2
- ConstantSpecs::ContainerB::ChildB.const_source_location(:CSL_CONST304).should == [__FILE__, __LINE__ - 1]
- end
-
- it "searches a path in the superclass chain" do
- ConstantSpecs::ModuleA::CSL_CONST305 = :const305
- ConstantSpecs::ContainerB::ChildB.const_source_location(:CSL_CONST305).should == [__FILE__, __LINE__ - 1]
- end
-
- it "returns path to a toplevel constant when the receiver is a Class" do
- Object::CSL_CONST306 = :const306
- ConstantSpecs::ContainerB::ChildB.const_source_location(:CSL_CONST306).should == [__FILE__, __LINE__ - 1]
- end
-
- it "returns path to a toplevel constant when the receiver is a Module" do
- Object::CSL_CONST308 = :const308
- ConstantSpecs.const_source_location(:CSL_CONST308).should == [__FILE__, __LINE__ - 1]
- ConstantSpecs::ModuleA.const_source_location(:CSL_CONST308).should == [__FILE__, __LINE__ - 2]
- end
+ ConstantSpecs::ContainerA::ChildA::CSL_CONST301 = :const301_5
+ ConstantSpecs::ContainerA::ChildA.const_source_location(:CSL_CONST301).should == [__FILE__, __LINE__ - 1]
+ end
- it "returns path to the updated value of a constant" do
- ConstantSpecs::ClassB::CSL_CONST309 = :const309_1
- ConstantSpecs::ClassB.const_source_location(:CSL_CONST309).should == [__FILE__, __LINE__ - 1]
+ it "searches a path in a module included in the immediate class before the superclass" do
+ ConstantSpecs::ParentB::CSL_CONST302 = :const302_1
+ ConstantSpecs::ModuleF::CSL_CONST302 = :const302_2
+ ConstantSpecs::ContainerB::ChildB.const_source_location(:CSL_CONST302).should == [__FILE__, __LINE__ - 1]
+ end
- -> {
- ConstantSpecs::ClassB::CSL_CONST309 = :const309_2
- }.should complain(/already initialized constant/)
- ConstantSpecs::ClassB.const_source_location(:CSL_CONST309).should == [__FILE__, __LINE__ - 2]
- end
+ it "searches a path in the superclass before a module included in the superclass" do
+ ConstantSpecs::ModuleE::CSL_CONST303 = :const303_1
+ ConstantSpecs::ParentB::CSL_CONST303 = :const303_2
+ ConstantSpecs::ContainerB::ChildB.const_source_location(:CSL_CONST303).should == [__FILE__, __LINE__ - 1]
end
- describe "with statically assigned constants" do
- it "searches location path the immediate class or module first" do
- ConstantSpecs::ClassA.const_source_location(:CS_CONST10).should == [@constants_fixture_path, ConstantSpecs::ClassA::CS_CONST10_LINE]
- ConstantSpecs::ModuleA.const_source_location(:CS_CONST10).should == [@constants_fixture_path, ConstantSpecs::ModuleA::CS_CONST10_LINE]
- ConstantSpecs::ParentA.const_source_location(:CS_CONST10).should == [@constants_fixture_path, ConstantSpecs::ParentA::CS_CONST10_LINE]
- ConstantSpecs::ContainerA.const_source_location(:CS_CONST10).should == [@constants_fixture_path, ConstantSpecs::ContainerA::CS_CONST10_LINE]
- ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST10).should == [@constants_fixture_path, ConstantSpecs::ContainerA::ChildA::CS_CONST10_LINE]
- end
+ it "searches a path in a module included in the superclass" do
+ ConstantSpecs::ModuleA::CSL_CONST304 = :const304_1
+ ConstantSpecs::ModuleE::CSL_CONST304 = :const304_2
+ ConstantSpecs::ContainerB::ChildB.const_source_location(:CSL_CONST304).should == [__FILE__, __LINE__ - 1]
+ end
- it "searches location path a module included in the immediate class before the superclass" do
- ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST15).should == [@constants_fixture_path, ConstantSpecs::ModuleC::CS_CONST15_LINE]
- end
+ it "searches a path in the superclass chain" do
+ ConstantSpecs::ModuleA::CSL_CONST305 = :const305
+ ConstantSpecs::ContainerB::ChildB.const_source_location(:CSL_CONST305).should == [__FILE__, __LINE__ - 1]
+ end
- it "searches location path the superclass before a module included in the superclass" do
- ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST11).should == [@constants_fixture_path, ConstantSpecs::ParentA::CS_CONST11_LINE]
- end
+ it "returns path to a toplevel constant when the receiver is a Class" do
+ Object::CSL_CONST306 = :const306
+ ConstantSpecs::ContainerB::ChildB.const_source_location(:CSL_CONST306).should == [__FILE__, __LINE__ - 1]
+ end
- it "searches location path a module included in the superclass" do
- ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST12).should == [@constants_fixture_path, ConstantSpecs::ModuleB::CS_CONST12_LINE]
- end
+ it "returns path to a toplevel constant when the receiver is a Module" do
+ Object::CSL_CONST308 = :const308
+ ConstantSpecs.const_source_location(:CSL_CONST308).should == [__FILE__, __LINE__ - 1]
+ ConstantSpecs::ModuleA.const_source_location(:CSL_CONST308).should == [__FILE__, __LINE__ - 2]
+ end
- it "searches location path the superclass chain" do
- ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST13).should == [@constants_fixture_path, ConstantSpecs::ModuleA::CS_CONST13_LINE]
- end
+ it "returns path to the updated value of a constant" do
+ ConstantSpecs::ClassB::CSL_CONST309 = :const309_1
+ ConstantSpecs::ClassB.const_source_location(:CSL_CONST309).should == [__FILE__, __LINE__ - 1]
- it "returns location path a toplevel constant when the receiver is a Class" do
- ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST1).should == [@constants_fixture_path, CS_CONST1_LINE]
- end
+ -> {
+ ConstantSpecs::ClassB::CSL_CONST309 = :const309_2
+ }.should complain(/already initialized constant/)
+ ConstantSpecs::ClassB.const_source_location(:CSL_CONST309).should == [__FILE__, __LINE__ - 2]
+ end
+ end
- it "returns location path a toplevel constant when the receiver is a Module" do
- ConstantSpecs.const_source_location(:CS_CONST1).should == [@constants_fixture_path, CS_CONST1_LINE]
- ConstantSpecs::ModuleA.const_source_location(:CS_CONST1).should == [@constants_fixture_path, CS_CONST1_LINE]
- end
+ describe "with statically assigned constants" do
+ it "works for the module and class keywords" do
+ ConstantSpecs.const_source_location(:ModuleB).should == [@constants_fixture_path, ConstantSpecs::ModuleB::LINE]
+ ConstantSpecs.const_source_location(:ClassA).should == [@constants_fixture_path, ConstantSpecs::ClassA::LINE]
end
- it "return empty path if constant defined in C code" do
- Object.const_source_location(:String).should == []
+ it "searches location path the immediate class or module first" do
+ ConstantSpecs::ClassA.const_source_location(:CS_CONST10).should == [@constants_fixture_path, ConstantSpecs::ClassA::CS_CONST10_LINE]
+ ConstantSpecs::ModuleA.const_source_location(:CS_CONST10).should == [@constants_fixture_path, ConstantSpecs::ModuleA::CS_CONST10_LINE]
+ ConstantSpecs::ParentA.const_source_location(:CS_CONST10).should == [@constants_fixture_path, ConstantSpecs::ParentA::CS_CONST10_LINE]
+ ConstantSpecs::ContainerA.const_source_location(:CS_CONST10).should == [@constants_fixture_path, ConstantSpecs::ContainerA::CS_CONST10_LINE]
+ ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST10).should == [@constants_fixture_path, ConstantSpecs::ContainerA::ChildA::CS_CONST10_LINE]
end
- it "accepts a String or Symbol name" do
- Object.const_source_location(:CS_CONST1).should == [@constants_fixture_path, CS_CONST1_LINE]
- Object.const_source_location("CS_CONST1").should == [@constants_fixture_path, CS_CONST1_LINE]
+ it "searches location path a module included in the immediate class before the superclass" do
+ ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST15).should == [@constants_fixture_path, ConstantSpecs::ModuleC::CS_CONST15_LINE]
end
- it "returns nil if no constant is defined in the search path" do
- ConstantSpecs.const_source_location(:CS_CONSTX).should == nil
+ it "searches location path the superclass before a module included in the superclass" do
+ ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST11).should == [@constants_fixture_path, ConstantSpecs::ParentA::CS_CONST11_LINE]
end
- it "raises a NameError if the name does not start with a capital letter" do
- -> { ConstantSpecs.const_source_location "name" }.should raise_error(NameError)
+ it "searches location path a module included in the superclass" do
+ ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST12).should == [@constants_fixture_path, ConstantSpecs::ModuleB::CS_CONST12_LINE]
end
- it "raises a NameError if the name starts with a non-alphabetic character" do
- -> { ConstantSpecs.const_source_location "__CONSTX__" }.should raise_error(NameError)
- -> { ConstantSpecs.const_source_location "@CS_CONST1" }.should raise_error(NameError)
- -> { ConstantSpecs.const_source_location "!CS_CONST1" }.should raise_error(NameError)
+ it "searches location path the superclass chain" do
+ ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST13).should == [@constants_fixture_path, ConstantSpecs::ModuleA::CS_CONST13_LINE]
end
- it "raises a NameError if the name contains non-alphabetic characters except '_'" do
- Object.const_source_location("CS_CONST1").should == [@constants_fixture_path, CS_CONST1_LINE]
- -> { ConstantSpecs.const_source_location "CS_CONST1=" }.should raise_error(NameError)
- -> { ConstantSpecs.const_source_location "CS_CONST1?" }.should raise_error(NameError)
+ it "returns location path a toplevel constant when the receiver is a Class" do
+ ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST1).should == [@constants_fixture_path, CS_CONST1_LINE]
end
- it "calls #to_str to convert the given name to a String" do
- name = mock("ClassA")
- name.should_receive(:to_str).and_return("ClassA")
- ConstantSpecs.const_source_location(name).should == [@constants_fixture_path, ConstantSpecs::ClassA::CS_CLASS_A_LINE]
+ it "returns location path a toplevel constant when the receiver is a Module" do
+ ConstantSpecs.const_source_location(:CS_CONST1).should == [@constants_fixture_path, CS_CONST1_LINE]
+ ConstantSpecs::ModuleA.const_source_location(:CS_CONST1).should == [@constants_fixture_path, CS_CONST1_LINE]
end
+ end
- it "raises a TypeError if conversion to a String by calling #to_str fails" do
- name = mock('123')
- -> { ConstantSpecs.const_source_location(name) }.should raise_error(TypeError)
+ it "return empty path if constant defined in C code" do
+ Object.const_source_location(:String).should == []
+ end
- name.should_receive(:to_str).and_return(123)
- -> { ConstantSpecs.const_source_location(name) }.should raise_error(TypeError)
- end
+ it "accepts a String or Symbol name" do
+ Object.const_source_location(:CS_CONST1).should == [@constants_fixture_path, CS_CONST1_LINE]
+ Object.const_source_location("CS_CONST1").should == [@constants_fixture_path, CS_CONST1_LINE]
+ end
- it "does not search the singleton class of a Class or Module" do
- ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST14).should == nil
- ConstantSpecs.const_source_location(:CS_CONST14).should == nil
- end
+ it "returns nil if no constant is defined in the search path" do
+ ConstantSpecs.const_source_location(:CS_CONSTX).should == nil
+ end
- it "does not search the containing scope" do
- ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST20).should == [@constants_fixture_path, ConstantSpecs::ParentA::CS_CONST20_LINE]
- ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST5) == nil
- end
+ it "raises a NameError if the name does not start with a capital letter" do
+ -> { ConstantSpecs.const_source_location "name" }.should raise_error(NameError)
+ end
- it "returns nil if the constant is defined in the receiver's superclass and the inherit flag is false" do
- ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST4, false).should == nil
- end
+ it "raises a NameError if the name starts with a non-alphabetic character" do
+ -> { ConstantSpecs.const_source_location "__CONSTX__" }.should raise_error(NameError)
+ -> { ConstantSpecs.const_source_location "@CS_CONST1" }.should raise_error(NameError)
+ -> { ConstantSpecs.const_source_location "!CS_CONST1" }.should raise_error(NameError)
+ end
- it "searches into the receiver superclasses if the inherit flag is true" do
- ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST4, true).should == [@constants_fixture_path, ConstantSpecs::ParentA::CS_CONST4_LINE]
- end
+ it "raises a NameError if the name contains non-alphabetic characters except '_'" do
+ Object.const_source_location("CS_CONST1").should == [@constants_fixture_path, CS_CONST1_LINE]
+ -> { ConstantSpecs.const_source_location "CS_CONST1=" }.should raise_error(NameError)
+ -> { ConstantSpecs.const_source_location "CS_CONST1?" }.should raise_error(NameError)
+ end
- it "returns nil when the receiver is a Module, the constant is defined at toplevel and the inherit flag is false" do
- ConstantSpecs::ModuleA.const_source_location(:CS_CONST1, false).should == nil
- end
+ it "calls #to_str to convert the given name to a String" do
+ name = mock("ClassA")
+ name.should_receive(:to_str).and_return("ClassA")
+ ConstantSpecs.const_source_location(name).should == [@constants_fixture_path, ConstantSpecs::ClassA::LINE]
+ end
- it "returns nil when the receiver is a Class, the constant is defined at toplevel and the inherit flag is false" do
- ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST1, false).should == nil
- end
+ it "raises a TypeError if conversion to a String by calling #to_str fails" do
+ name = mock('123')
+ -> { ConstantSpecs.const_source_location(name) }.should raise_error(TypeError)
- it "accepts a toplevel scope qualifier" do
- ConstantSpecs.const_source_location("::CS_CONST1").should == [@constants_fixture_path, CS_CONST1_LINE]
- end
+ name.should_receive(:to_str).and_return(123)
+ -> { ConstantSpecs.const_source_location(name) }.should raise_error(TypeError)
+ end
- it "accepts a scoped constant name" do
- ConstantSpecs.const_source_location("ClassA::CS_CONST10").should == [@constants_fixture_path, ConstantSpecs::ClassA::CS_CONST10_LINE]
- end
+ it "does not search the singleton class of a Class or Module" do
+ ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST14).should == nil
+ ConstantSpecs.const_source_location(:CS_CONST14).should == nil
+ end
- it "raises a NameError if the name includes two successive scope separators" do
- -> { ConstantSpecs.const_source_location("ClassA::::CS_CONST10") }.should raise_error(NameError)
- end
+ it "does not search the containing scope" do
+ ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST20).should == [@constants_fixture_path, ConstantSpecs::ParentA::CS_CONST20_LINE]
+ ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST5) == nil
+ end
- it "raises a NameError if only '::' is passed" do
- -> { ConstantSpecs.const_source_location("::") }.should raise_error(NameError)
- end
+ it "returns nil if the constant is defined in the receiver's superclass and the inherit flag is false" do
+ ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST4, false).should == nil
+ end
+
+ it "searches into the receiver superclasses if the inherit flag is true" do
+ ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST4, true).should == [@constants_fixture_path, ConstantSpecs::ParentA::CS_CONST4_LINE]
+ end
- it "raises a NameError if a Symbol has a toplevel scope qualifier" do
- -> { ConstantSpecs.const_source_location(:'::CS_CONST1') }.should raise_error(NameError)
+ it "returns nil when the receiver is a Module, the constant is defined at toplevel and the inherit flag is false" do
+ ConstantSpecs::ModuleA.const_source_location(:CS_CONST1, false).should == nil
+ end
+
+ it "returns nil when the receiver is a Class, the constant is defined at toplevel and the inherit flag is false" do
+ ConstantSpecs::ContainerA::ChildA.const_source_location(:CS_CONST1, false).should == nil
+ end
+
+ it "accepts a toplevel scope qualifier" do
+ ConstantSpecs.const_source_location("::CS_CONST1").should == [@constants_fixture_path, CS_CONST1_LINE]
+ end
+
+ it "accepts a scoped constant name" do
+ ConstantSpecs.const_source_location("ClassA::CS_CONST10").should == [@constants_fixture_path, ConstantSpecs::ClassA::CS_CONST10_LINE]
+ end
+
+ it "returns updated location from const_set" do
+ mod = Module.new
+ const_line = __LINE__ + 1
+ mod.const_set :Foo, 1
+ mod.const_source_location(:Foo).should == [__FILE__, const_line]
+ end
+
+ it "raises a NameError if the name includes two successive scope separators" do
+ -> { ConstantSpecs.const_source_location("ClassA::::CS_CONST10") }.should raise_error(NameError)
+ end
+
+ it "raises a NameError if only '::' is passed" do
+ -> { ConstantSpecs.const_source_location("::") }.should raise_error(NameError)
+ end
+
+ it "raises a NameError if a Symbol has a toplevel scope qualifier" do
+ -> { ConstantSpecs.const_source_location(:'::CS_CONST1') }.should raise_error(NameError)
+ end
+
+ it "raises a NameError if a Symbol is a scoped constant name" do
+ -> { ConstantSpecs.const_source_location(:'ClassA::CS_CONST10') }.should raise_error(NameError)
+ end
+
+ it "does search private constants path" do
+ ConstantSpecs.const_source_location(:CS_PRIVATE).should == [@constants_fixture_path, ConstantSpecs::CS_PRIVATE_LINE]
+ end
+
+ it "works for eval with a given line" do
+ c = Class.new do
+ eval('self::C = 1', nil, "foo", 100)
end
+ c.const_source_location(:C).should == ["foo", 100]
+ end
- it "raises a NameError if a Symbol is a scoped constant name" do
- -> { ConstantSpecs.const_source_location(:'ClassA::CS_CONST10') }.should raise_error(NameError)
+ context 'autoload' do
+ before :all do
+ ConstantSpecs.autoload :CSL_CONST1, "#{__dir__}/notexisting.rb"
+ @line = __LINE__ - 1
end
- it "does search private constants path" do
- ConstantSpecs.const_source_location(:CS_PRIVATE).should == [@constants_fixture_path, ConstantSpecs::CS_PRIVATE_LINE]
+ it 'returns the autoload location while not resolved' do
+ ConstantSpecs.const_source_location('CSL_CONST1').should == [__FILE__, @line]
end
- context 'autoload' do
- before :all do
- ConstantSpecs.autoload :CSL_CONST1, "#{__dir__}/notexisting.rb"
- @line = __LINE__ - 1
- end
+ it 'returns where the constant was resolved when resolved' do
+ file = fixture(__FILE__, 'autoload_location.rb')
+ ConstantSpecs.autoload :CONST_LOCATION, file
+ line = ConstantSpecs::CONST_LOCATION
+ ConstantSpecs.const_source_location('CONST_LOCATION').should == [file, line]
+ end
- it 'returns the autoload location while not resolved' do
- ConstantSpecs.const_source_location('CSL_CONST1').should == [__FILE__, @line]
- end
+ ruby_bug("#20188", ""..."3.4") do
+ it 'returns the real constant location as soon as it is defined' do
+ file = fixture(__FILE__, 'autoload_const_source_location.rb')
+ ConstantSpecs.autoload :ConstSource, file
+ autoload_location = [__FILE__, __LINE__ - 1]
- it 'returns where the constant was resolved when resolved' do
- file = fixture(__FILE__, 'autoload_location.rb')
- ConstantSpecs.autoload :CONST_LOCATION, file
- line = ConstantSpecs::CONST_LOCATION
- ConstantSpecs.const_source_location('CONST_LOCATION').should == [file, line]
+ ConstantSpecs.const_source_location(:ConstSource).should == autoload_location
+ ConstantSpecs::ConstSource::LOCATION.should == ConstantSpecs.const_source_location(:ConstSource)
+ ConstantSpecs::BEFORE_DEFINE_LOCATION.should == autoload_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 c65b30de24..e04bb87ceb 100644
--- a/spec/ruby/core/module/define_method_spec.rb
+++ b/spec/ruby/core/module/define_method_spec.rb
@@ -133,6 +133,17 @@ describe "Module#define_method when name is not a special private name" do
klass.should have_public_instance_method(:baz)
end
end
+
+ it "sets the method owner for a dynamically added method with a different original owner" do
+ mixin_module = Module.new do
+ def bar; end
+ end
+
+ foo = Object.new
+ foo.singleton_class.define_method(:bar, mixin_module.instance_method(:bar))
+
+ foo.method(:bar).owner.should == foo.singleton_class
+ end
end
describe "passed a block" do
@@ -219,18 +230,55 @@ describe "Module#define_method" do
o.block_test2.should == o
end
+ it "raises TypeError if name cannot converted to String" do
+ -> {
+ Class.new { define_method(1001, -> {}) }
+ }.should raise_error(TypeError, /is not a symbol nor a string/)
+
+ -> {
+ Class.new { define_method([], -> {}) }
+ }.should raise_error(TypeError, /is not a symbol nor a string/)
+ end
+
+ it "converts non-String name to String with #to_str" do
+ obj = Object.new
+ def obj.to_str() "foo" end
+
+ new_class = Class.new { define_method(obj, -> { :called }) }
+ new_class.new.foo.should == :called
+ end
+
+ it "raises TypeError when #to_str called on non-String name returns non-String value" do
+ obj = Object.new
+ def obj.to_str() [] end
+
+ -> {
+ Class.new { define_method(obj, -> {}) }
+ }.should raise_error(TypeError, /can't convert Object to String/)
+ end
+
it "raises a TypeError when the given method is no Method/Proc" do
-> {
Class.new { define_method(:test, "self") }
- }.should raise_error(TypeError)
+ }.should raise_error(TypeError, "wrong argument type String (expected Proc/Method/UnboundMethod)")
-> {
Class.new { define_method(:test, 1234) }
- }.should raise_error(TypeError)
+ }.should raise_error(TypeError, "wrong argument type Integer (expected Proc/Method/UnboundMethod)")
-> {
Class.new { define_method(:test, nil) }
- }.should raise_error(TypeError)
+ }.should raise_error(TypeError, "wrong argument type NilClass (expected Proc/Method/UnboundMethod)")
+ end
+
+ it "uses provided Method/Proc even if block is specified" do
+ new_class = Class.new do
+ define_method(:test, -> { :method_is_called }) do
+ :block_is_called
+ end
+ end
+
+ new_class.new.test.should == :method_is_called
end
it "raises an ArgumentError when no block is given" do
@@ -451,6 +499,33 @@ describe "Module#define_method" do
Class.new { define_method :bar, m }
}.should raise_error(TypeError, /can't bind singleton method to a different class/)
end
+
+ it "defines a new method with public visibility when a Method passed and the class/module of the context isn't equal to the receiver of #define_method" do
+ c = Class.new do
+ private def foo
+ "public"
+ end
+ end
+
+ object = c.new
+ object.singleton_class.define_method(:bar, object.method(:foo))
+
+ object.bar.should == "public"
+ end
+
+ it "defines the new method according to the scope visibility when a Method passed and the class/module of the context is equal to the receiver of #define_method" do
+ c = Class.new do
+ def foo; end
+ end
+
+ object = c.new
+ object.singleton_class.class_eval do
+ private
+ define_method(:bar, c.new.method(:foo))
+ end
+
+ -> { object.bar }.should raise_error(NoMethodError)
+ end
end
describe "Module#define_method" do
@@ -649,7 +724,7 @@ describe "Module#define_method" do
end
end
-describe "Method#define_method when passed a Method object" do
+describe "Module#define_method when passed a Method object" do
before :each do
@klass = Class.new do
def m(a, b, *c)
@@ -674,7 +749,7 @@ describe "Method#define_method when passed a Method object" do
end
end
-describe "Method#define_method when passed an UnboundMethod object" do
+describe "Module#define_method when passed an UnboundMethod object" do
before :each do
@klass = Class.new do
def m(a, b, *c)
@@ -699,7 +774,7 @@ describe "Method#define_method when passed an UnboundMethod object" do
end
end
-describe "Method#define_method when passed a Proc object" do
+describe "Module#define_method when passed a Proc object" do
describe "and a method is defined inside" do
it "defines the nested method in the default definee where the Proc was created" do
prc = nil
@@ -724,7 +799,7 @@ describe "Method#define_method when passed a Proc object" do
end
end
-describe "Method#define_method when passed a block" do
+describe "Module#define_method when passed a block" do
describe "behaves exactly like a lambda" do
it "for return" do
Class.new do
diff --git a/spec/ruby/core/module/deprecate_constant_spec.rb b/spec/ruby/core/module/deprecate_constant_spec.rb
index faacbea03e..aabef934c4 100644
--- a/spec/ruby/core/module/deprecate_constant_spec.rb
+++ b/spec/ruby/core/module/deprecate_constant_spec.rb
@@ -31,17 +31,15 @@ describe "Module#deprecate_constant" do
-> { @module.const_get :PRIVATE }.should complain(/warning: constant .+::PRIVATE is deprecated/)
end
- ruby_version_is '2.7' do
- it "does not warn if Warning[:deprecated] is false" do
- @module.deprecate_constant :PUBLIC1
-
- deprecated = Warning[:deprecated]
- begin
- Warning[:deprecated] = false
- -> { @module::PUBLIC1 }.should_not complain
- ensure
- Warning[:deprecated] = deprecated
- end
+ it "does not warn if Warning[:deprecated] is false" do
+ @module.deprecate_constant :PUBLIC1
+
+ deprecated = Warning[:deprecated]
+ begin
+ Warning[:deprecated] = false
+ -> { @module::PUBLIC1 }.should_not complain
+ ensure
+ Warning[:deprecated] = deprecated
end
end
end
diff --git a/spec/ruby/core/module/extend_object_spec.rb b/spec/ruby/core/module/extend_object_spec.rb
index e66b87efef..1fd1abc0b5 100644
--- a/spec/ruby/core/module/extend_object_spec.rb
+++ b/spec/ruby/core/module/extend_object_spec.rb
@@ -42,20 +42,6 @@ describe "Module#extend_object" do
ScratchPad.recorded.should == :extended
end
- ruby_version_is ''...'2.7' do
- it "does not copy own tainted status to the given object" do
- other = Object.new
- Module.new.taint.send :extend_object, other
- other.tainted?.should be_false
- end
-
- it "does not copy own untrusted status to the given object" do
- other = Object.new
- Module.new.untrust.send :extend_object, other
- other.untrusted?.should be_false
- end
- end
-
describe "when given a frozen object" do
before :each do
@receiver = Module.new
diff --git a/spec/ruby/core/module/fixtures/autoload_const_source_location.rb b/spec/ruby/core/module/fixtures/autoload_const_source_location.rb
new file mode 100644
index 0000000000..ee0e5a689f
--- /dev/null
+++ b/spec/ruby/core/module/fixtures/autoload_const_source_location.rb
@@ -0,0 +1,6 @@
+module ConstantSpecs
+ BEFORE_DEFINE_LOCATION = const_source_location(:ConstSource)
+ module ConstSource
+ LOCATION = Object.const_source_location(name)
+ end
+end
diff --git a/spec/ruby/core/module/fixtures/autoload_during_autoload_after_define.rb b/spec/ruby/core/module/fixtures/autoload_during_autoload_after_define.rb
new file mode 100644
index 0000000000..a9d886dfd6
--- /dev/null
+++ b/spec/ruby/core/module/fixtures/autoload_during_autoload_after_define.rb
@@ -0,0 +1,6 @@
+module ModuleSpecs::Autoload
+ class DuringAutoloadAfterDefine
+ block = ScratchPad.recorded
+ ScratchPad.record(block.call)
+ end
+end
diff --git a/spec/ruby/core/module/fixtures/classes.rb b/spec/ruby/core/module/fixtures/classes.rb
index 40777cdbbd..a434e7b0b8 100644
--- a/spec/ruby/core/module/fixtures/classes.rb
+++ b/spec/ruby/core/module/fixtures/classes.rb
@@ -42,6 +42,14 @@ module ModuleSpecs
class LookupChild < Lookup
end
+ module ModuleWithPrepend
+ prepend LookupMod
+ end
+
+ class WithPrependedModule
+ include ModuleWithPrepend
+ end
+
class Parent
# For private_class_method spec
def self.private_method; end
@@ -352,6 +360,10 @@ module ModuleSpecs
end
end
+ class SubCVars < CVars
+ @@sub = :sub
+ end
+
module MVars
@@mvar = :mvar
end
@@ -376,6 +388,7 @@ module ModuleSpecs
# empty modules
module M1; end
module M2; end
+ module M3; end
module Autoload
def self.use_ex1
@@ -583,6 +596,32 @@ module ModuleSpecs
private :foo
end
EmptyFooMethod = m.instance_method(:foo)
+
+ # for undefined_instance_methods spec
+ module UndefinedInstanceMethods
+ module Super
+ def super_included_method; end
+ end
+
+ class Parent
+ def undefed_method; end
+ undef_method :undefed_method
+
+ def parent_method; end
+ def another_parent_method; end
+ end
+
+ class Child < Parent
+ include Super
+
+ undef_method :parent_method
+ undef_method :another_parent_method
+ end
+
+ class Grandchild < Child
+ undef_method :super_included_method
+ end
+ end
end
class Object
diff --git a/spec/ruby/core/module/fixtures/module.rb b/spec/ruby/core/module/fixtures/module.rb
index 9050a272ec..34543ca2b4 100644
--- a/spec/ruby/core/module/fixtures/module.rb
+++ b/spec/ruby/core/module/fixtures/module.rb
@@ -1,4 +1,8 @@
module ModuleSpecs
module Anonymous
+ module Child
+ end
+
+ SameChild = Child
end
end
diff --git a/spec/ruby/core/module/include_spec.rb b/spec/ruby/core/module/include_spec.rb
index c47e052d22..c073bc31ca 100644
--- a/spec/ruby/core/module/include_spec.rb
+++ b/spec/ruby/core/module/include_spec.rb
@@ -104,9 +104,9 @@ describe "Module#include" do
class A; include M; end
class B < A; include M; end
- all = [A,B,M]
+ all = [A, B, M]
- (B.ancestors & all).should == [B, A, M]
+ (B.ancestors.filter { |a| all.include?(a) }).should == [B, A, M]
end
end
diff --git a/spec/ruby/core/module/included_modules_spec.rb b/spec/ruby/core/module/included_modules_spec.rb
index 40e20953f4..ce94ed1285 100644
--- a/spec/ruby/core/module/included_modules_spec.rb
+++ b/spec/ruby/core/module/included_modules_spec.rb
@@ -4,9 +4,11 @@ require_relative 'fixtures/classes'
describe "Module#included_modules" do
it "returns a list of modules included in self" do
ModuleSpecs.included_modules.should == []
+
ModuleSpecs::Child.included_modules.should include(ModuleSpecs::Super, ModuleSpecs::Basic, Kernel)
ModuleSpecs::Parent.included_modules.should include(Kernel)
ModuleSpecs::Basic.included_modules.should == []
ModuleSpecs::Super.included_modules.should include(ModuleSpecs::Basic)
+ ModuleSpecs::WithPrependedModule.included_modules.should include(ModuleSpecs::ModuleWithPrepend)
end
end
diff --git a/spec/ruby/core/module/instance_method_spec.rb b/spec/ruby/core/module/instance_method_spec.rb
index b4d6a0d8c8..8d006e647e 100644
--- a/spec/ruby/core/module/instance_method_spec.rb
+++ b/spec/ruby/core/module/instance_method_spec.rb
@@ -45,20 +45,46 @@ describe "Module#instance_method" do
@parent_um.inspect.should =~ /\bModuleSpecs::InstanceMeth\b/
@child_um.inspect.should =~ /\bfoo\b/
@child_um.inspect.should =~ /\bModuleSpecs::InstanceMeth\b/
- @child_um.inspect.should =~ /\bModuleSpecs::InstanceMethChild\b/
+
@mod_um.inspect.should =~ /\bbar\b/
@mod_um.inspect.should =~ /\bModuleSpecs::InstanceMethMod\b/
- @mod_um.inspect.should =~ /\bModuleSpecs::InstanceMethChild\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 not passed a symbol" do
- -> { Object.instance_method([]) }.should raise_error(TypeError)
- -> { Object.instance_method(0) }.should raise_error(TypeError)
+ it "raises a TypeError if the given name is not a String/Symbol" do
+ -> { Object.instance_method([]) }.should raise_error(TypeError, /is not a symbol nor a string/)
+ -> { Object.instance_method(0) }.should raise_error(TypeError, /is not a symbol nor a string/)
+ -> { Object.instance_method(nil) }.should raise_error(TypeError, /is not a symbol nor a string/)
+ -> { Object.instance_method(mock('x')) }.should raise_error(TypeError, /is not a symbol nor a string/)
end
- it "raises a TypeError if the given name is not a string/symbol" do
- -> { Object.instance_method(nil) }.should raise_error(TypeError)
- -> { Object.instance_method(mock('x')) }.should raise_error(TypeError)
+ it "accepts String name argument" do
+ method = ModuleSpecs::InstanceMeth.instance_method(:foo)
+ method.should be_kind_of(UnboundMethod)
+ end
+
+ it "accepts Symbol name argument" do
+ method = ModuleSpecs::InstanceMeth.instance_method("foo")
+ method.should be_kind_of(UnboundMethod)
+ end
+
+ it "converts non-String name by calling #to_str method" do
+ obj = Object.new
+ def obj.to_str() "foo" end
+
+ method = ModuleSpecs::InstanceMeth.instance_method(obj)
+ method.should be_kind_of(UnboundMethod)
+ end
+
+ it "raises TypeError when passed non-String name and #to_str returns non-String value" do
+ obj = Object.new
+ def obj.to_str() [] end
+
+ -> { ModuleSpecs::InstanceMeth.instance_method(obj) }.should raise_error(TypeError, /can't convert Object to String/)
end
it "raises a NameError if the method has been undefined" do
diff --git a/spec/ruby/core/module/method_added_spec.rb b/spec/ruby/core/module/method_added_spec.rb
index b983c8da76..ec92cddc1e 100644
--- a/spec/ruby/core/module/method_added_spec.rb
+++ b/spec/ruby/core/module/method_added_spec.rb
@@ -2,6 +2,10 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Module#method_added" do
+ before :each do
+ ScratchPad.record []
+ end
+
it "is a private instance method" do
Module.should have_private_instance_method(:method_added)
end
@@ -13,8 +17,6 @@ describe "Module#method_added" do
end
it "is called when a new instance method is defined in self" do
- ScratchPad.record []
-
Module.new do
def self.method_added(name)
ScratchPad << name
@@ -32,8 +34,6 @@ describe "Module#method_added" do
it "is not called when a singleton method is added" do
# obj.singleton_method_added is called instead
- ScratchPad.record []
-
klass = Class.new
def klass.method_added(name)
ScratchPad << name
@@ -60,8 +60,71 @@ describe "Module#method_added" do
m.should_not have_method(:method_to_undef)
end
+ it "is not called when a method changes visibility" do
+ Module.new do
+ def public_method
+ end
+
+ def private_method
+ end
+
+ def self.method_added(name)
+ ScratchPad << name
+ end
+
+ public :public_method
+ private :public_method
+
+ private :private_method
+ public :private_method
+ end
+
+ ScratchPad.recorded.should == []
+ end
+
+ it "is called when using #private in a subclass" do
+ parent = Class.new do
+ def foo
+ end
+ end
+
+ Class.new(parent) do
+ def self.method_added(name)
+ ScratchPad << name
+ end
+
+ # Create an instance as that might initialize some method lookup caches, which is interesting to test
+ self.new.foo
+
+ private :foo
+ public :foo
+ end
+
+ ScratchPad.recorded.should == [:foo]
+ end
+
+ it "is not called when a method is copied via module_function, rather #singleton_method_added is called" do
+ Module.new do
+ def mod_function
+ end
+
+ def self.method_added(name)
+ ScratchPad << [:method_added, name]
+ end
+
+ def self.singleton_method_added(name)
+ ScratchPad << [:singleton_method_added, name]
+ end
+
+ ScratchPad.record []
+
+ module_function :mod_function
+ end
+
+ ScratchPad.recorded.should == [[:singleton_method_added, :mod_function]]
+ end
+
it "is called with a precise caller location with the line of the 'def'" do
- ScratchPad.record []
line = nil
Module.new do
diff --git a/spec/ruby/core/module/module_function_spec.rb b/spec/ruby/core/module/module_function_spec.rb
index 0602e95ca9..1c3ec5471b 100644
--- a/spec/ruby/core/module/module_function_spec.rb
+++ b/spec/ruby/core/module/module_function_spec.rb
@@ -155,15 +155,62 @@ describe "Module#module_function with specific method names" do
m.foo.should == ["m", "super_m"]
end
+
+ context "methods created with define_method" do
+ context "passed a block" do
+ it "creates duplicates of the given instance methods" do
+ m = Module.new do
+ define_method :test1 do; end
+ module_function :test1
+ end
+
+ m.respond_to?(:test1).should == true
+ end
+ end
+
+ context "passed a method" do
+ it "creates duplicates of the given instance methods" do
+ module_with_method = Module.new do
+ def test1; end
+ end
+
+ c = Class.new do
+ extend module_with_method
+ end
+
+ m = Module.new do
+ define_method :test2, c.method(:test1)
+ module_function :test2
+ end
+
+ m.respond_to?(:test2).should == true
+ end
+ end
+
+ context "passed an unbound method" do
+ it "creates duplicates of the given instance methods" do
+ module_with_method = Module.new do
+ def test1; end
+ end
+
+ m = Module.new do
+ define_method :test2, module_with_method.instance_method(:test1)
+ module_function :test2
+ end
+
+ m.respond_to?(:test2).should == true
+ end
+ end
+ end
end
describe "Module#module_function as a toggle (no arguments) in a Module body" do
it "makes any subsequently defined methods module functions with the normal semantics" do
- m = Module.new {
+ m = Module.new do
module_function
def test1() end
def test2() end
- }
+ end
m.respond_to?(:test1).should == true
m.respond_to?(:test2).should == true
@@ -187,13 +234,13 @@ describe "Module#module_function as a toggle (no arguments) in a Module body" do
it "stops creating module functions if the body encounters another toggle " \
"like public/protected/private without arguments" do
- m = Module.new {
+ m = Module.new do
module_function
def test1() end
def test2() end
public
def test3() end
- }
+ end
m.respond_to?(:test1).should == true
m.respond_to?(:test2).should == true
@@ -202,14 +249,14 @@ describe "Module#module_function as a toggle (no arguments) in a Module body" do
it "does not stop creating module functions if the body encounters " \
"public/protected/private WITH arguments" do
- m = Module.new {
+ m = Module.new do
def foo() end
module_function
def test1() end
def test2() end
public :foo
def test3() end
- }
+ end
m.respond_to?(:test1).should == true
m.respond_to?(:test2).should == true
@@ -217,69 +264,116 @@ describe "Module#module_function as a toggle (no arguments) in a Module body" do
end
it "does not affect module_evaled method definitions also if outside the eval itself" do
- m = Module.new {
+ m = Module.new do
module_function
module_eval { def test1() end }
module_eval " def test2() end "
- }
+ end
m.respond_to?(:test1).should == false
m.respond_to?(:test2).should == false
end
it "has no effect if inside a module_eval if the definitions are outside of it" do
- m = Module.new {
+ m = Module.new do
module_eval { module_function }
def test1() end
def test2() end
- }
+ end
m.respond_to?(:test1).should == false
m.respond_to?(:test2).should == false
end
it "functions normally if both toggle and definitions inside a module_eval" do
- m = Module.new {
- module_eval {
+ m = Module.new do
+ module_eval do
module_function
def test1() end
def test2() end
- }
- }
+ end
+ end
m.respond_to?(:test1).should == true
m.respond_to?(:test2).should == true
end
- it "affects evaled method definitions also even when outside the eval itself" do
- m = Module.new {
+ it "affects eval'ed method definitions also even when outside the eval itself" do
+ m = Module.new do
module_function
eval "def test1() end"
- }
+ end
m.respond_to?(:test1).should == true
end
it "doesn't affect definitions when inside an eval even if the definitions are outside of it" do
- m = Module.new {
+ m = Module.new do
eval "module_function"
def test1() end
- }
+ end
m.respond_to?(:test1).should == false
end
it "functions normally if both toggle and definitions inside a eval" do
- m = Module.new {
+ m = Module.new do
eval <<-CODE
module_function
def test1() end
def test2() end
CODE
- }
+ end
m.respond_to?(:test1).should == true
m.respond_to?(:test2).should == true
end
+
+ context "methods are defined with define_method" do
+ context "passed a block" do
+ it "makes any subsequently defined methods module functions with the normal semantics" do
+ m = Module.new do
+ module_function
+ define_method :test1 do; end
+ end
+
+ m.respond_to?(:test1).should == true
+ end
+ end
+
+ context "passed a method" do
+ it "makes any subsequently defined methods module functions with the normal semantics" do
+ module_with_method = Module.new do
+ def test1; end
+ end
+
+ c = Class.new do
+ extend module_with_method
+ end
+
+ m = Module.new do
+ module_function
+ define_method :test2, c.method(:test1)
+ end
+
+ m.respond_to?(:test2).should == true
+ end
+ end
+
+ context "passed an unbound method" do
+ it "makes any subsequently defined methods module functions with the normal semantics" do
+ module_with_method = Module.new do
+ def test1; end
+ end
+
+ m = Module.new do
+ module_function
+ define_method :test2, module_with_method.instance_method(:test1)
+ end
+
+ m.respond_to?(:test2).should == true
+ end
+ end
+ end
end
diff --git a/spec/ruby/core/module/name_spec.rb b/spec/ruby/core/module/name_spec.rb
index ca9106a973..0d1f4e24d5 100644
--- a/spec/ruby/core/module/name_spec.rb
+++ b/spec/ruby/core/module/name_spec.rb
@@ -6,20 +6,10 @@ describe "Module#name" do
Module.new.name.should be_nil
end
- ruby_version_is ""..."3.0" do
- it "is nil when assigned to a constant in an anonymous module" do
- m = Module.new
- m::N = Module.new
- m::N.name.should be_nil
- end
- end
-
- ruby_version_is "3.0" do
- it "is not nil when assigned to a constant in an anonymous module" do
- m = Module.new
- m::N = Module.new
- m::N.name.should.end_with? '::N'
- end
+ it "is not nil when assigned to a constant in an anonymous module" do
+ m = Module.new
+ m::N = Module.new
+ m::N.name.should.end_with? '::N'
end
it "is not nil for a nested module created with the module keyword" do
@@ -42,6 +32,19 @@ describe "Module#name" do
m::N.name.should == "ModuleSpecs::Anonymous::WasAnnon"
end
+ it "may be the repeated in different module objects" do
+ m = Module.new
+ n = Module.new
+
+ suppress_warning do
+ ModuleSpecs::Anonymous::SameName = m
+ ModuleSpecs::Anonymous::SameName = n
+ end
+
+ m.name.should == "ModuleSpecs::Anonymous::SameName"
+ n.name.should == "ModuleSpecs::Anonymous::SameName"
+ end
+
it "is set after it is removed from a constant" do
module ModuleSpecs
module ModuleToRemove
@@ -69,12 +72,18 @@ describe "Module#name" do
ModuleSpecs::Anonymous.name.should == "ModuleSpecs::Anonymous"
end
- it "is set when assigning to a constant" do
+ it "is set when assigning to a constant (constant path matches outer module name)" do
m = Module.new
ModuleSpecs::Anonymous::A = m
m.name.should == "ModuleSpecs::Anonymous::A"
end
+ it "is set when assigning to a constant (constant path does not match outer module name)" do
+ m = Module.new
+ ModuleSpecs::Anonymous::SameChild::A = m
+ m.name.should == "ModuleSpecs::Anonymous::Child::A"
+ end
+
it "is not modified when assigning to a new constant after it has been accessed" do
m = Module.new
ModuleSpecs::Anonymous::B = m
@@ -111,34 +120,33 @@ describe "Module#name" do
ModuleSpecs::NameEncoding.new.name.encoding.should == Encoding::UTF_8
end
- it "is set when the anonymous outer module name is set" do
+ it "is set when the anonymous outer module name is set (module in one single constant)" do
m = Module.new
m::N = Module.new
ModuleSpecs::Anonymous::E = m
m::N.name.should == "ModuleSpecs::Anonymous::E::N"
end
- ruby_version_is ""..."2.7" do
- it "returns a mutable string" do
- ModuleSpecs.name.frozen?.should be_false
- end
-
- it "returns a mutable string that when mutated does not modify the original module name" do
- ModuleSpecs.name << "foo"
-
- ModuleSpecs.name.should == "ModuleSpecs"
- end
+ # https://bugs.ruby-lang.org/issues/19681
+ it "is set when the anonymous outer module name is set (module in several constants)" do
+ m = Module.new
+ m::N = Module.new
+ m::O = m::N
+ ModuleSpecs::Anonymous::StoredInMultiplePlaces = m
+ valid_names = [
+ "ModuleSpecs::Anonymous::StoredInMultiplePlaces::N",
+ "ModuleSpecs::Anonymous::StoredInMultiplePlaces::O"
+ ]
+ valid_names.should include(m::N.name) # You get one of the two, but you don't know which one.
end
- ruby_version_is "2.7" do
- it "returns a frozen String" do
- ModuleSpecs.name.should.frozen?
- end
+ it "returns a frozen String" do
+ ModuleSpecs.name.should.frozen?
+ end
- it "always returns the same String for a given Module" do
- s1 = ModuleSpecs.name
- s2 = ModuleSpecs.name
- s1.should equal(s2)
- end
+ it "always returns the same String for a given Module" do
+ s1 = ModuleSpecs.name
+ s2 = ModuleSpecs.name
+ s1.should equal(s2)
end
end
diff --git a/spec/ruby/core/module/prepend_features_spec.rb b/spec/ruby/core/module/prepend_features_spec.rb
index 2d1fa713b7..09c15c5c15 100644
--- a/spec/ruby/core/module/prepend_features_spec.rb
+++ b/spec/ruby/core/module/prepend_features_spec.rb
@@ -28,20 +28,6 @@ describe "Module#prepend_features" do
}.should raise_error(ArgumentError)
end
- ruby_version_is ''...'2.7' do
- it "copies own tainted status to the given module" do
- other = Module.new
- Module.new.taint.send :prepend_features, other
- other.tainted?.should be_true
- end
-
- it "copies own untrusted status to the given module" do
- other = Module.new
- Module.new.untrust.send :prepend_features, other
- other.untrusted?.should be_true
- end
- end
-
it "clears caches of the given module" do
parent = Class.new do
def bar; :bar; end
diff --git a/spec/ruby/core/module/prepend_spec.rb b/spec/ruby/core/module/prepend_spec.rb
index d636e023ed..c90fa9700e 100644
--- a/spec/ruby/core/module/prepend_spec.rb
+++ b/spec/ruby/core/module/prepend_spec.rb
@@ -499,34 +499,17 @@ describe "Module#prepend" do
c.dup.new.should be_kind_of(m)
end
- ruby_version_is ''...'3.0' do
- it "keeps the module in the chain when dupping an intermediate module" do
- m1 = Module.new { def calc(x) x end }
- m2 = Module.new { prepend(m1) }
- c1 = Class.new { prepend(m2) }
- m2dup = m2.dup
- m2dup.ancestors.should == [m2dup,m1,m2]
- c2 = Class.new { prepend(m2dup) }
- c1.ancestors[0,3].should == [m1,m2,c1]
- c1.new.should be_kind_of(m1)
- c2.ancestors[0,4].should == [m2dup,m1,m2,c2]
- c2.new.should be_kind_of(m1)
- end
- end
-
- ruby_version_is '3.0' do
- it "uses only new module when dupping the module" do
- m1 = Module.new { def calc(x) x end }
- m2 = Module.new { prepend(m1) }
- c1 = Class.new { prepend(m2) }
- m2dup = m2.dup
- m2dup.ancestors.should == [m1,m2dup]
- c2 = Class.new { prepend(m2dup) }
- c1.ancestors[0,3].should == [m1,m2,c1]
- c1.new.should be_kind_of(m1)
- c2.ancestors[0,3].should == [m1,m2dup,c2]
- c2.new.should be_kind_of(m1)
- end
+ it "uses only new module when dupping the module" do
+ m1 = Module.new { def calc(x) x end }
+ m2 = Module.new { prepend(m1) }
+ c1 = Class.new { prepend(m2) }
+ m2dup = m2.dup
+ m2dup.ancestors.should == [m1,m2dup]
+ c2 = Class.new { prepend(m2dup) }
+ c1.ancestors[0,3].should == [m1,m2,c1]
+ c1.new.should be_kind_of(m1)
+ c2.ancestors[0,3].should == [m1,m2dup,c2]
+ c2.new.should be_kind_of(m1)
end
it "depends on prepend_features to add the module" do
@@ -611,6 +594,18 @@ describe "Module#prepend" do
ScratchPad.recorded.should == [[:prepend_features, c], [:prepended, c]]
end
+ it "prepends a module if it is included in a super class" do
+ module ModuleSpecs::M3
+ module M; end
+ class A; include M; end
+ class B < A; prepend M; end
+
+ all = [A, B, M]
+
+ (B.ancestors.filter { |a| all.include?(a) }).should == [M, B, A, M]
+ end
+ end
+
it "detects cyclic prepends" do
-> {
module ModuleSpecs::P
@@ -731,6 +726,50 @@ describe "Module#prepend" do
ary.should == [3, 2, 1]
end
+ it "does not prepend a second copy if the module already indirectly exists in the hierarchy" do
+ mod = Module.new do; end
+ submod = Module.new do; end
+ klass = Class.new do; end
+ klass.include(mod)
+ mod.prepend(submod)
+ klass.include(mod)
+
+ klass.ancestors.take(4).should == [klass, submod, mod, Object]
+ end
+
+ # 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
+
+ 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.prepend(m)
+ b.ancestors.take(5).should == [m, b, m, a, Object]
+ end
+ end
+ end
+
describe "called on a module" do
describe "included into a class"
it "does not obscure the module's methods from reflective access" do
diff --git a/spec/ruby/core/module/private_class_method_spec.rb b/spec/ruby/core/module/private_class_method_spec.rb
index 407779cccc..f899c71a57 100644
--- a/spec/ruby/core/module/private_class_method_spec.rb
+++ b/spec/ruby/core/module/private_class_method_spec.rb
@@ -79,15 +79,13 @@ describe "Module#private_class_method" do
end.should raise_error(NameError)
end
- ruby_version_is "3.0" do
- context "when single argument is passed and is an array" do
- it "sets the visibility of the given methods to private" do
- c = Class.new do
- def self.foo() "foo" end
- private_class_method [:foo]
- end
- -> { c.foo }.should raise_error(NoMethodError)
+ context "when single argument is passed and is an array" do
+ it "sets the visibility of the given methods to private" do
+ c = Class.new do
+ def self.foo() "foo" end
+ private_class_method [:foo]
end
+ -> { c.foo }.should raise_error(NoMethodError)
end
end
end
diff --git a/spec/ruby/core/module/public_class_method_spec.rb b/spec/ruby/core/module/public_class_method_spec.rb
index b5d76e7b7a..71b20acda5 100644
--- a/spec/ruby/core/module/public_class_method_spec.rb
+++ b/spec/ruby/core/module/public_class_method_spec.rb
@@ -78,19 +78,17 @@ describe "Module#public_class_method" do
end.should raise_error(NameError)
end
- ruby_version_is "3.0" do
- context "when single argument is passed and is an array" do
- it "makes a class method public" do
- c = Class.new do
- class << self
- private
- def foo() "foo" end
- end
- public_class_method [:foo]
+ context "when single argument is passed and is an array" do
+ it "makes a class method public" do
+ c = Class.new do
+ class << self
+ private
+ def foo() "foo" end
end
-
- c.foo.should == "foo"
+ public_class_method [:foo]
end
+
+ c.foo.should == "foo"
end
end
end
diff --git a/spec/ruby/core/module/refine_spec.rb b/spec/ruby/core/module/refine_spec.rb
index 56ffc7ead2..11085c325b 100644
--- a/spec/ruby/core/module/refine_spec.rb
+++ b/spec/ruby/core/module/refine_spec.rb
@@ -71,7 +71,7 @@ describe "Module#refine" do
Module.new do
refine("foo") {}
end
- end.should raise_error(TypeError)
+ end.should raise_error(TypeError, "wrong argument type String (expected Class or Module)")
end
it "accepts a module as argument" do
@@ -518,115 +518,55 @@ describe "Module#refine" do
result.should == "hello from refinement"
end
- ruby_version_is "" ... "2.7" do
- it "is not honored by Kernel#method" do
- klass = Class.new
- refinement = Module.new do
- refine klass do
- def foo; end
- end
+ it "is honored by Kernel#method" do
+ klass = Class.new
+ refinement = Module.new do
+ refine klass do
+ def foo; end
end
-
- -> {
- Module.new do
- using refinement
- klass.new.method(:foo)
- end
- }.should raise_error(NameError, /undefined method `foo'/)
end
- end
-
- ruby_version_is "2.7" do
- it "is honored by Kernel#method" do
- klass = Class.new
- refinement = Module.new do
- refine klass do
- def foo; end
- end
- end
-
- result = nil
- Module.new do
- using refinement
- result = klass.new.method(:foo).class
- end
- result.should == Method
+ result = nil
+ Module.new do
+ using refinement
+ result = klass.new.method(:foo).class
end
- end
-
- ruby_version_is "" ... "2.7" do
- it "is not honored by Kernel#public_method" do
- klass = Class.new
- refinement = Module.new do
- refine klass do
- def foo; end
- end
- end
- -> {
- Module.new do
- using refinement
- klass.new.public_method(:foo)
- end
- }.should raise_error(NameError, /undefined method `foo'/)
- end
+ result.should == Method
end
- ruby_version_is "2.7" do
- it "is honored by Kernel#public_method" do
- klass = Class.new
- refinement = Module.new do
- refine klass do
- def foo; end
- end
- end
-
- result = nil
- Module.new do
- using refinement
- result = klass.new.public_method(:foo).class
+ it "is honored by Kernel#public_method" do
+ klass = Class.new
+ refinement = Module.new do
+ refine klass do
+ def foo; end
end
-
- result.should == Method
end
- end
- ruby_version_is "" ... "2.7" do
- it "is not honored by Kernel#instance_method" do
- klass = Class.new
- refinement = Module.new do
- refine klass do
- def foo; end
- end
- end
-
- -> {
- Module.new do
- using refinement
- klass.instance_method(:foo)
- end
- }.should raise_error(NameError, /undefined method `foo'/)
+ result = nil
+ Module.new do
+ using refinement
+ result = klass.new.public_method(:foo).class
end
- end
- ruby_version_is "2.7" do
- it "is honored by Kernel#instance_method" do
- klass = Class.new
- refinement = Module.new do
- refine klass do
- def foo; end
- end
- end
+ result.should == Method
+ end
- result = nil
- Module.new do
- using refinement
- result = klass.instance_method(:foo).class
+ it "is honored by Kernel#instance_method" do
+ klass = Class.new
+ refinement = Module.new do
+ refine klass do
+ def foo; end
end
+ end
- result.should == UnboundMethod
+ result = nil
+ Module.new do
+ using refinement
+ result = klass.instance_method(:foo).class
end
+
+ result.should == UnboundMethod
end
it "is honored by Kernel#respond_to?" do
diff --git a/spec/ruby/core/module/refinements_spec.rb b/spec/ruby/core/module/refinements_spec.rb
new file mode 100644
index 0000000000..5648fcbd6f
--- /dev/null
+++ b/spec/ruby/core/module/refinements_spec.rb
@@ -0,0 +1,45 @@
+require_relative '../../spec_helper'
+
+describe "Module#refinements" do
+ ruby_version_is "3.2" do
+ it "returns refinements defined in a module" do
+ ScratchPad.record []
+
+ m = Module.new do
+ refine String do
+ ScratchPad << self
+ end
+
+ refine Array do
+ ScratchPad << self
+ end
+ end
+
+ m.refinements.sort_by(&:object_id).should == ScratchPad.recorded.sort_by(&:object_id)
+ end
+
+ it "does not return refinements defined in the included module" do
+ ScratchPad.record []
+
+ m1 = Module.new do
+ refine Integer do
+ nil
+ end
+ end
+
+ m2 = Module.new do
+ include m1
+
+ refine String do
+ ScratchPad << self
+ end
+ end
+
+ m2.refinements.should == ScratchPad.recorded
+ end
+
+ it "returns an empty array if no refinements defined in a module" do
+ Module.new.refinements.should == []
+ end
+ end
+end
diff --git a/spec/ruby/core/module/ruby2_keywords_spec.rb b/spec/ruby/core/module/ruby2_keywords_spec.rb
index 34c45cb1bc..aca419f522 100644
--- a/spec/ruby/core/module/ruby2_keywords_spec.rb
+++ b/spec/ruby/core/module/ruby2_keywords_spec.rb
@@ -1,112 +1,297 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-ruby_version_is "2.7" do
- describe "Module#ruby2_keywords" do
- it "marks the final hash argument as keyword hash" do
- obj = Object.new
+describe "Module#ruby2_keywords" do
+ class << self
+ ruby2_keywords def mark(*args)
+ args
+ end
+ end
- obj.singleton_class.class_exec do
- def foo(*a) a.last end
- ruby2_keywords :foo
- end
+ it "marks the final hash argument as keyword hash" do
+ last = mark(1, 2, a: "a").last
+ Hash.ruby2_keywords_hash?(last).should == true
+ end
- last = obj.foo(1, 2, a: "a")
- Hash.ruby2_keywords_hash?(last).should == true
+ it "makes a copy of the hash and only marks the copy as keyword hash" do
+ obj = Object.new
+ obj.singleton_class.class_exec do
+ def regular(*args)
+ args.last
+ end
end
- ruby_version_is "2.7" ... "3.0" do
- it "fixes delegation warnings when calling a method accepting keywords" do
- obj = Object.new
+ h = {a: 1}
- obj.singleton_class.class_exec do
- def foo(*a) bar(*a) end
- def bar(*a, **b) end
- end
+ last = mark(**h).last
+ Hash.ruby2_keywords_hash?(last).should == true
+ Hash.ruby2_keywords_hash?(h).should == false
- -> { obj.foo(1, 2, {a: "a"}) }.should complain(/Using the last argument as keyword parameters is deprecated/)
-
- obj.singleton_class.class_exec do
- ruby2_keywords :foo
- end
+ last2 = mark(**last).last # last is already marked
+ Hash.ruby2_keywords_hash?(last2).should == true
+ Hash.ruby2_keywords_hash?(last).should == true
+ last2.should_not.equal?(last)
+ Hash.ruby2_keywords_hash?(h).should == false
+ end
- -> { obj.foo(1, 2, {a: "a"}) }.should_not complain
+ it "makes a copy and unmark the Hash when calling a method taking (arg)" do
+ obj = Object.new
+ obj.singleton_class.class_exec do
+ def single(arg)
+ arg
end
end
- it "returns nil" do
- obj = Object.new
+ h = { a: 1 }
+ args = mark(**h)
+ marked = args.last
+ Hash.ruby2_keywords_hash?(marked).should == true
- obj.singleton_class.class_exec do
- def foo(*a) end
+ after_usage = obj.single(*args)
+ after_usage.should == h
+ after_usage.should_not.equal?(h)
+ after_usage.should_not.equal?(marked)
+ Hash.ruby2_keywords_hash?(after_usage).should == false
+ Hash.ruby2_keywords_hash?(marked).should == true
+ end
- ruby2_keywords(:foo).should == nil
+ it "makes a copy and unmark the Hash when calling a method taking (**kw)" do
+ obj = Object.new
+ obj.singleton_class.class_exec do
+ def kwargs(**kw)
+ kw
end
end
- it "raises NameError when passed not existing method name" do
- obj = Object.new
+ h = { a: 1 }
+ args = mark(**h)
+ marked = args.last
+ Hash.ruby2_keywords_hash?(marked).should == true
- -> {
- obj.singleton_class.class_exec do
- ruby2_keywords :not_existing
- end
- }.should raise_error(NameError, /undefined method `not_existing'/)
- end
+ after_usage = obj.kwargs(*args)
+ after_usage.should == h
+ after_usage.should_not.equal?(h)
+ after_usage.should_not.equal?(marked)
+ Hash.ruby2_keywords_hash?(after_usage).should == false
+ Hash.ruby2_keywords_hash?(marked).should == true
+ end
- it "acceps String as well" do
+ ruby_version_is "3.2" do
+ it "makes a copy and unmark the Hash when calling a method taking (*args)" do
obj = Object.new
-
obj.singleton_class.class_exec do
- def foo(*a) a.last end
- ruby2_keywords "foo"
+ def splat(*args)
+ args.last
+ end
+
+ def splat1(arg, *args)
+ args.last
+ end
+
+ def proc_call(*args)
+ -> *a { a.last }.call(*args)
+ end
end
- last = obj.foo(1, 2, a: "a")
- Hash.ruby2_keywords_hash?(last).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_not.equal?(marked)
+ Hash.ruby2_keywords_hash?(after_usage).should == false
+ Hash.ruby2_keywords_hash?(marked).should == true
+
+ args = mark(1, **h)
+ marked = args.last
+ after_usage = obj.splat1(*args)
+ after_usage.should == h
+ after_usage.should_not.equal?(h)
+ after_usage.should_not.equal?(marked)
+ Hash.ruby2_keywords_hash?(after_usage).should == false
+ Hash.ruby2_keywords_hash?(marked).should == true
+
+ args = mark(**h)
+ marked = args.last
+ after_usage = obj.proc_call(*args)
+ after_usage.should == h
+ after_usage.should_not.equal?(h)
+ after_usage.should_not.equal?(marked)
+ Hash.ruby2_keywords_hash?(after_usage).should == false
+ Hash.ruby2_keywords_hash?(marked).should == true
+
+ args = mark(**h)
+ marked = args.last
+ after_usage = obj.send(:splat, *args)
+ after_usage.should == h
+ after_usage.should_not.equal?(h)
+ after_usage.should_not.equal?(marked)
+ Hash.ruby2_keywords_hash?(after_usage).should == false
+ Hash.ruby2_keywords_hash?(marked).should == true
end
+ end
- it "raises TypeError when passed not Symbol or String" do
+ ruby_version_is ""..."3.2" do
+ # https://bugs.ruby-lang.org/issues/18625
+ it "does NOT copy the Hash when calling a method taking (*args)" do
obj = Object.new
+ obj.singleton_class.class_exec do
+ def splat(*args)
+ args.last
+ end
- -> {
- obj.singleton_class.class_exec do
- ruby2_keywords Object.new
+ def splat1(arg, *args)
+ args.last
end
- }.should raise_error(TypeError, /is not a symbol nor a string/)
+
+ def proc_call(*args)
+ -> *a { a.last }.call(*args)
+ end
+ end
+
+ h = { a: 1 }
+ args = mark(**h)
+ marked = args.last
+ Hash.ruby2_keywords_hash?(marked).should == true
+
+ after_usage = obj.splat(*args)
+ after_usage.should == h
+ after_usage.should_not.equal?(h)
+ after_usage.should.equal?(marked) # https://bugs.ruby-lang.org/issues/18625
+ Hash.ruby2_keywords_hash?(after_usage).should == true # https://bugs.ruby-lang.org/issues/18625
+ Hash.ruby2_keywords_hash?(marked).should == true
+
+ args = mark(1, **h)
+ marked = args.last
+ after_usage = obj.splat1(*args)
+ after_usage.should == h
+ after_usage.should_not.equal?(h)
+ after_usage.should.equal?(marked) # https://bugs.ruby-lang.org/issues/18625
+ Hash.ruby2_keywords_hash?(after_usage).should == true # https://bugs.ruby-lang.org/issues/18625
+ Hash.ruby2_keywords_hash?(marked).should == true
+
+ args = mark(**h)
+ marked = args.last
+ after_usage = obj.proc_call(*args)
+ after_usage.should == h
+ after_usage.should_not.equal?(h)
+ after_usage.should.equal?(marked) # https://bugs.ruby-lang.org/issues/18625
+ Hash.ruby2_keywords_hash?(after_usage).should == true # https://bugs.ruby-lang.org/issues/18625
+ Hash.ruby2_keywords_hash?(marked).should == true
+
+ args = mark(**h)
+ marked = args.last
+ after_usage = obj.send(:splat, *args)
+ after_usage.should == h
+ after_usage.should_not.equal?(h)
+ send_copies = RUBY_ENGINE == "ruby" # inconsistent with Proc#call above for CRuby
+ after_usage.equal?(marked).should == !send_copies
+ Hash.ruby2_keywords_hash?(after_usage).should == !send_copies
+ Hash.ruby2_keywords_hash?(marked).should == true
end
+ end
- it "prints warning when a method does not accept argument splat" do
- obj = Object.new
- def obj.foo(a, b, c) end
+ it "applies to the underlying method and applies across aliasing" do
+ obj = Object.new
- -> {
- obj.singleton_class.class_exec do
- ruby2_keywords :foo
- end
- }.should complain(/Skipping set of ruby2_keywords flag for/)
+ obj.singleton_class.class_exec do
+ def foo(*a) a.last end
+ alias_method :bar, :foo
+ ruby2_keywords :foo
+
+ def baz(*a) a.last end
+ ruby2_keywords :baz
+ alias_method :bob, :baz
end
- it "prints warning when a method accepts keywords" do
- obj = Object.new
- def obj.foo(a:, b:) end
+ last = obj.foo(1, 2, a: "a")
+ Hash.ruby2_keywords_hash?(last).should == true
- -> {
- obj.singleton_class.class_exec do
- ruby2_keywords :foo
- end
- }.should complain(/Skipping set of ruby2_keywords flag for/)
+ last = obj.bar(1, 2, a: "a")
+ Hash.ruby2_keywords_hash?(last).should == true
+
+ last = obj.baz(1, 2, a: "a")
+ Hash.ruby2_keywords_hash?(last).should == true
+
+ last = obj.bob(1, 2, a: "a")
+ Hash.ruby2_keywords_hash?(last).should == true
+ end
+
+ it "returns nil" do
+ obj = Object.new
+
+ obj.singleton_class.class_exec do
+ def foo(*a) end
+
+ ruby2_keywords(:foo).should == nil
end
+ end
- it "prints warning when a method accepts keyword splat" do
- obj = Object.new
- def obj.foo(**a) end
+ it "raises NameError when passed not existing method name" do
+ obj = Object.new
- -> {
- obj.singleton_class.class_exec do
- ruby2_keywords :foo
- end
- }.should complain(/Skipping set of ruby2_keywords flag for/)
+ -> {
+ obj.singleton_class.class_exec do
+ ruby2_keywords :not_existing
+ end
+ }.should raise_error(NameError, /undefined method [`']not_existing'/)
+ end
+
+ it "accepts String as well" do
+ obj = Object.new
+
+ obj.singleton_class.class_exec do
+ def foo(*a) a.last end
+ ruby2_keywords "foo"
end
+
+ last = obj.foo(1, 2, a: "a")
+ Hash.ruby2_keywords_hash?(last).should == true
+ end
+
+ it "raises TypeError when passed not Symbol or String" do
+ obj = Object.new
+
+ -> {
+ obj.singleton_class.class_exec do
+ ruby2_keywords Object.new
+ end
+ }.should raise_error(TypeError, /is not a symbol nor a string/)
+ end
+
+ it "prints warning when a method does not accept argument splat" do
+ obj = Object.new
+ def obj.foo(a, b, c) end
+
+ -> {
+ obj.singleton_class.class_exec do
+ ruby2_keywords :foo
+ end
+ }.should complain(/Skipping set of ruby2_keywords flag for/)
+ end
+
+ it "prints warning when a method accepts keywords" do
+ obj = Object.new
+ def obj.foo(a:, b:) end
+
+ -> {
+ obj.singleton_class.class_exec do
+ ruby2_keywords :foo
+ end
+ }.should complain(/Skipping set of ruby2_keywords flag for/)
+ end
+
+ it "prints warning when a method accepts keyword splat" do
+ obj = Object.new
+ def obj.foo(**a) end
+
+ -> {
+ obj.singleton_class.class_exec do
+ ruby2_keywords :foo
+ end
+ }.should complain(/Skipping set of ruby2_keywords flag for/)
end
end
diff --git a/spec/ruby/core/module/set_temporary_name_spec.rb b/spec/ruby/core/module/set_temporary_name_spec.rb
new file mode 100644
index 0000000000..f5886a3398
--- /dev/null
+++ b/spec/ruby/core/module/set_temporary_name_spec.rb
@@ -0,0 +1,68 @@
+require_relative '../../spec_helper'
+
+ruby_version_is "3.3" do
+ describe "Module#set_temporary_name" do
+ it "can assign a temporary name" do
+ m = Module.new
+ m.name.should be_nil
+
+ m.set_temporary_name("fake_name")
+ m.name.should == "fake_name"
+
+ m.set_temporary_name(nil)
+ m.name.should be_nil
+ end
+
+ it "can assign a temporary name which is not a valid constant path" do
+ m = Module.new
+ m.set_temporary_name("a::B")
+ m.name.should == "a::B"
+
+ m.set_temporary_name("Template['foo.rb']")
+ m.name.should == "Template['foo.rb']"
+ end
+
+ it "can't assign empty string as name" do
+ m = Module.new
+ -> { m.set_temporary_name("") }.should raise_error(ArgumentError, "empty class/module name")
+ end
+
+ it "can't assign a constant name as a temporary name" do
+ m = Module.new
+ -> { m.set_temporary_name("Object") }.should raise_error(ArgumentError, "the temporary name must not be a constant path to avoid confusion")
+ end
+
+ it "can't assign a constant path as a temporary name" do
+ m = Module.new
+ -> { m.set_temporary_name("A::B") }.should raise_error(ArgumentError, "the temporary name must not be a constant path to avoid confusion")
+ -> { m.set_temporary_name("::A") }.should raise_error(ArgumentError, "the temporary name must not be a constant path to avoid confusion")
+ -> { m.set_temporary_name("::A::B") }.should raise_error(ArgumentError, "the temporary name must not be a constant path to avoid confusion")
+ end
+
+ it "can't assign name to permanent module" do
+ -> { Object.set_temporary_name("fake_name") }.should raise_error(RuntimeError, "can't change permanent name")
+ end
+
+ it "can assign a temporary name to a nested module" do
+ m = Module.new
+ module m::N; end
+ m::N.name.should =~ /\A#<Module:0x\h+>::N\z/
+
+ m::N.set_temporary_name("fake_name")
+ m::N.name.should == "fake_name"
+
+ m::N.set_temporary_name(nil)
+ m::N.name.should be_nil
+ end
+
+ it "can update the name when assigned to a constant" do
+ m = Module.new
+ m::N = Module.new
+ m::N.name.should =~ /\A#<Module:0x\h+>::N\z/
+ m::N.set_temporary_name(nil)
+
+ m::M = m::N
+ m::M.name.should =~ /\A#<Module:0x\h+>::M\z/m
+ end
+ end
+end
diff --git a/spec/ruby/core/module/shared/attr_added.rb b/spec/ruby/core/module/shared/attr_added.rb
new file mode 100644
index 0000000000..ce832cdcff
--- /dev/null
+++ b/spec/ruby/core/module/shared/attr_added.rb
@@ -0,0 +1,34 @@
+describe :module_attr_added, shared: true do
+ it "calls method_added for normal classes" do
+ ScratchPad.record []
+
+ cls = Class.new do
+ class << self
+ def method_added(name)
+ ScratchPad.recorded << name
+ end
+ end
+ end
+
+ cls.send(@method, :foo)
+
+ ScratchPad.recorded.each {|name| name.to_s.should =~ /foo[=]?/}
+ end
+
+ it "calls singleton_method_added for singleton classes" do
+ ScratchPad.record []
+ cls = Class.new do
+ class << self
+ def singleton_method_added(name)
+ # called for this def so ignore it
+ return if name == :singleton_method_added
+ ScratchPad.recorded << name
+ end
+ end
+ end
+
+ cls.singleton_class.send(@method, :foo)
+
+ ScratchPad.recorded.each {|name| name.to_s.should =~ /foo[=]?/}
+ end
+end
diff --git a/spec/ruby/core/module/shared/class_eval.rb b/spec/ruby/core/module/shared/class_eval.rb
index 224078ae54..b1d5cb3814 100644
--- a/spec/ruby/core/module/shared/class_eval.rb
+++ b/spec/ruby/core/module/shared/class_eval.rb
@@ -52,43 +52,58 @@ describe :module_class_eval, shared: true do
ModuleSpecs.send(@method, "[__FILE__, __LINE__]", "test", 102).should == ["test", 102]
end
+ ruby_version_is "3.3" do
+ it "uses the caller location as default filename" do
+ ModuleSpecs.send(@method, "[__FILE__, __LINE__]").should == ["(eval at #{__FILE__}:#{__LINE__})", 1]
+ end
+ end
+
it "converts a non-string filename to a string using to_str" do
(file = mock(__FILE__)).should_receive(:to_str).and_return(__FILE__)
ModuleSpecs.send(@method, "1+1", file)
+
+ (file = mock(__FILE__)).should_receive(:to_str).and_return(__FILE__)
+ ModuleSpecs.send(@method, "1+1", file, 15)
end
it "raises a TypeError when the given filename can't be converted to string using to_str" do
(file = mock('123')).should_receive(:to_str).and_return(123)
- -> { ModuleSpecs.send(@method, "1+1", file) }.should raise_error(TypeError)
+ -> { ModuleSpecs.send(@method, "1+1", file) }.should raise_error(TypeError, /can't convert MockObject to String/)
end
it "converts non string eval-string to string using to_str" do
(o = mock('1 + 1')).should_receive(:to_str).and_return("1 + 1")
ModuleSpecs.send(@method, o).should == 2
+
+ (o = mock('1 + 1')).should_receive(:to_str).and_return("1 + 1")
+ ModuleSpecs.send(@method, o, "file.rb").should == 2
+
+ (o = mock('1 + 1')).should_receive(:to_str).and_return("1 + 1")
+ ModuleSpecs.send(@method, o, "file.rb", 15).should == 2
end
it "raises a TypeError when the given eval-string can't be converted to string using to_str" do
o = mock('x')
- -> { ModuleSpecs.send(@method, o) }.should raise_error(TypeError)
+ -> { ModuleSpecs.send(@method, o) }.should raise_error(TypeError, "no implicit conversion of MockObject into String")
(o = mock('123')).should_receive(:to_str).and_return(123)
- -> { ModuleSpecs.send(@method, o) }.should raise_error(TypeError)
+ -> { ModuleSpecs.send(@method, o) }.should raise_error(TypeError, /can't convert MockObject to String/)
end
it "raises an ArgumentError when no arguments and no block are given" do
- -> { ModuleSpecs.send(@method) }.should raise_error(ArgumentError)
+ -> { ModuleSpecs.send(@method) }.should raise_error(ArgumentError, "wrong number of arguments (given 0, expected 1..3)")
end
it "raises an ArgumentError when more than 3 arguments are given" do
-> {
ModuleSpecs.send(@method, "1 + 1", "some file", 0, "bogus")
- }.should raise_error(ArgumentError)
+ }.should raise_error(ArgumentError, "wrong number of arguments (given 4, expected 1..3)")
end
it "raises an ArgumentError when a block and normal arguments are given" do
-> {
ModuleSpecs.send(@method, "1 + 1") { 1 + 1 }
- }.should raise_error(ArgumentError)
+ }.should raise_error(ArgumentError, "wrong number of arguments (given 1, expected 0)")
end
# This case was found because Rubinius was caching the compiled
diff --git a/spec/ruby/core/module/shared/set_visibility.rb b/spec/ruby/core/module/shared/set_visibility.rb
index 9f31e230ca..a1586dd2bd 100644
--- a/spec/ruby/core/module/shared/set_visibility.rb
+++ b/spec/ruby/core/module/shared/set_visibility.rb
@@ -22,21 +22,19 @@ describe :set_visibility, shared: true do
end
end
- ruby_version_is "3.0" do
- describe "array as a single argument" do
- it "sets visibility of given method names" do
- visibility = @method
- old_visibility = [:protected, :private].find {|vis| vis != visibility }
-
- mod = Module.new {
- send old_visibility
- def test1() end
- def test2() end
- send visibility, [:test1, :test2]
- }
- mod.should send(:"have_#{visibility}_instance_method", :test1, false)
- mod.should send(:"have_#{visibility}_instance_method", :test2, false)
- end
+ describe "array as a single argument" do
+ it "sets visibility of given method names" do
+ visibility = @method
+ old_visibility = [:protected, :private].find {|vis| vis != visibility }
+
+ mod = Module.new {
+ send old_visibility
+ def test1() end
+ def test2() end
+ send visibility, [:test1, :test2]
+ }
+ mod.should send(:"have_#{visibility}_instance_method", :test1, false)
+ mod.should send(:"have_#{visibility}_instance_method", :test2, false)
end
end
diff --git a/spec/ruby/core/module/undef_method_spec.rb b/spec/ruby/core/module/undef_method_spec.rb
index c2ad200536..d4efcd51cb 100644
--- a/spec/ruby/core/module/undef_method_spec.rb
+++ b/spec/ruby/core/module/undef_method_spec.rb
@@ -50,7 +50,7 @@ describe "Module#undef_method" do
end
it "raises a NameError when passed a missing name for a module" do
- -> { @module.send :undef_method, :not_exist }.should raise_error(NameError, /undefined method `not_exist' for module `#{@module}'/) { |e|
+ -> { @module.send :undef_method, :not_exist }.should raise_error(NameError, /undefined method [`']not_exist' for module [`']#{@module}'/) { |e|
# a NameError and not a NoMethodError
e.class.should == NameError
}
@@ -58,7 +58,7 @@ describe "Module#undef_method" do
it "raises a NameError when passed a missing name for a class" do
klass = Class.new
- -> { klass.send :undef_method, :not_exist }.should raise_error(NameError, /undefined method `not_exist' for class `#{klass}'/) { |e|
+ -> { klass.send :undef_method, :not_exist }.should raise_error(NameError, /undefined method [`']not_exist' for class [`']#{klass}'/) { |e|
# a NameError and not a NoMethodError
e.class.should == NameError
}
@@ -69,8 +69,8 @@ describe "Module#undef_method" do
obj = klass.new
sclass = obj.singleton_class
- -> { sclass.send :undef_method, :not_exist }.should raise_error(NameError, /undefined method `not_exist' for class `#{sclass}'/) { |e|
- e.message.should include('`#<Class:#<#<Class:')
+ -> { sclass.send :undef_method, :not_exist }.should raise_error(NameError, /undefined method [`']not_exist' for class [`']#{sclass}'/) { |e|
+ e.message.should =~ /[`']#<Class:#<#<Class:/
# a NameError and not a NoMethodError
e.class.should == NameError
@@ -79,7 +79,7 @@ describe "Module#undef_method" do
it "raises a NameError when passed a missing name for a metaclass" do
klass = String.singleton_class
- -> { klass.send :undef_method, :not_exist }.should raise_error(NameError, /undefined method `not_exist' for class `String'/) { |e|
+ -> { klass.send :undef_method, :not_exist }.should raise_error(NameError, /undefined method [`']not_exist' for class [`']String'/) { |e|
# a NameError and not a NoMethodError
e.class.should == NameError
}
diff --git a/spec/ruby/core/module/undefined_instance_methods_spec.rb b/spec/ruby/core/module/undefined_instance_methods_spec.rb
new file mode 100644
index 0000000000..3be860d053
--- /dev/null
+++ b/spec/ruby/core/module/undefined_instance_methods_spec.rb
@@ -0,0 +1,26 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+
+describe "Module#undefined_instance_methods" do
+ ruby_version_is "3.2" do
+ it "returns methods undefined in the class" do
+ methods = ModuleSpecs::UndefinedInstanceMethods::Parent.undefined_instance_methods
+ methods.should == [:undefed_method]
+ end
+
+ it "returns inherited methods undefined in the class" do
+ methods = ModuleSpecs::UndefinedInstanceMethods::Child.undefined_instance_methods
+ methods.should include(:parent_method, :another_parent_method)
+ end
+
+ it "returns methods from an included module that are undefined in the class" do
+ methods = ModuleSpecs::UndefinedInstanceMethods::Grandchild.undefined_instance_methods
+ methods.should include(:super_included_method)
+ end
+
+ it "does not returns ancestors undefined methods" do
+ methods = ModuleSpecs::UndefinedInstanceMethods::Grandchild.undefined_instance_methods
+ methods.should_not include(:parent_method, :another_parent_method)
+ end
+ end
+end
diff --git a/spec/ruby/core/module/used_refinements_spec.rb b/spec/ruby/core/module/used_refinements_spec.rb
new file mode 100644
index 0000000000..c16cab0e3c
--- /dev/null
+++ b/spec/ruby/core/module/used_refinements_spec.rb
@@ -0,0 +1,87 @@
+require_relative '../../spec_helper'
+
+describe "Module.used_refinements" do
+ ruby_version_is "3.2" do
+ it "returns list of all refinements imported in the current scope" do
+ refinement_int = nil
+ refinement_str = nil
+ ScratchPad.record []
+
+ m1 = Module.new do
+ refine Integer do
+ refinement_int = self
+ end
+ end
+
+ m2 = Module.new do
+ refine String do
+ refinement_str = self
+ end
+ end
+
+ Module.new do
+ using m1
+ using m2
+
+ Module.used_refinements.each { |r| ScratchPad << r }
+ end
+
+ ScratchPad.recorded.sort_by(&:object_id).should == [refinement_int, refinement_str].sort_by(&:object_id)
+ end
+
+ it "returns empty array if does not have any refinements imported" do
+ used_refinements = nil
+
+ Module.new do
+ used_refinements = Module.used_refinements
+ end
+
+ used_refinements.should == []
+ end
+
+ it "ignores refinements imported in a module that is included into the current one" do
+ used_refinements = nil
+
+ m1 = Module.new do
+ refine Integer do
+ nil
+ end
+ end
+
+ m2 = Module.new do
+ using m1
+ end
+
+ Module.new do
+ include m2
+
+ used_refinements = Module.used_refinements
+ end
+
+ used_refinements.should == []
+ end
+
+ it "returns refinements even not defined directly in a module refinements are imported from" do
+ used_refinements = nil
+ ScratchPad.record []
+
+ m1 = Module.new do
+ refine Integer do
+ ScratchPad << self
+ end
+ end
+
+ m2 = Module.new do
+ include m1
+ end
+
+ Module.new do
+ using m2
+
+ used_refinements = Module.used_refinements
+ end
+
+ used_refinements.should == ScratchPad.recorded
+ end
+ end
+end
diff --git a/spec/ruby/core/module/using_spec.rb b/spec/ruby/core/module/using_spec.rb
index 4781b99bb7..a908363c96 100644
--- a/spec/ruby/core/module/using_spec.rb
+++ b/spec/ruby/core/module/using_spec.rb
@@ -316,7 +316,7 @@ describe "Module#using" do
using refinement
def initialize
- @a = "1703"
+ @a = +"1703"
@a.instance_eval do
def abc
diff --git a/spec/ruby/core/mutex/lock_spec.rb b/spec/ruby/core/mutex/lock_spec.rb
index 7a39817b11..e9d33f5fd9 100644
--- a/spec/ruby/core/mutex/lock_spec.rb
+++ b/spec/ruby/core/mutex/lock_spec.rb
@@ -1,10 +1,6 @@
require_relative '../../spec_helper'
describe "Mutex#lock" do
- before :each do
- ScratchPad.clear
- end
-
it "returns self" do
m = Mutex.new
m.lock.should == m
diff --git a/spec/ruby/core/mutex/owned_spec.rb b/spec/ruby/core/mutex/owned_spec.rb
index 1f843cd576..7bfc7d8f83 100644
--- a/spec/ruby/core/mutex/owned_spec.rb
+++ b/spec/ruby/core/mutex/owned_spec.rb
@@ -41,15 +41,13 @@ describe "Mutex#owned?" do
end
end
- ruby_version_is "3.0" do
- it "is held per Fiber" do
- m = Mutex.new
- m.lock
-
- Fiber.new do
- m.locked?.should == true
- m.owned?.should == false
- end.resume
- end
+ it "is held per Fiber" do
+ m = Mutex.new
+ m.lock
+
+ Fiber.new do
+ m.locked?.should == true
+ m.owned?.should == false
+ end.resume
end
end
diff --git a/spec/ruby/core/nil/singleton_method_spec.rb b/spec/ruby/core/nil/singleton_method_spec.rb
new file mode 100644
index 0000000000..8d898b1cc9
--- /dev/null
+++ b/spec/ruby/core/nil/singleton_method_spec.rb
@@ -0,0 +1,15 @@
+require_relative '../../spec_helper'
+
+describe "NilClass#singleton_method" do
+ ruby_version_is '3.3' do
+ it "raises regardless of whether NilClass defines the method" do
+ -> { nil.singleton_method(:foo) }.should raise_error(NameError)
+ begin
+ def (nil).foo; end
+ -> { nil.singleton_method(:foo) }.should raise_error(NameError)
+ ensure
+ NilClass.send(:remove_method, :foo)
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/nil/to_s_spec.rb b/spec/ruby/core/nil/to_s_spec.rb
index 283d26477a..fa0b929677 100644
--- a/spec/ruby/core/nil/to_s_spec.rb
+++ b/spec/ruby/core/nil/to_s_spec.rb
@@ -5,13 +5,11 @@ describe "NilClass#to_s" do
nil.to_s.should == ""
end
- ruby_version_is "2.7" do
- it "returns a frozen string" do
- nil.to_s.should.frozen?
- end
+ it "returns a frozen string" do
+ nil.to_s.should.frozen?
+ end
- it "always returns the same string" do
- nil.to_s.should equal(nil.to_s)
- end
+ it "always returns the same string" do
+ nil.to_s.should equal(nil.to_s)
end
end
diff --git a/spec/ruby/core/numeric/clone_spec.rb b/spec/ruby/core/numeric/clone_spec.rb
index c3b06ca0c9..423cec85dd 100644
--- a/spec/ruby/core/numeric/clone_spec.rb
+++ b/spec/ruby/core/numeric/clone_spec.rb
@@ -14,7 +14,7 @@ describe "Numeric#clone" do
1.clone.frozen?.should == true
end
- it "accepts optonal keyword argument :freeze" do
+ it "accepts optional keyword argument :freeze" do
value = 1
value.clone(freeze: true).should equal(value)
end
@@ -23,10 +23,8 @@ describe "Numeric#clone" do
-> { 1.clone(freeze: false) }.should raise_error(ArgumentError, /can't unfreeze/)
end
- ruby_version_is "3.0" do
- it "does not change frozen status if passed freeze: nil" do
- value = 1
- value.clone(freeze: nil).should equal(value)
- end
+ it "does not change frozen status if passed freeze: nil" do
+ value = 1
+ value.clone(freeze: nil).should equal(value)
end
end
diff --git a/spec/ruby/core/numeric/fdiv_spec.rb b/spec/ruby/core/numeric/fdiv_spec.rb
index 907e5d343c..e97fa77f79 100644
--- a/spec/ruby/core/numeric/fdiv_spec.rb
+++ b/spec/ruby/core/numeric/fdiv_spec.rb
@@ -1,5 +1,4 @@
require_relative '../../spec_helper'
-require_relative 'shared/quo'
describe "Numeric#fdiv" do
it "coerces self with #to_f" do
diff --git a/spec/ruby/core/numeric/magnitude_spec.rb b/spec/ruby/core/numeric/magnitude_spec.rb
index 7a3290b036..1371dff21f 100644
--- a/spec/ruby/core/numeric/magnitude_spec.rb
+++ b/spec/ruby/core/numeric/magnitude_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../spec_helper"
require_relative 'shared/abs'
describe "Numeric#magnitude" do
diff --git a/spec/ruby/core/numeric/quo_spec.rb b/spec/ruby/core/numeric/quo_spec.rb
index b4a23fd476..6e3ce7a374 100644
--- a/spec/ruby/core/numeric/quo_spec.rb
+++ b/spec/ruby/core/numeric/quo_spec.rb
@@ -1,6 +1,5 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'shared/quo'
describe "Numeric#quo" do
it "returns the result of self divided by the given Integer as a Rational" do
@@ -20,7 +19,7 @@ describe "Numeric#quo" do
-> { 10.quo(0) }.should raise_error(ZeroDivisionError)
-> { -10.quo(0) }.should raise_error(ZeroDivisionError)
-> { bignum_value.quo(0) }.should raise_error(ZeroDivisionError)
- -> { -bignum_value.quo(0) }.should raise_error(ZeroDivisionError)
+ -> { (-bignum_value).quo(0) }.should raise_error(ZeroDivisionError)
end
it "calls #to_r to convert the object to a Rational" do
diff --git a/spec/ruby/core/numeric/remainder_spec.rb b/spec/ruby/core/numeric/remainder_spec.rb
index 1e2f5f3a96..674fa22d8e 100644
--- a/spec/ruby/core/numeric/remainder_spec.rb
+++ b/spec/ruby/core/numeric/remainder_spec.rb
@@ -6,6 +6,9 @@ describe "Numeric#remainder" do
@obj = NumericSpecs::Subclass.new
@result = mock("Numeric#% result")
@other = mock("Passed Object")
+ ruby_version_is "3.3" do
+ @other.should_receive(:coerce).with(@obj).and_return([@obj, @other])
+ end
end
it "returns the result of calling self#% with other if self is 0" do
diff --git a/spec/ruby/core/numeric/shared/quo.rb b/spec/ruby/core/numeric/shared/quo.rb
deleted file mode 100644
index 2392636fe7..0000000000
--- a/spec/ruby/core/numeric/shared/quo.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-describe :numeric_quo_18, shared: true do
- it "returns the result of calling self#/ with other" do
- obj = mock_numeric('numeric')
- obj.should_receive(:/).with(19).and_return(:result)
- obj.send(@method, 19).should == :result
- end
-end
diff --git a/spec/ruby/core/numeric/shared/step.rb b/spec/ruby/core/numeric/shared/step.rb
index 8b1a7bf307..977ec6de02 100644
--- a/spec/ruby/core/numeric/shared/step.rb
+++ b/spec/ruby/core/numeric/shared/step.rb
@@ -5,7 +5,7 @@ require_relative '../fixtures/classes'
# To be able to do it, the @step ivar must contain a Proc that transforms
# the step call arguments passed as positional arguments to the style of
# arguments pretended to test.
-describe :numeric_step, :shared => true do
+describe :numeric_step, shared: true do
before :each do
ScratchPad.record []
@prc = -> x { ScratchPad << x }
@@ -258,12 +258,6 @@ describe :numeric_step, :shared => true do
describe "when no block is given" do
step_enum_class = Enumerator::ArithmeticSequence
- ruby_version_is ""..."3.0" do
- it "returns an #{step_enum_class} when step is 0" do
- @step.call(1, 2, 0).should be_an_instance_of(step_enum_class)
- end
- end
-
it "returns an #{step_enum_class} when not passed a block and self > stop" do
@step.call(1, 0, 2).should be_an_instance_of(step_enum_class)
end
diff --git a/spec/ruby/core/numeric/step_spec.rb b/spec/ruby/core/numeric/step_spec.rb
index 095c474fec..1705fb1b4e 100644
--- a/spec/ruby/core/numeric/step_spec.rb
+++ b/spec/ruby/core/numeric/step_spec.rb
@@ -23,30 +23,8 @@ describe "Numeric#step" do
describe "when no block is given" do
step_enum_class = Enumerator::ArithmeticSequence
- ruby_version_is ""..."3.0" do
- it "returns an #{step_enum_class} when step is 0" do
- 1.step(5, 0).should be_an_instance_of(step_enum_class)
- end
-
- it "returns an #{step_enum_class} when step is 0.0" do
- 1.step(2, 0.0).should be_an_instance_of(step_enum_class)
- end
- end
-
describe "returned #{step_enum_class}" do
describe "size" do
- ruby_version_is ""..."3.0" do
- it "is infinity when step is 0" do
- enum = 1.step(5, 0)
- enum.size.should == Float::INFINITY
- end
-
- it "is infinity when step is 0.0" do
- enum = 1.step(2, 0.0)
- enum.size.should == Float::INFINITY
- end
- end
-
it "defaults to an infinite size" do
enum = 1.step
enum.size.should == Float::INFINITY
@@ -63,22 +41,6 @@ describe "Numeric#step" do
end
describe 'with keyword arguments' do
- ruby_version_is ""..."3.0" do
- it "doesn't raise an error when step is 0" do
- -> { 1.step(to: 5, by: 0) { break } }.should_not raise_error
- end
-
- it "doesn't raise an error when step is 0.0" do
- -> { 1.step(to: 2, by: 0.0) { break } }.should_not raise_error
- end
-
- it "should loop over self when step is 0 or 0.0" do
- 1.step(to: 2, by: 0.0).take(5).should eql [1.0, 1.0, 1.0, 1.0, 1.0]
- 1.step(to: 2, by: 0).take(5).should eql [1, 1, 1, 1, 1]
- 1.1.step(to: 2, by: 0).take(5).should eql [1.1, 1.1, 1.1, 1.1, 1.1]
- end
- end
-
describe "when no block is given" do
describe "returned Enumerator" do
describe "size" do
@@ -86,16 +48,6 @@ describe "Numeric#step" do
1.step(by: 42).size.should == infinity_value
end
- ruby_version_is ""..."3.0" do
- it "should return infinity_value when step is 0" do
- 1.step(to: 5, by: 0).size.should == infinity_value
- end
-
- it "should return infinity_value when step is 0.0" do
- 1.step(to: 2, by: 0.0).size.should == infinity_value
- end
- end
-
it "should return infinity_value when ascending towards a limit of Float::INFINITY" do
1.step(to: Float::INFINITY, by: 42).size.should == infinity_value
end
@@ -128,24 +80,12 @@ describe "Numeric#step" do
end
describe 'with mixed arguments' do
- ruby_version_is ""..."3.0" do
- it "doesn't raise an error when step is 0" do
- -> { 1.step(5, by: 0) { break } }.should_not raise_error
- end
-
- it "doesn't raise an error when step is 0.0" do
- -> { 1.step(2, by: 0.0) { break } }.should_not raise_error
- end
+ it " raises an ArgumentError when step is 0" do
+ -> { 1.step(5, by: 0) { break } }.should raise_error(ArgumentError)
end
- ruby_version_is "3.0" do
- it " raises an ArgumentError when step is 0" do
- -> { 1.step(5, by: 0) { break } }.should raise_error(ArgumentError)
- end
-
- it "raises an ArgumentError when step is 0.0" do
- -> { 1.step(2, by: 0.0) { break } }.should raise_error(ArgumentError)
- end
+ it "raises an ArgumentError when step is 0.0" do
+ -> { 1.step(2, by: 0.0) { break } }.should raise_error(ArgumentError)
end
it "raises a ArgumentError when limit and to are defined" do
@@ -156,26 +96,9 @@ describe "Numeric#step" do
-> { 1.step(5, 1, by: 5) { break } }.should raise_error(ArgumentError)
end
- ruby_version_is ""..."3.0" do
- it "should loop over self when step is 0 or 0.0" do
- 1.step(2, by: 0.0).take(5).should eql [1.0, 1.0, 1.0, 1.0, 1.0]
- 1.step(2, by: 0).take(5).should eql [1, 1, 1, 1, 1]
- 1.1.step(2, by: 0).take(5).should eql [1.1, 1.1, 1.1, 1.1, 1.1]
- end
- end
-
describe "when no block is given" do
describe "returned Enumerator" do
describe "size" do
- ruby_version_is ""..."3.0" do
- it "should return infinity_value when step is 0" do
- 1.step(5, by: 0).size.should == infinity_value
- end
-
- it "should return infinity_value when step is 0.0" do
- 1.step(2, by: 0.0).size.should == infinity_value
- end
- end
end
end
end
diff --git a/spec/ruby/core/objectspace/define_finalizer_spec.rb b/spec/ruby/core/objectspace/define_finalizer_spec.rb
index 281785b0a4..effecc41d0 100644
--- a/spec/ruby/core/objectspace/define_finalizer_spec.rb
+++ b/spec/ruby/core/objectspace/define_finalizer_spec.rb
@@ -52,7 +52,7 @@ describe "ObjectSpace.define_finalizer" do
Proc.new { puts "finalizer run" }
end
handler = scoped
- obj = "Test"
+ obj = +"Test"
ObjectSpace.define_finalizer(obj, handler)
exit 0
RUBY
@@ -60,60 +60,58 @@ describe "ObjectSpace.define_finalizer" do
ruby_exe(code, :args => "2>&1").should include("finalizer run\n")
end
- ruby_version_is "3.0" do
- it "warns if the finalizer has the object as the receiver" do
- code = <<-RUBY
- class CapturesSelf
- def initialize
- ObjectSpace.define_finalizer(self, proc {
- puts "finalizer run"
- })
- end
+ it "warns if the finalizer has the object as the receiver" do
+ code = <<-RUBY
+ class CapturesSelf
+ def initialize
+ ObjectSpace.define_finalizer(self, proc {
+ puts "finalizer run"
+ })
end
- CapturesSelf.new
- exit 0
- RUBY
+ end
+ CapturesSelf.new
+ exit 0
+ RUBY
- ruby_exe(code, :args => "2>&1").should include("warning: finalizer references object to be finalized\n")
- end
+ ruby_exe(code, :args => "2>&1").should include("warning: finalizer references object to be finalized\n")
+ end
- it "warns if the finalizer is a method bound to the receiver" do
- code = <<-RUBY
- class CapturesSelf
- def initialize
- ObjectSpace.define_finalizer(self, method(:finalize))
- end
- def finalize(id)
- puts "finalizer run"
- end
+ it "warns if the finalizer is a method bound to the receiver" do
+ code = <<-RUBY
+ class CapturesSelf
+ def initialize
+ ObjectSpace.define_finalizer(self, method(:finalize))
end
- CapturesSelf.new
- exit 0
- RUBY
+ def finalize(id)
+ puts "finalizer run"
+ end
+ end
+ CapturesSelf.new
+ exit 0
+ RUBY
- ruby_exe(code, :args => "2>&1").should include("warning: finalizer references object to be finalized\n")
- end
+ ruby_exe(code, :args => "2>&1").should include("warning: finalizer references object to be finalized\n")
+ end
- it "warns if the finalizer was a block in the receiver" do
- code = <<-RUBY
- class CapturesSelf
- def initialize
- ObjectSpace.define_finalizer(self) do
- puts "finalizer run"
- end
+ it "warns if the finalizer was a block in the receiver" do
+ code = <<-RUBY
+ class CapturesSelf
+ def initialize
+ ObjectSpace.define_finalizer(self) do
+ puts "finalizer run"
end
end
- CapturesSelf.new
- exit 0
- RUBY
+ end
+ CapturesSelf.new
+ exit 0
+ RUBY
- ruby_exe(code, :args => "2>&1").should include("warning: finalizer references object to be finalized\n")
- end
+ ruby_exe(code, :args => "2>&1").should include("warning: finalizer references object to be finalized\n")
end
it "calls a finalizer at exit even if it is self-referencing" do
code = <<-RUBY
- obj = "Test"
+ obj = +"Test"
handler = Proc.new { puts "finalizer run" }
ObjectSpace.define_finalizer(obj, handler)
exit 0
@@ -143,9 +141,9 @@ describe "ObjectSpace.define_finalizer" do
it "calls a finalizer defined in a finalizer running at exit" do
code = <<-RUBY
- obj = "Test"
+ obj = +"Test"
handler = Proc.new do
- obj2 = "Test"
+ obj2 = +"Test"
handler2 = Proc.new { puts "finalizer 2 run" }
ObjectSpace.define_finalizer(obj2, handler2)
exit 0
@@ -169,4 +167,26 @@ describe "ObjectSpace.define_finalizer" do
ruby_exe(code).lines.sort.should == ["finalized1\n", "finalized2\n"]
end
+
+ ruby_version_is "3.1" do
+ describe "when $VERBOSE is not nil" do
+ it "warns if an exception is raised in finalizer" do
+ code = <<-RUBY
+ ObjectSpace.define_finalizer(Object.new) { raise "finalizing" }
+ RUBY
+
+ ruby_exe(code, args: "2>&1").should include("warning: Exception in finalizer", "finalizing")
+ end
+ end
+
+ describe "when $VERBOSE is nil" do
+ it "does not warn even if an exception is raised in finalizer" do
+ code = <<-RUBY
+ ObjectSpace.define_finalizer(Object.new) { raise "finalizing" }
+ RUBY
+
+ ruby_exe(code, args: "2>&1", options: "-W0").should == ""
+ end
+ end
+ end
end
diff --git a/spec/ruby/core/objectspace/weakkeymap/delete_spec.rb b/spec/ruby/core/objectspace/weakkeymap/delete_spec.rb
new file mode 100644
index 0000000000..6e534b8ea8
--- /dev/null
+++ b/spec/ruby/core/objectspace/weakkeymap/delete_spec.rb
@@ -0,0 +1,40 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is '3.3' do
+ describe "ObjectSpace::WeakKeyMap#delete" do
+ it "removes the entry and returns the deleted value" do
+ m = ObjectSpace::WeakKeyMap.new
+ key = Object.new
+ value = Object.new
+ m[key] = value
+
+ m.delete(key).should == value
+ m.key?(key).should == false
+ end
+
+ it "uses equality semantic" do
+ m = ObjectSpace::WeakKeyMap.new
+ key = "foo".upcase
+ value = Object.new
+ m[key] = value
+
+ m.delete("foo".upcase).should == value
+ m.key?(key).should == false
+ end
+
+ it "calls supplied block if the key is not found" do
+ key = Object.new
+ m = ObjectSpace::WeakKeyMap.new
+ return_value = m.delete(key) do |yielded_key|
+ yielded_key.should == key
+ 5
+ end
+ return_value.should == 5
+ end
+
+ it "returns nil if the key is not found when no block is given" do
+ m = ObjectSpace::WeakMap.new
+ m.delete(Object.new).should == nil
+ end
+ end
+end
diff --git a/spec/ruby/core/objectspace/weakkeymap/element_reference_spec.rb b/spec/ruby/core/objectspace/weakkeymap/element_reference_spec.rb
new file mode 100644
index 0000000000..862480cd02
--- /dev/null
+++ b/spec/ruby/core/objectspace/weakkeymap/element_reference_spec.rb
@@ -0,0 +1,26 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is "3.3" do
+ describe "ObjectSpace::WeakKeyMap#[]" do
+ it "is faithful to the map's content" do
+ map = ObjectSpace::WeakKeyMap.new
+ key1, key2 = %w[a b].map(&:upcase)
+ ref1, ref2 = %w[x y]
+ map[key1] = ref1
+ map[key1].should == ref1
+ map[key1] = ref1
+ map[key1].should == ref1
+ map[key2] = ref2
+ map[key1].should == ref1
+ map[key2].should == ref2
+ end
+
+ it "matches using equality semantics" do
+ map = ObjectSpace::WeakKeyMap.new
+ key1, key2 = %w[a a].map(&:upcase)
+ ref = "x"
+ map[key1] = ref
+ map[key2].should == ref
+ end
+ end
+end
diff --git a/spec/ruby/core/objectspace/weakkeymap/element_set_spec.rb b/spec/ruby/core/objectspace/weakkeymap/element_set_spec.rb
new file mode 100644
index 0000000000..c427e01ca5
--- /dev/null
+++ b/spec/ruby/core/objectspace/weakkeymap/element_set_spec.rb
@@ -0,0 +1,71 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is "3.3" do
+ describe "ObjectSpace::WeakKeyMap#[]=" do
+ def should_accept(map, key, value)
+ (map[key] = value).should == value
+ map.should.key?(key)
+ map[key].should == value
+ end
+
+ def should_not_accept(map, key, value)
+ -> { map[key] = value }.should raise_error(ArgumentError)
+ end
+
+ it "is correct" do
+ map = ObjectSpace::WeakKeyMap.new
+ key1, key2 = %w[a b].map(&:upcase)
+ ref1, ref2 = %w[x y]
+ should_accept(map, key1, ref1)
+ should_accept(map, key1, ref1)
+ should_accept(map, key2, ref2)
+ map[key1].should == ref1
+ end
+
+ it "requires the keys to implement #hash" do
+ map = ObjectSpace::WeakKeyMap.new
+ -> { map[BasicObject.new] = 1 }.should raise_error(NoMethodError, /undefined method [`']hash' for an instance of BasicObject/)
+ end
+
+ it "accepts frozen keys or values" do
+ map = ObjectSpace::WeakKeyMap.new
+ x = Object.new
+ should_accept(map, x, true)
+ should_accept(map, x, false)
+ should_accept(map, x, 42)
+ should_accept(map, x, :foo)
+
+ y = Object.new.freeze
+ should_accept(map, x, y)
+ should_accept(map, y, x)
+ end
+
+ it "rejects symbols as keys" do
+ map = ObjectSpace::WeakKeyMap.new
+ should_not_accept(map, :foo, true)
+ should_not_accept(map, rand.to_s.to_sym, true)
+ end
+
+ it "rejects integers as keys" do
+ map = ObjectSpace::WeakKeyMap.new
+ should_not_accept(map, 42, true)
+ should_not_accept(map, 2 ** 68, true)
+ end
+
+ it "rejects floats as keys" do
+ map = ObjectSpace::WeakKeyMap.new
+ should_not_accept(map, 4.2, true)
+ end
+
+ it "rejects booleans as keys" do
+ map = ObjectSpace::WeakKeyMap.new
+ should_not_accept(map, true, true)
+ should_not_accept(map, false, true)
+ end
+
+ it "rejects nil as keys" do
+ map = ObjectSpace::WeakKeyMap.new
+ should_not_accept(map, nil, true)
+ end
+ end
+end
diff --git a/spec/ruby/core/objectspace/weakkeymap/getkey_spec.rb b/spec/ruby/core/objectspace/weakkeymap/getkey_spec.rb
new file mode 100644
index 0000000000..3af0186f27
--- /dev/null
+++ b/spec/ruby/core/objectspace/weakkeymap/getkey_spec.rb
@@ -0,0 +1,14 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is "3.3" do
+ describe "ObjectSpace::WeakKeyMap#getkey" do
+ it "returns the existing equal key" do
+ map = ObjectSpace::WeakKeyMap.new
+ key1, key2 = %w[a a].map(&:upcase)
+
+ map[key1] = true
+ map.getkey(key2).should equal(key1)
+ map.getkey("X").should == nil
+ end
+ end
+end
diff --git a/spec/ruby/core/objectspace/weakkeymap/inspect_spec.rb b/spec/ruby/core/objectspace/weakkeymap/inspect_spec.rb
new file mode 100644
index 0000000000..557fbc8733
--- /dev/null
+++ b/spec/ruby/core/objectspace/weakkeymap/inspect_spec.rb
@@ -0,0 +1,17 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is "3.3" do
+ describe "ObjectSpace::WeakKeyMap#inspect" do
+ it "only displays size in output" do
+ map = ObjectSpace::WeakKeyMap.new
+ key1, key2, key3 = "foo", "bar", "bar"
+ map.inspect.should =~ /\A\#<ObjectSpace::WeakKeyMap:0x\h+ size=0>\z/
+ map[key1] = 1
+ map.inspect.should =~ /\A\#<ObjectSpace::WeakKeyMap:0x\h+ size=1>\z/
+ map[key2] = 2
+ map.inspect.should =~ /\A\#<ObjectSpace::WeakKeyMap:0x\h+ size=2>\z/
+ map[key3] = 3
+ map.inspect.should =~ /\A\#<ObjectSpace::WeakKeyMap:0x\h+ size=2>\z/
+ end
+ end
+end
diff --git a/spec/ruby/core/objectspace/weakkeymap/key_spec.rb b/spec/ruby/core/objectspace/weakkeymap/key_spec.rb
new file mode 100644
index 0000000000..2af9c2b8e7
--- /dev/null
+++ b/spec/ruby/core/objectspace/weakkeymap/key_spec.rb
@@ -0,0 +1,33 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is "3.3" do
+ describe "ObjectSpace::WeakKeyMap#key?" do
+ it "recognizes keys in use" do
+ map = ObjectSpace::WeakKeyMap.new
+ key1, key2 = %w[a b].map(&:upcase)
+ ref1, ref2 = %w[x y]
+
+ map[key1] = ref1
+ map.key?(key1).should == true
+ map[key1] = ref1
+ map.key?(key1).should == true
+ map[key2] = ref2
+ map.key?(key2).should == true
+ end
+
+ it "matches using equality semantics" do
+ map = ObjectSpace::WeakKeyMap.new
+ key1, key2 = %w[a a].map(&:upcase)
+ ref = "x"
+ map[key1] = ref
+ map.key?(key2).should == true
+ end
+
+ it "reports true if the pair exists and the value is nil" do
+ map = ObjectSpace::WeakKeyMap.new
+ key = Object.new
+ map[key] = nil
+ map.key?(key).should == true
+ end
+ end
+end
diff --git a/spec/ruby/core/objectspace/weakmap/delete_spec.rb b/spec/ruby/core/objectspace/weakmap/delete_spec.rb
new file mode 100644
index 0000000000..302de264fb
--- /dev/null
+++ b/spec/ruby/core/objectspace/weakmap/delete_spec.rb
@@ -0,0 +1,30 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is '3.3' do
+ describe "ObjectSpace::WeakMap#delete" do
+ it "removes the entry and returns the deleted value" do
+ m = ObjectSpace::WeakMap.new
+ key = Object.new
+ value = Object.new
+ m[key] = value
+
+ m.delete(key).should == value
+ m.key?(key).should == false
+ end
+
+ it "calls supplied block if the key is not found" do
+ key = Object.new
+ m = ObjectSpace::WeakMap.new
+ return_value = m.delete(key) do |yielded_key|
+ yielded_key.should == key
+ 5
+ end
+ return_value.should == 5
+ end
+
+ it "returns nil if the key is not found when no block is given" do
+ m = ObjectSpace::WeakMap.new
+ m.delete(Object.new).should == nil
+ end
+ end
+end
diff --git a/spec/ruby/core/objectspace/weakmap/element_set_spec.rb b/spec/ruby/core/objectspace/weakmap/element_set_spec.rb
index 2b53650148..8588877158 100644
--- a/spec/ruby/core/objectspace/weakmap/element_set_spec.rb
+++ b/spec/ruby/core/objectspace/weakmap/element_set_spec.rb
@@ -17,45 +17,22 @@ describe "ObjectSpace::WeakMap#[]=" do
map[key1].should == ref1
end
- ruby_version_is ""..."2.7" do
- it "does not accept primitive or frozen keys or values" do
- map = ObjectSpace::WeakMap.new
- x = Object.new
- -> { map[true] = x }.should raise_error(ArgumentError)
- -> { map[false] = x }.should raise_error(ArgumentError)
- -> { map[nil] = x }.should raise_error(ArgumentError)
- -> { map[42] = x }.should raise_error(ArgumentError)
- -> { map[:foo] = x }.should raise_error(ArgumentError)
- -> { map[x] = true }.should raise_error(ArgumentError)
- -> { map[x] = false }.should raise_error(ArgumentError)
- -> { map[x] = nil }.should raise_error(ArgumentError)
- -> { map[x] = 42 }.should raise_error(ArgumentError)
- -> { map[x] = :foo }.should raise_error(ArgumentError)
-
- y = Object.new.freeze
- -> { map[x] = y}.should raise_error(FrozenError)
- -> { map[y] = x}.should raise_error(FrozenError)
- end
- end
-
- ruby_version_is "2.7" do
- it "accepts primitive or frozen keys or values" do
- map = ObjectSpace::WeakMap.new
- x = Object.new
- should_accept(map, true, x)
- should_accept(map, false, x)
- should_accept(map, nil, x)
- should_accept(map, 42, x)
- should_accept(map, :foo, x)
+ it "accepts primitive or frozen keys or values" do
+ map = ObjectSpace::WeakMap.new
+ x = Object.new
+ should_accept(map, true, x)
+ should_accept(map, false, x)
+ should_accept(map, nil, x)
+ should_accept(map, 42, x)
+ should_accept(map, :foo, x)
- should_accept(map, x, true)
- should_accept(map, x, false)
- should_accept(map, x, 42)
- should_accept(map, x, :foo)
+ should_accept(map, x, true)
+ should_accept(map, x, false)
+ should_accept(map, x, 42)
+ should_accept(map, x, :foo)
- y = Object.new.freeze
- should_accept(map, x, y)
- should_accept(map, y, x)
- end
+ y = Object.new.freeze
+ should_accept(map, x, y)
+ should_accept(map, y, x)
end
end
diff --git a/spec/ruby/core/objectspace/weakmap/shared/include.rb b/spec/ruby/core/objectspace/weakmap/shared/include.rb
index f9c174b6d1..1770eeac8b 100644
--- a/spec/ruby/core/objectspace/weakmap/shared/include.rb
+++ b/spec/ruby/core/objectspace/weakmap/shared/include.rb
@@ -20,15 +20,11 @@ describe :weakmap_include?, shared: true do
map.send(@method, key2).should == false
end
- ruby_version_is "2.7" do
- ruby_bug "#16826", "2.7.0"..."2.7.2" do
- it "reports true if the pair exists and the value is nil" do
- map = ObjectSpace::WeakMap.new
- key = Object.new
- map[key] = nil
- map.size.should == 1
- map.send(@method, key).should == true
- end
- end
+ it "reports true if the pair exists and the value is nil" do
+ map = ObjectSpace::WeakMap.new
+ key = Object.new
+ map[key] = nil
+ map.size.should == 1
+ map.send(@method, key).should == true
end
end
diff --git a/spec/ruby/core/proc/arity_spec.rb b/spec/ruby/core/proc/arity_spec.rb
index f7cb5ad0f8..5c7728cb30 100644
--- a/spec/ruby/core/proc/arity_spec.rb
+++ b/spec/ruby/core/proc/arity_spec.rb
@@ -268,6 +268,14 @@ describe "Proc#arity" do
@a.arity.should == 3
@b.arity.should == 3
end
+
+ # implicit rest
+ evaluate <<-ruby do
+ @a = lambda { |a, | }
+ ruby
+
+ @a.arity.should == 1
+ end
end
context "returns negative values" do
@@ -530,6 +538,14 @@ describe "Proc#arity" do
@a.arity.should == 1
@b.arity.should == 5
end
+
+ # implicit rest
+ evaluate <<-ruby do
+ @a = proc { |a, | }
+ ruby
+
+ @a.arity.should == 1
+ end
end
context "returns negative values" do
diff --git a/spec/ruby/core/proc/block_pass_spec.rb b/spec/ruby/core/proc/block_pass_spec.rb
index 99255139d4..411c0bf3db 100644
--- a/spec/ruby/core/proc/block_pass_spec.rb
+++ b/spec/ruby/core/proc/block_pass_spec.rb
@@ -19,25 +19,3 @@ describe "Proc as a block pass argument" do
p.should == p2
end
end
-
-ruby_version_is ""..."2.7" do
- describe "Proc as an implicit block pass argument" do
- def revivify
- Proc.new
- end
-
- it "remains the same object if re-vivified by the target method" do
- p = Proc.new {}
- p2 = revivify(&p)
- p.should equal p2
- p.should == p2
- end
-
- it "remains the same object if reconstructed with Proc.new" do
- p = Proc.new {}
- p2 = Proc.new(&p)
- p.should equal p2
- p.should == p2
- end
- end
-end
diff --git a/spec/ruby/core/proc/clone_spec.rb b/spec/ruby/core/proc/clone_spec.rb
index a1a1292654..7eca9c561e 100644
--- a/spec/ruby/core/proc/clone_spec.rb
+++ b/spec/ruby/core/proc/clone_spec.rb
@@ -3,4 +3,13 @@ require_relative 'shared/dup'
describe "Proc#clone" do
it_behaves_like :proc_dup, :clone
+
+ ruby_bug "cloning a frozen proc is broken on Ruby 3.3", "3.3"..."3.4" do
+ it "preserves frozen status" do
+ proc = Proc.new { }
+ proc.freeze
+ proc.frozen?.should == true
+ proc.clone.frozen?.should == true
+ end
+ end
end
diff --git a/spec/ruby/core/proc/compose_spec.rb b/spec/ruby/core/proc/compose_spec.rb
index 94814d11bc..9e9b57e06f 100644
--- a/spec/ruby/core/proc/compose_spec.rb
+++ b/spec/ruby/core/proc/compose_spec.rb
@@ -37,42 +37,22 @@ describe "Proc#<<" do
(f << g).should_not.lambda?
end
- ruby_version_is(''...'3.0') do
- it "is a Proc when other is lambda" do
- f = proc { |x| x * x }
- g = -> x { x + x }
-
- (f << g).is_a?(Proc).should == true
- (f << g).should_not.lambda?
- end
-
- it "is a lambda when self is lambda" do
- f = -> x { x * x }
- g = proc { |x| x + x }
-
- (f << g).is_a?(Proc).should == true
- (f << g).should.lambda?
- end
- end
-
- ruby_version_is('3.0') do
- it "is a lambda when parameter is lambda" do
- f = -> x { x * x }
- g = proc { |x| x + x }
- lambda_proc = -> x { x }
+ it "is a lambda when parameter is lambda" do
+ f = -> x { x * x }
+ g = proc { |x| x + x }
+ lambda_proc = -> x { x }
- # lambda << proc
- (f << g).is_a?(Proc).should == true
- (f << g).should_not.lambda?
+ # lambda << proc
+ (f << g).is_a?(Proc).should == true
+ (f << g).should_not.lambda?
- # lambda << lambda
- (f << lambda_proc).is_a?(Proc).should == true
- (f << lambda_proc).should.lambda?
+ # lambda << lambda
+ (f << lambda_proc).is_a?(Proc).should == true
+ (f << lambda_proc).should.lambda?
- # proc << lambda
- (g << f).is_a?(Proc).should == true
- (g << f).should.lambda?
- end
+ # proc << lambda
+ (g << f).is_a?(Proc).should == true
+ (g << f).should.lambda?
end
it "may accept multiple arguments" do
diff --git a/spec/ruby/core/proc/dup_spec.rb b/spec/ruby/core/proc/dup_spec.rb
index 6da2f3080c..dd19b3c1e9 100644
--- a/spec/ruby/core/proc/dup_spec.rb
+++ b/spec/ruby/core/proc/dup_spec.rb
@@ -3,4 +3,11 @@ require_relative 'shared/dup'
describe "Proc#dup" do
it_behaves_like :proc_dup, :dup
+
+ it "resets frozen status" do
+ proc = Proc.new { }
+ proc.freeze
+ proc.frozen?.should == true
+ proc.dup.frozen?.should == false
+ end
end
diff --git a/spec/ruby/core/proc/eql_spec.rb b/spec/ruby/core/proc/eql_spec.rb
index 06aee272e5..ad8f6749fc 100644
--- a/spec/ruby/core/proc/eql_spec.rb
+++ b/spec/ruby/core/proc/eql_spec.rb
@@ -2,11 +2,5 @@ require_relative '../../spec_helper'
require_relative 'shared/equal'
describe "Proc#eql?" do
- ruby_version_is ""..."3.0" do
- it_behaves_like :proc_equal_undefined, :eql?
- end
-
- ruby_version_is "3.0" do
- it_behaves_like :proc_equal, :eql?
- end
+ it_behaves_like :proc_equal, :eql?
end
diff --git a/spec/ruby/core/proc/equal_value_spec.rb b/spec/ruby/core/proc/equal_value_spec.rb
index ee88c0537d..ec7f274732 100644
--- a/spec/ruby/core/proc/equal_value_spec.rb
+++ b/spec/ruby/core/proc/equal_value_spec.rb
@@ -2,11 +2,5 @@ require_relative '../../spec_helper'
require_relative 'shared/equal'
describe "Proc#==" do
- ruby_version_is ""..."3.0" do
- it_behaves_like :proc_equal_undefined, :==
- end
-
- ruby_version_is "3.0" do
- it_behaves_like :proc_equal, :==
- end
+ it_behaves_like :proc_equal, :==
end
diff --git a/spec/ruby/core/proc/fixtures/proc_aref.rb b/spec/ruby/core/proc/fixtures/proc_aref.rb
index a305667797..8ee355b14c 100644
--- a/spec/ruby/core/proc/fixtures/proc_aref.rb
+++ b/spec/ruby/core/proc/fixtures/proc_aref.rb
@@ -1,3 +1,4 @@
+# frozen_string_literal: false
module ProcArefSpecs
def self.aref
proc {|a| a }["sometext"]
diff --git a/spec/ruby/core/proc/lambda_spec.rb b/spec/ruby/core/proc/lambda_spec.rb
index b2d3f50350..5c3c38fc2a 100644
--- a/spec/ruby/core/proc/lambda_spec.rb
+++ b/spec/ruby/core/proc/lambda_spec.rb
@@ -14,9 +14,11 @@ describe "Proc#lambda?" do
Proc.new {}.lambda?.should be_false
end
- it "is preserved when passing a Proc with & to the lambda keyword" do
- suppress_warning {lambda(&->{})}.lambda?.should be_true
- suppress_warning {lambda(&proc{})}.lambda?.should be_false
+ ruby_version_is ""..."3.3" do
+ it "is preserved when passing a Proc with & to the lambda keyword" do
+ suppress_warning {lambda(&->{})}.lambda?.should be_true
+ suppress_warning {lambda(&proc{})}.lambda?.should be_false
+ end
end
it "is preserved when passing a Proc with & to the proc keyword" do
diff --git a/spec/ruby/core/proc/new_spec.rb b/spec/ruby/core/proc/new_spec.rb
index 6d5eb67a4b..b2b7387756 100644
--- a/spec/ruby/core/proc/new_spec.rb
+++ b/spec/ruby/core/proc/new_spec.rb
@@ -94,20 +94,6 @@ describe "Proc.new with an associated block" do
obj.first.should == :a
obj.second.should == 2
end
-
- ruby_version_is ""..."2.7" do
- it "returns a new Proc instance from the block passed to the containing method" do
- prc = ProcSpecs.new_proc_in_method { "hello" }
- prc.should be_an_instance_of(Proc)
- prc.call.should == "hello"
- end
-
- it "returns a new Proc instance from the block passed to the containing method" do
- prc = ProcSpecs.new_proc_subclass_in_method { "hello" }
- prc.should be_an_instance_of(ProcSpecs::ProcSubclass)
- prc.call.should == "hello"
- end
- end
end
describe "Proc.new with a block argument" do
@@ -180,59 +166,13 @@ describe "Proc.new without a block" do
-> { ProcSpecs.new_proc_subclass_in_method }.should raise_error(ArgumentError)
end
- ruby_version_is ""..."2.7" do
- it "uses the implicit block from an enclosing method" do
- def some_method
- Proc.new
- end
-
- prc = some_method { "hello" }
-
- prc.call.should == "hello"
- end
-
- it "uses the implicit block from an enclosing method when called inside a block" do
- def some_method
- proc do |&block|
- Proc.new
- end.call { "failing" }
- end
- prc = some_method { "hello" }
-
- prc.call.should == "hello"
- end
- end
-
- ruby_version_is "2.7"..."3.0" do
- it "can be created if invoked from within a method with a block" do
- -> { ProcSpecs.new_proc_in_method { "hello" } }.should complain(/Capturing the given block using Proc.new is deprecated/)
- end
-
- it "can be created if invoked on a subclass from within a method with a block" do
- -> { ProcSpecs.new_proc_subclass_in_method { "hello" } }.should complain(/Capturing the given block using Proc.new is deprecated/)
- end
-
-
- it "can be create when called with no block" do
- def some_method
- Proc.new
- end
-
- -> {
- some_method { "hello" }
- }.should complain(/Capturing the given block using Proc.new is deprecated/)
+ it "raises an ArgumentError when passed no block" do
+ def some_method
+ Proc.new
end
- end
- ruby_version_is "3.0" do
- it "raises an ArgumentError when passed no block" do
- def some_method
- Proc.new
- end
-
- -> { ProcSpecs.new_proc_in_method { "hello" } }.should raise_error(ArgumentError, 'tried to create Proc object without a block')
- -> { ProcSpecs.new_proc_subclass_in_method { "hello" } }.should raise_error(ArgumentError, 'tried to create Proc object without a block')
- -> { some_method { "hello" } }.should raise_error(ArgumentError, 'tried to create Proc object without a block')
- end
+ -> { ProcSpecs.new_proc_in_method { "hello" } }.should raise_error(ArgumentError, 'tried to create Proc object without a block')
+ -> { ProcSpecs.new_proc_subclass_in_method { "hello" } }.should raise_error(ArgumentError, 'tried to create Proc object without a block')
+ -> { some_method { "hello" } }.should raise_error(ArgumentError, 'tried to create Proc object without a block')
end
end
diff --git a/spec/ruby/core/proc/parameters_spec.rb b/spec/ruby/core/proc/parameters_spec.rb
index 11a38b66e3..972596d2ea 100644
--- a/spec/ruby/core/proc/parameters_spec.rb
+++ b/spec/ruby/core/proc/parameters_spec.rb
@@ -20,6 +20,31 @@ describe "Proc#parameters" do
proc {|x| }.parameters.first.first.should == :opt
end
+ ruby_version_is "3.2" do
+ it "sets the first element of each sub-Array to :req for required argument if lambda keyword used" do
+ proc {|x| }.parameters(lambda: true).first.first.should == :req
+ proc {|y,*x| }.parameters(lambda: true).first.first.should == :req
+ end
+
+ it "regards named parameters in procs as required if lambda keyword used" do
+ proc {|x| }.parameters(lambda: true).first.first.should == :req
+ end
+
+ it "regards named parameters in lambda as optional if lambda: false keyword used" do
+ -> x { }.parameters(lambda: false).first.first.should == :opt
+ end
+
+ 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
+ end
+
it "regards optional keyword parameters in procs as optional" do
proc {|x: :y| }.parameters.first.first.should == :key
end
@@ -76,19 +101,38 @@ describe "Proc#parameters" do
proc {|&block| }.parameters.first.last.should == :block
end
- it "ignores unnamed rest args" do
+ it "ignores unnamed rest arguments" do
-> x {}.parameters.should == [[:req, :x]]
end
+ it "ignores implicit rest arguments" do
+ proc { |x, | }.parameters.should == [[:opt, :x]]
+ -> x { }.parameters.should == [[:req, :x]]
+ end
+
ruby_version_is '3.2' do
- it "adds * rest arg for \"star\" argument" do
- -> x, * {}.parameters.should == [[:req, :x], [:rest, :*]]
+ it "adds rest arg with name * for \"star\" argument" do
+ -> * {}.parameters.should == [[:rest, :*]]
+ end
+
+ it "adds keyrest arg with ** as a name for \"double star\" argument" do
+ -> ** {}.parameters.should == [[:keyrest, :**]]
end
end
ruby_version_is ''...'3.2' do
it "adds nameless rest arg for \"star\" argument" do
- -> x, * {}.parameters.should == [[:req, :x], [:rest]]
+ -> * {}.parameters.should == [[:rest]]
+ end
+
+ it "adds nameless keyrest arg for \"double star\" argument" do
+ -> ** {}.parameters.should == [[:keyrest]]
+ end
+ end
+
+ ruby_version_is '3.1' do
+ it "adds block arg with name & for anonymous block argument" do
+ eval('-> & {}.parameters').should == [[:block, :&]]
end
end
@@ -100,4 +144,34 @@ describe "Proc#parameters" do
local_is_not_parameter = {}
end.parameters.should == [[:rest, :args], [:block, :blk]]
end
+
+ it "returns all parameters defined with the name _ as _" do
+ proc = proc {|_, _, _ = 1, *_, _:, _: 2, **_, &_| }
+ proc.parameters.should == [
+ [:opt, :_],
+ [:opt, :_],
+ [:opt, :_],
+ [:rest, :_],
+ [:keyreq, :_],
+ [:key, :_],
+ [:keyrest, :_],
+ [:block, :_]
+ ]
+
+ lambda = -> _, _, _ = 1, *_, _:, _: 2, **_, &_ {}
+ lambda.parameters.should == [
+ [:req, :_],
+ [:req, :_],
+ [:opt, :_],
+ [:rest, :_],
+ [:keyreq, :_],
+ [:key, :_],
+ [:keyrest, :_],
+ [:block, :_]
+ ]
+ end
+
+ it "returns :nokey for **nil parameter" do
+ proc { |**nil| }.parameters.should == [[:nokey]]
+ end
end
diff --git a/spec/ruby/core/proc/ruby2_keywords_spec.rb b/spec/ruby/core/proc/ruby2_keywords_spec.rb
index 4f6bc151b6..ab67302231 100644
--- a/spec/ruby/core/proc/ruby2_keywords_spec.rb
+++ b/spec/ruby/core/proc/ruby2_keywords_spec.rb
@@ -1,64 +1,56 @@
require_relative '../../spec_helper'
-ruby_version_is "2.7" do
- describe "Proc#ruby2_keywords" do
- it "marks the final hash argument as keyword hash" do
- f = -> *a { a.last }
- f.ruby2_keywords
-
- last = f.call(1, 2, a: "a")
- Hash.ruby2_keywords_hash?(last).should == true
- end
+describe "Proc#ruby2_keywords" do
+ it "marks the final hash argument as keyword hash" do
+ f = -> *a { a.last }
+ f.ruby2_keywords
- ruby_version_is "2.7" ... "3.0" do
- it "fixes delegation warnings when calling a method accepting keywords" do
- obj = Object.new
- def obj.foo(*a, **b) end
+ last = f.call(1, 2, a: "a")
+ Hash.ruby2_keywords_hash?(last).should == true
+ end
- f = -> *a { obj.foo(*a) }
+ it "applies to the underlying method and applies across duplication" do
+ f1 = -> *a { a.last }
+ f1.ruby2_keywords
+ f2 = f1.dup
- -> { f.call(1, 2, {a: "a"}) }.should complain(/Using the last argument as keyword parameters is deprecated/)
- f.ruby2_keywords
- -> { f.call(1, 2, {a: "a"}) }.should_not complain
- end
+ Hash.ruby2_keywords_hash?(f1.call(1, 2, a: "a")).should == true
+ Hash.ruby2_keywords_hash?(f2.call(1, 2, a: "a")).should == true
- it "fixes delegation warnings when calling a proc accepting keywords" do
- g = -> *a, **b { }
- f = -> *a { g.call(*a) }
+ f3 = -> *a { a.last }
+ f4 = f3.dup
+ f3.ruby2_keywords
- -> { f.call(1, 2, {a: "a"}) }.should complain(/Using the last argument as keyword parameters is deprecated/)
- f.ruby2_keywords
- -> { f.call(1, 2, {a: "a"}) }.should_not complain
- end
- end
+ Hash.ruby2_keywords_hash?(f3.call(1, 2, a: "a")).should == true
+ Hash.ruby2_keywords_hash?(f4.call(1, 2, a: "a")).should == true
+ end
- it "returns self" do
- f = -> *a { }
- f.ruby2_keywords.should equal f
- end
+ it "returns self" do
+ f = -> *a { }
+ f.ruby2_keywords.should equal f
+ end
- it "prints warning when a proc does not accept argument splat" do
- f = -> a, b, c { }
+ it "prints warning when a proc does not accept argument splat" do
+ f = -> a, b, c { }
- -> {
- f.ruby2_keywords
- }.should complain(/Skipping set of ruby2_keywords flag for/)
- end
+ -> {
+ f.ruby2_keywords
+ }.should complain(/Skipping set of ruby2_keywords flag for/)
+ end
- it "prints warning when a proc accepts keywords" do
- f = -> a:, b: { }
+ it "prints warning when a proc accepts keywords" do
+ f = -> a:, b: { }
- -> {
- f.ruby2_keywords
- }.should complain(/Skipping set of ruby2_keywords flag for/)
- end
+ -> {
+ f.ruby2_keywords
+ }.should complain(/Skipping set of ruby2_keywords flag for/)
+ end
- it "prints warning when a proc accepts keyword splat" do
- f = -> **a { }
+ it "prints warning when a proc accepts keyword splat" do
+ f = -> **a { }
- -> {
- f.ruby2_keywords
- }.should complain(/Skipping set of ruby2_keywords flag for/)
- end
+ -> {
+ f.ruby2_keywords
+ }.should complain(/Skipping set of ruby2_keywords flag for/)
end
end
diff --git a/spec/ruby/core/proc/shared/compose.rb b/spec/ruby/core/proc/shared/compose.rb
index e3ae7f76b8..3d3f3b310d 100644
--- a/spec/ruby/core/proc/shared/compose.rb
+++ b/spec/ruby/core/proc/shared/compose.rb
@@ -1,47 +1,22 @@
describe :proc_compose, shared: true do
- ruby_version_is ""..."2.7" do
- it "raises NoMethodError when called if passed not callable object" do
- not_callable = Object.new
- composed = @object.call.send(@method, not_callable)
+ it "raises TypeError if passed not callable object" do
+ lhs = @object.call
+ not_callable = Object.new
- -> {
- composed.call('a')
- }.should raise_error(NoMethodError, /undefined method `call' for/)
+ -> {
+ lhs.send(@method, not_callable)
+ }.should raise_error(TypeError, "callable object is expected")
- end
-
- it "when called does not try to coerce argument with #to_proc" do
- succ = Object.new
- def succ.to_proc(s); s.succ; end
-
- composed = @object.call.send(@method, succ)
-
- -> {
- composed.call('a')
- }.should raise_error(NoMethodError, /undefined method `call' for/)
- end
end
- ruby_version_is "2.7" do # https://bugs.ruby-lang.org/issues/15428
- it "raises TypeError if passed not callable object" do
- lhs = @object.call
- not_callable = Object.new
-
- -> {
- lhs.send(@method, not_callable)
- }.should raise_error(TypeError, "callable object is expected")
-
- end
-
- it "does not try to coerce argument with #to_proc" do
- lhs = @object.call
+ it "does not try to coerce argument with #to_proc" do
+ lhs = @object.call
- succ = Object.new
- def succ.to_proc(s); s.succ; end
+ succ = Object.new
+ def succ.to_proc(s); s.succ; end
- -> {
- lhs.send(@method, succ)
- }.should raise_error(TypeError, "callable object is expected")
- end
+ -> {
+ lhs.send(@method, succ)
+ }.should raise_error(TypeError, "callable object is expected")
end
end
diff --git a/spec/ruby/core/proc/shared/dup.rb b/spec/ruby/core/proc/shared/dup.rb
index eda1d6929d..c419a4078a 100644
--- a/spec/ruby/core/proc/shared/dup.rb
+++ b/spec/ruby/core/proc/shared/dup.rb
@@ -7,4 +7,35 @@ describe :proc_dup, shared: true do
a.call.should == b.call
end
+
+ ruby_version_is "3.2" do
+ it "returns an instance of subclass" do
+ cl = Class.new(Proc)
+
+ cl.new{}.send(@method).class.should == cl
+ end
+ end
+
+ ruby_version_is "3.4" do
+ it "copies instance variables" do
+ proc = -> { "hello" }
+ proc.instance_variable_set(:@ivar, 1)
+ cl = proc.send(@method)
+ cl.instance_variables.should == [:@ivar]
+ end
+
+ it "copies the finalizer" do
+ code = <<-RUBY
+ obj = Proc.new { }
+
+ ObjectSpace.define_finalizer(obj, Proc.new { STDOUT.write "finalized\n" })
+
+ obj.clone
+
+ exit 0
+ RUBY
+
+ ruby_exe(code).lines.sort.should == ["finalized\n", "finalized\n"]
+ end
+ end
end
diff --git a/spec/ruby/core/proc/shared/equal.rb b/spec/ruby/core/proc/shared/equal.rb
index 0c0020ca7f..d0503fb064 100644
--- a/spec/ruby/core/proc/shared/equal.rb
+++ b/spec/ruby/core/proc/shared/equal.rb
@@ -81,20 +81,3 @@ describe :proc_equal, shared: true do
p.send(@method, p2).should be_false
end
end
-
-describe :proc_equal_undefined, shared: true do
- it "is not defined" do
- Proc.should_not have_instance_method(@method, false)
- end
-
- it "returns false if other is a dup of the original" do
- p = proc { :foo }
- p.send(@method, p.dup).should be_false
-
- p = Proc.new { :foo }
- p.send(@method, p.dup).should be_false
-
- p = -> { :foo }
- p.send(@method, p.dup).should be_false
- end
-end
diff --git a/spec/ruby/core/proc/shared/to_s.rb b/spec/ruby/core/proc/shared/to_s.rb
index 7f167a3d9d..a52688a89f 100644
--- a/spec/ruby/core/proc/shared/to_s.rb
+++ b/spec/ruby/core/proc/shared/to_s.rb
@@ -1,9 +1,7 @@
describe :proc_to_s, shared: true do
- sep = ruby_version_is("2.7") ? " " : "@"
-
describe "for a proc created with Proc.new" do
it "returns a description including file and line number" do
- Proc.new { "hello" }.send(@method).should =~ /^#<Proc:([^ ]*?)#{sep}#{Regexp.escape __FILE__}:#{__LINE__ }>$/
+ Proc.new { "hello" }.send(@method).should =~ /^#<Proc:([^ ]*?) #{Regexp.escape __FILE__}:#{__LINE__ }>$/
end
it "has a binary encoding" do
@@ -13,7 +11,7 @@ describe :proc_to_s, shared: true do
describe "for a proc created with lambda" do
it "returns a description including '(lambda)' and including file and line number" do
- -> { "hello" }.send(@method).should =~ /^#<Proc:([^ ]*?)#{sep}#{Regexp.escape __FILE__}:#{__LINE__ } \(lambda\)>$/
+ -> { "hello" }.send(@method).should =~ /^#<Proc:([^ ]*?) #{Regexp.escape __FILE__}:#{__LINE__ } \(lambda\)>$/
end
it "has a binary encoding" do
@@ -23,7 +21,7 @@ describe :proc_to_s, shared: true do
describe "for a proc created with proc" do
it "returns a description including file and line number" do
- proc { "hello" }.send(@method).should =~ /^#<Proc:([^ ]*?)#{sep}#{Regexp.escape __FILE__}:#{__LINE__ }>$/
+ proc { "hello" }.send(@method).should =~ /^#<Proc:([^ ]*?) #{Regexp.escape __FILE__}:#{__LINE__ }>$/
end
it "has a binary encoding" do
@@ -33,13 +31,13 @@ describe :proc_to_s, shared: true do
describe "for a proc created with UnboundMethod#to_proc" do
it "returns a description including '(lambda)' and optionally including file and line number" do
- def hello; end
- s = method("hello").to_proc.send(@method)
- if s.include? __FILE__
- s.should =~ /^#<Proc:([^ ]*?)#{sep}#{Regexp.escape __FILE__}:#{__LINE__ - 3} \(lambda\)>$/
- else
- s.should =~ /^#<Proc:([^ ]*?) \(lambda\)>$/
- end
+ def hello; end
+ s = method("hello").to_proc.send(@method)
+ if s.include? __FILE__
+ s.should =~ /^#<Proc:([^ ]*?) #{Regexp.escape __FILE__}:#{__LINE__ - 3} \(lambda\)>$/
+ else
+ s.should =~ /^#<Proc:([^ ]*?) \(lambda\)>$/
+ end
end
it "has a binary encoding" do
diff --git a/spec/ruby/core/proc/source_location_spec.rb b/spec/ruby/core/proc/source_location_spec.rb
index f268499b82..a8b99287d5 100644
--- a/spec/ruby/core/proc/source_location_spec.rb
+++ b/spec/ruby/core/proc/source_location_spec.rb
@@ -19,19 +19,19 @@ describe "Proc#source_location" do
it "sets the first value to the path of the file in which the proc was defined" do
file = @proc.source_location.first
file.should be_an_instance_of(String)
- file.should == File.realpath('../fixtures/source_location.rb', __FILE__)
+ file.should == File.realpath('fixtures/source_location.rb', __dir__)
file = @proc_new.source_location.first
file.should be_an_instance_of(String)
- file.should == File.realpath('../fixtures/source_location.rb', __FILE__)
+ file.should == File.realpath('fixtures/source_location.rb', __dir__)
file = @lambda.source_location.first
file.should be_an_instance_of(String)
- file.should == File.realpath('../fixtures/source_location.rb', __FILE__)
+ file.should == File.realpath('fixtures/source_location.rb', __dir__)
file = @method.source_location.first
file.should be_an_instance_of(String)
- file.should == File.realpath('../fixtures/source_location.rb', __FILE__)
+ 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
@@ -83,4 +83,9 @@ describe "Proc#source_location" do
proc.source_location.should == nil
end
+
+ it "works for eval with a given line" do
+ proc = eval('-> {}', nil, "foo", 100)
+ proc.source_location.should == ["foo", 100]
+ end
end
diff --git a/spec/ruby/core/process/_fork_spec.rb b/spec/ruby/core/process/_fork_spec.rb
new file mode 100644
index 0000000000..6f711ad2dd
--- /dev/null
+++ b/spec/ruby/core/process/_fork_spec.rb
@@ -0,0 +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
+
+ guard_not -> { Process.respond_to?(:fork) } do
+ it "raises a NotImplementedError when called" do
+ -> { Process._fork }.should raise_error(NotImplementedError)
+ end
+ end
+
+ guard -> { Process.respond_to?(:fork) } do
+ it "is called by Process#fork" do
+ Process.should_receive(:_fork).once.and_return(42)
+
+ pid = Process.fork {}
+ pid.should equal(42)
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/process/argv0_spec.rb b/spec/ruby/core/process/argv0_spec.rb
new file mode 100644
index 0000000000..f5aba719e9
--- /dev/null
+++ b/spec/ruby/core/process/argv0_spec.rb
@@ -0,0 +1,25 @@
+require_relative '../../spec_helper'
+
+describe "Process.argv0" do
+ it "returns a String" do
+ Process.argv0.should be_kind_of(String)
+ end
+
+ it "is the path given as the main script and the same as __FILE__" do
+ script = "fixtures/argv0.rb"
+
+ Dir.chdir(__dir__) do
+ ruby_exe(script).should == "#{script}\n#{script}\nOK"
+ end
+ end
+
+ ruby_bug "#19597", ""..."3.3" do
+ it "returns a frozen object" do
+ Process.argv0.should.frozen?
+ end
+ end
+
+ it "returns every time the same object" do
+ Process.argv0.should.equal?(Process.argv0)
+ end
+end
diff --git a/spec/ruby/core/process/clock_gettime_spec.rb b/spec/ruby/core/process/clock_gettime_spec.rb
index 59e1406e02..6c1a52f21e 100644
--- a/spec/ruby/core/process/clock_gettime_spec.rb
+++ b/spec/ruby/core/process/clock_gettime_spec.rb
@@ -52,7 +52,7 @@ describe "Process.clock_gettime" do
end
# These specs need macOS 10.12+ / darwin 16+
- guard_not -> { platform_is_not(:darwin) or RUBY_PLATFORM[/darwin\d+/].to_i >= 16 } do
+ guard -> { platform_is_not(:darwin) or kernel_version_is '16' } do
platform_is :linux, :openbsd, :darwin do
it "CLOCK_PROCESS_CPUTIME_ID" do
Process.clock_gettime(Process::CLOCK_PROCESS_CPUTIME_ID).should be_an_instance_of(Float)
@@ -65,20 +65,6 @@ describe "Process.clock_gettime" do
end
end
- platform_is :freebsd, :openbsd do
- it "CLOCK_VIRTUAL" do
- Process.clock_gettime(Process::CLOCK_VIRTUAL).should be_an_instance_of(Float)
- end
-
- it "CLOCK_PROF" do
- Process.clock_gettime(Process::CLOCK_PROF).should be_an_instance_of(Float)
- end
-
- it "CLOCK_UPTIME" do
- Process.clock_gettime(Process::CLOCK_UPTIME).should be_an_instance_of(Float)
- end
- end
-
platform_is :linux, :darwin do
it "CLOCK_MONOTONIC_RAW" do
Process.clock_gettime(Process::CLOCK_MONOTONIC_RAW).should be_an_instance_of(Float)
@@ -95,42 +81,71 @@ describe "Process.clock_gettime" do
Process.clock_gettime(Process::CLOCK_UPTIME_RAW_APPROX).should be_an_instance_of(Float)
end
end
+ end
- platform_is :freebsd do
- it "CLOCK_REALTIME_FAST and CLOCK_REALTIME_PRECISE" do
- Process.clock_gettime(Process::CLOCK_REALTIME_FAST).should be_an_instance_of(Float)
- Process.clock_gettime(Process::CLOCK_REALTIME_PRECISE).should be_an_instance_of(Float)
- end
+ platform_is :freebsd do
+ it "CLOCK_VIRTUAL" do
+ Process.clock_gettime(Process::CLOCK_VIRTUAL).should be_an_instance_of(Float)
+ end
- it "CLOCK_MONOTONIC_FAST and CLOCK_MONOTONIC_PRECISE" do
- Process.clock_gettime(Process::CLOCK_MONOTONIC_FAST).should be_an_instance_of(Float)
- Process.clock_gettime(Process::CLOCK_MONOTONIC_PRECISE).should be_an_instance_of(Float)
- end
+ it "CLOCK_PROF" do
+ Process.clock_gettime(Process::CLOCK_PROF).should be_an_instance_of(Float)
+ end
+ end
- it "CLOCK_UPTIME_FAST and CLOCK_UPTIME_PRECISE" do
- Process.clock_gettime(Process::CLOCK_UPTIME_FAST).should be_an_instance_of(Float)
- Process.clock_gettime(Process::CLOCK_UPTIME_PRECISE).should be_an_instance_of(Float)
- end
+ platform_is :freebsd, :openbsd do
+ it "CLOCK_UPTIME" do
+ Process.clock_gettime(Process::CLOCK_UPTIME).should be_an_instance_of(Float)
+ end
+ end
- it "CLOCK_SECOND" do
- Process.clock_gettime(Process::CLOCK_SECOND).should be_an_instance_of(Float)
- end
+ platform_is :freebsd do
+ it "CLOCK_REALTIME_FAST and CLOCK_REALTIME_PRECISE" do
+ Process.clock_gettime(Process::CLOCK_REALTIME_FAST).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_REALTIME_PRECISE).should be_an_instance_of(Float)
end
- platform_is :linux do
- it "CLOCK_REALTIME_COARSE and CLOCK_REALTIME_ALARM" do
- Process.clock_gettime(Process::CLOCK_REALTIME_COARSE).should be_an_instance_of(Float)
- Process.clock_gettime(Process::CLOCK_REALTIME_ALARM).should be_an_instance_of(Float)
- end
+ it "CLOCK_MONOTONIC_FAST and CLOCK_MONOTONIC_PRECISE" do
+ Process.clock_gettime(Process::CLOCK_MONOTONIC_FAST).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_MONOTONIC_PRECISE).should be_an_instance_of(Float)
+ end
- it "CLOCK_MONOTONIC_COARSE" do
- Process.clock_gettime(Process::CLOCK_MONOTONIC_COARSE).should be_an_instance_of(Float)
- end
+ it "CLOCK_UPTIME_FAST and CLOCK_UPTIME_PRECISE" do
+ Process.clock_gettime(Process::CLOCK_UPTIME_FAST).should be_an_instance_of(Float)
+ Process.clock_gettime(Process::CLOCK_UPTIME_PRECISE).should be_an_instance_of(Float)
+ end
- it "CLOCK_BOOTTIME and CLOCK_BOOTTIME_ALARM" do
- Process.clock_gettime(Process::CLOCK_BOOTTIME).should be_an_instance_of(Float)
- Process.clock_gettime(Process::CLOCK_BOOTTIME_ALARM).should be_an_instance_of(Float)
- end
+ it "CLOCK_SECOND" do
+ Process.clock_gettime(Process::CLOCK_SECOND).should be_an_instance_of(Float)
+ end
+ end
+
+ guard -> { platform_is :linux and kernel_version_is '2.6.32' } do
+ it "CLOCK_REALTIME_COARSE" do
+ Process.clock_gettime(Process::CLOCK_REALTIME_COARSE).should be_an_instance_of(Float)
+ end
+
+ it "CLOCK_MONOTONIC_COARSE" do
+ Process.clock_gettime(Process::CLOCK_MONOTONIC_COARSE).should be_an_instance_of(Float)
+ end
+ end
+
+ guard -> { platform_is :linux and kernel_version_is '2.6.39' } do
+ it "CLOCK_BOOTTIME" do
+ skip "No Process::CLOCK_BOOTTIME" unless defined?(Process::CLOCK_BOOTTIME)
+ Process.clock_gettime(Process::CLOCK_BOOTTIME).should be_an_instance_of(Float)
+ end
+ end
+
+ guard -> { platform_is "x86_64-linux" and kernel_version_is '3.0' } do
+ it "CLOCK_REALTIME_ALARM" do
+ skip "No Process::CLOCK_REALTIME_ALARM" unless defined?(Process::CLOCK_REALTIME_ALARM)
+ Process.clock_gettime(Process::CLOCK_REALTIME_ALARM).should be_an_instance_of(Float)
+ end
+
+ it "CLOCK_BOOTTIME_ALARM" do
+ skip "No Process::CLOCK_BOOTTIME_ALARM" unless defined?(Process::CLOCK_BOOTTIME_ALARM)
+ Process.clock_gettime(Process::CLOCK_BOOTTIME_ALARM).should be_an_instance_of(Float)
end
end
end
diff --git a/spec/ruby/core/process/constants_spec.rb b/spec/ruby/core/process/constants_spec.rb
index b61f5ab64e..616c54b8e1 100644
--- a/spec/ruby/core/process/constants_spec.rb
+++ b/spec/ruby/core/process/constants_spec.rb
@@ -1,3 +1,4 @@
+require_relative '../../spec_helper'
describe "Process::Constants" do
platform_is :darwin, :netbsd, :freebsd do
@@ -55,12 +56,18 @@ describe "Process::Constants" do
end
platform_is :netbsd, :freebsd do
- it "Process::RLIMIT_SBSIZE" do
+ it "has the correct constant values on NetBSD and FreeBSD" do
Process::RLIMIT_SBSIZE.should == 9 # FIXME: what's it equal?
Process::RLIMIT_AS.should == 10
end
end
+ platform_is :freebsd do
+ it "has the correct constant values on FreeBSD" do
+ Process::RLIMIT_NPTS.should == 11
+ end
+ end
+
platform_is :windows do
it "does not define RLIMIT constants" do
%i[
diff --git a/spec/ruby/core/process/detach_spec.rb b/spec/ruby/core/process/detach_spec.rb
index 1c27ed9c2c..f13bda1f5d 100644
--- a/spec/ruby/core/process/detach_spec.rb
+++ b/spec/ruby/core/process/detach_spec.rb
@@ -42,5 +42,40 @@ describe "Process.detach" do
thr.pid.should == pid
end
+
+ it "tolerates not existing child process pid" do
+ # Use a value that is close to the INT_MAX (pid usually is signed int).
+ # It should (at least) be greater than allowed pid limit value that depends on OS.
+ pid_not_existing = 2.pow(30)
+
+ # Check that there is no a child process with this hardcoded pid.
+ # Command `kill 0 pid`:
+ # - returns "1" if a process exists and
+ # - raises Errno::ESRCH otherwise
+ -> { Process.kill(0, pid_not_existing) }.should raise_error(Errno::ESRCH)
+
+ thr = Process.detach(pid_not_existing)
+ thr.join
+
+ thr.should be_kind_of(Thread)
+ end
+
+ it "calls #to_int to implicitly convert non-Integer pid to Integer" do
+ pid = MockObject.new('mock-enumerable')
+ pid.should_receive(:to_int).and_return(100500)
+
+ Process.detach(pid).join
+ end
+
+ it "raises TypeError when pid argument does not have #to_int method" do
+ -> { Process.detach(Object.new) }.should raise_error(TypeError, "no implicit conversion of Object into Integer")
+ end
+
+ it "raises TypeError when #to_int returns non-Integer value" do
+ pid = MockObject.new('mock-enumerable')
+ pid.should_receive(:to_int).and_return(:symbol)
+
+ -> { Process.detach(pid) }.should raise_error(TypeError, "can't convert MockObject to Integer (MockObject#to_int gives Symbol)")
+ end
end
end
diff --git a/spec/ruby/core/process/egid_spec.rb b/spec/ruby/core/process/egid_spec.rb
index 24dda43804..a67b623d5c 100644
--- a/spec/ruby/core/process/egid_spec.rb
+++ b/spec/ruby/core/process/egid_spec.rb
@@ -15,5 +15,44 @@ describe "Process.egid" do
end
describe "Process.egid=" do
- it "needs to be reviewed for spec completeness"
+
+ platform_is_not :windows do
+ it "raises TypeError if not passed an Integer or String" do
+ -> { Process.egid = Object.new }.should raise_error(TypeError)
+ end
+
+ it "sets the effective group id to its own gid if given the username corresponding to its own gid" do
+ raise unless Process.gid == Process.egid
+
+ require "etc"
+ group = Etc.getgrgid(Process.gid).name
+
+ Process.egid = group
+ Process.egid.should == Process.gid
+ end
+
+ as_user do
+ it "raises Errno::ERPERM if run by a non superuser trying to set the root group id" do
+ -> { Process.egid = 0 }.should raise_error(Errno::EPERM)
+ end
+
+ platform_is :linux do
+ it "raises Errno::ERPERM if run by a non superuser trying to set the group id from group name" do
+ -> { Process.egid = "root" }.should raise_error(Errno::EPERM)
+ end
+ end
+ end
+
+ as_superuser do
+ context "when ran by a superuser" do
+ it "sets the effective group id for the current process if run by a superuser" do
+ code = <<-RUBY
+ Process.egid = 1
+ puts Process.egid
+ RUBY
+ ruby_exe(code).should == "1\n"
+ end
+ end
+ end
+ end
end
diff --git a/spec/ruby/core/process/euid_spec.rb b/spec/ruby/core/process/euid_spec.rb
index a2f1bbf42e..c1ec4171d0 100644
--- a/spec/ruby/core/process/euid_spec.rb
+++ b/spec/ruby/core/process/euid_spec.rb
@@ -21,9 +21,19 @@ describe "Process.euid=" do
-> { Process.euid = Object.new }.should raise_error(TypeError)
end
+ it "sets the effective user id to its own uid if given the username corresponding to its own uid" do
+ raise unless Process.uid == Process.euid
+
+ require "etc"
+ user = Etc.getpwuid(Process.uid).name
+
+ Process.euid = user
+ Process.euid.should == Process.uid
+ end
+
as_user do
it "raises Errno::ERPERM if run by a non superuser trying to set the superuser id" do
- -> { (Process.euid = 0)}.should raise_error(Errno::EPERM)
+ -> { Process.euid = 0 }.should raise_error(Errno::EPERM)
end
it "raises Errno::ERPERM if run by a non superuser trying to set the superuser id from username" do
diff --git a/spec/ruby/core/process/exec_spec.rb b/spec/ruby/core/process/exec_spec.rb
index deb8913b6b..0f371b39c8 100644
--- a/spec/ruby/core/process/exec_spec.rb
+++ b/spec/ruby/core/process/exec_spec.rb
@@ -30,20 +30,20 @@ describe "Process.exec" do
end
it "raises Errno::EACCES when passed a directory" do
- -> { Process.exec File.dirname(__FILE__) }.should raise_error(Errno::EACCES)
+ -> { Process.exec __dir__ }.should raise_error(Errno::EACCES)
end
it "runs the specified command, replacing current process" do
- ruby_exe('Process.exec "echo hello"; puts "fail"', escape: true).should == "hello\n"
+ ruby_exe('Process.exec "echo hello"; puts "fail"').should == "hello\n"
end
it "sets the current directory when given the :chdir option" do
tmpdir = tmp("")[0..-2]
platform_is_not :windows do
- ruby_exe("Process.exec(\"pwd\", chdir: #{tmpdir.inspect})", escape: true).should == "#{tmpdir}\n"
+ ruby_exe("Process.exec(\"pwd\", chdir: #{tmpdir.inspect})").should == "#{tmpdir}\n"
end
platform_is :windows do
- ruby_exe("Process.exec(\"cd\", chdir: #{tmpdir.inspect})", escape: true).tr('\\', '/').should == "#{tmpdir}\n"
+ ruby_exe("Process.exec(\"cd\", chdir: #{tmpdir.inspect})").tr('\\', '/').should == "#{tmpdir}\n"
end
end
@@ -73,13 +73,13 @@ describe "Process.exec" do
platform_is_not :windows do
it "subjects the specified command to shell expansion" do
result = Dir.chdir(@dir) do
- ruby_exe('Process.exec "echo *"', escape: true)
+ ruby_exe('Process.exec "echo *"')
end
result.chomp.should == @name
end
it "creates an argument array with shell parsing semantics for whitespace" do
- ruby_exe('Process.exec "echo a b c d"', escape: true).should == "a b c d\n"
+ ruby_exe('Process.exec "echo a b c d"').should == "a b c d\n"
end
end
@@ -87,13 +87,13 @@ describe "Process.exec" do
# There is no shell expansion on Windows
it "does not subject the specified command to shell expansion on Windows" do
result = Dir.chdir(@dir) do
- ruby_exe('Process.exec "echo *"', escape: true)
+ ruby_exe('Process.exec "echo *"')
end
result.should == "*\n"
end
it "does not create an argument array with shell parsing semantics for whitespace on Windows" do
- ruby_exe('Process.exec "echo a b c d"', escape: true).should == "a b c d\n"
+ ruby_exe('Process.exec "echo a b c d"').should == "a b c d\n"
end
end
@@ -105,7 +105,7 @@ describe "Process.exec" do
platform_is :windows do
cmd = '"cmd.exe", "/C", "echo", "*"'
end
- ruby_exe("Process.exec #{cmd}", escape: true).should == "*\n"
+ ruby_exe("Process.exec #{cmd}").should == "*\n"
end
end
@@ -124,29 +124,29 @@ describe "Process.exec" do
end
it "sets environment variables in the child environment" do
- ruby_exe('Process.exec({"FOO" => "BAR"}, "echo ' + var + '")', escape: true).should == "BAR\n"
+ ruby_exe('Process.exec({"FOO" => "BAR"}, "echo ' + var + '")').should == "BAR\n"
end
it "unsets environment variables whose value is nil" do
platform_is_not :windows do
- ruby_exe('Process.exec({"FOO" => nil}, "echo ' + var + '")', escape: true).should == "\n"
+ ruby_exe('Process.exec({"FOO" => nil}, "echo ' + var + '")').should == "\n"
end
platform_is :windows do
# On Windows, echo-ing a non-existent env var is treated as echo-ing any other string of text
- ruby_exe('Process.exec({"FOO" => nil}, "echo ' + var + '")', escape: true).should == var + "\n"
+ ruby_exe('Process.exec({"FOO" => nil}, "echo ' + var + '")').should == var + "\n"
end
end
it "coerces environment argument using to_hash" do
- ruby_exe('o = Object.new; def o.to_hash; {"FOO" => "BAR"}; end; Process.exec(o, "echo ' + var + '")', escape: true).should == "BAR\n"
+ ruby_exe('o = Object.new; def o.to_hash; {"FOO" => "BAR"}; end; Process.exec(o, "echo ' + var + '")').should == "BAR\n"
end
it "unsets other environment variables when given a true :unsetenv_others option" do
platform_is_not :windows do
- ruby_exe('Process.exec("echo ' + var + '", unsetenv_others: true)', escape: true).should == "\n"
+ ruby_exe('Process.exec("echo ' + var + '", unsetenv_others: true)').should == "\n"
end
platform_is :windows do
- ruby_exe('Process.exec("' + ENV['COMSPEC'].gsub('\\', '\\\\\\') + ' /C echo ' + var + '", unsetenv_others: true)', escape: true).should == var + "\n"
+ ruby_exe('Process.exec("' + ENV['COMSPEC'].gsub('\\', '\\\\\\') + ' /C echo ' + var + '", unsetenv_others: true)').should == var + "\n"
end
end
end
@@ -154,19 +154,19 @@ describe "Process.exec" do
describe "with a command array" do
it "uses the first element as the command name and the second as the argv[0] value" do
platform_is_not :windows do
- ruby_exe('Process.exec(["/bin/sh", "argv_zero"], "-c", "echo $0")', escape: true).should == "argv_zero\n"
+ ruby_exe('Process.exec(["/bin/sh", "argv_zero"], "-c", "echo $0")').should == "argv_zero\n"
end
platform_is :windows do
- ruby_exe('Process.exec(["cmd.exe", "/C"], "/C", "echo", "argv_zero")', escape: true).should == "argv_zero\n"
+ ruby_exe('Process.exec(["cmd.exe", "/C"], "/C", "echo", "argv_zero")').should == "argv_zero\n"
end
end
it "coerces the argument using to_ary" do
platform_is_not :windows do
- ruby_exe('o = Object.new; def o.to_ary; ["/bin/sh", "argv_zero"]; end; Process.exec(o, "-c", "echo $0")', escape: true).should == "argv_zero\n"
+ ruby_exe('o = Object.new; def o.to_ary; ["/bin/sh", "argv_zero"]; end; Process.exec(o, "-c", "echo $0")').should == "argv_zero\n"
end
platform_is :windows do
- ruby_exe('o = Object.new; def o.to_ary; ["cmd.exe", "/C"]; end; Process.exec(o, "/C", "echo", "argv_zero")', escape: true).should == "argv_zero\n"
+ ruby_exe('o = Object.new; def o.to_ary; ["cmd.exe", "/C"]; end; Process.exec(o, "/C", "echo", "argv_zero")').should == "argv_zero\n"
end
end
@@ -200,7 +200,7 @@ describe "Process.exec" do
end
EOC
- ruby_exe(cmd, escape: true)
+ ruby_exe(cmd)
child_fd = IO.read(@child_fd_file).to_i
child_fd.to_i.should > STDERR.fileno
@@ -216,7 +216,7 @@ describe "Process.exec" do
Process.exec("#{ruby_cmd(map_fd_fixture)} \#{f.fileno}", f.fileno => f.fileno)
EOC
- output = ruby_exe(cmd, escape: true)
+ output = ruby_exe(cmd)
child_fd, close_on_exec = output.split
child_fd.to_i.should > STDERR.fileno
@@ -232,7 +232,7 @@ describe "Process.exec" do
puts(f.close_on_exec?)
EOC
- output = ruby_exe(cmd, escape: true)
+ output = ruby_exe(cmd)
output.split.should == ['true', 'false']
end
end
diff --git a/spec/ruby/core/process/exit_spec.rb b/spec/ruby/core/process/exit_spec.rb
index 70d79d789d..4f7dc94407 100644
--- a/spec/ruby/core/process/exit_spec.rb
+++ b/spec/ruby/core/process/exit_spec.rb
@@ -6,5 +6,5 @@ describe "Process.exit" do
end
describe "Process.exit!" do
- it_behaves_like :process_exit!, :exit!, Process
+ it_behaves_like :process_exit!, :exit!, "Process"
end
diff --git a/spec/ruby/core/process/fixtures/argv0.rb b/spec/ruby/core/process/fixtures/argv0.rb
new file mode 100644
index 0000000000..847a3e903e
--- /dev/null
+++ b/spec/ruby/core/process/fixtures/argv0.rb
@@ -0,0 +1,6 @@
+puts Process.argv0
+puts __FILE__
+
+if Process.argv0 == __FILE__
+ print "OK"
+end
diff --git a/spec/ruby/core/process/fixtures/kill.rb b/spec/ruby/core/process/fixtures/kill.rb
index 0b88f8ee1f..b922a043f1 100644
--- a/spec/ruby/core/process/fixtures/kill.rb
+++ b/spec/ruby/core/process/fixtures/kill.rb
@@ -1,5 +1,3 @@
-require 'thread'
-
pid_file = ARGV.shift
scenario = ARGV.shift
diff --git a/spec/ruby/core/process/spawn_spec.rb b/spec/ruby/core/process/spawn_spec.rb
index 6be3f41a87..283a7f033d 100644
--- a/spec/ruby/core/process/spawn_spec.rb
+++ b/spec/ruby/core/process/spawn_spec.rb
@@ -349,7 +349,7 @@ describe "Process.spawn" do
pgid = Process.getpgid(Process.pid)
# The process group is not available on all platforms.
# See "man proc" - /proc/[pid]/stat - (5) pgrp
- # In Travis arm64 environment, the value is 0.
+ # In Travis aarch64 environment, the value is 0.
#
# $ cat /proc/[pid]/stat
# 19179 (ruby) S 19160 0 0 ...
@@ -477,6 +477,16 @@ describe "Process.spawn" do
# redirection
+ it 'redirects to the wrapped IO using wrapped_io.to_io if out: wrapped_io' do
+ File.open(@name, 'w') do |file|
+ -> do
+ wrapped_io = mock('wrapped IO')
+ wrapped_io.should_receive(:to_io).and_return(file)
+ Process.wait Process.spawn('echo Hello World', out: wrapped_io)
+ end.should output_to_fd("Hello World\n", file)
+ end
+ end
+
it "redirects STDOUT to the given file descriptor if out: Integer" do
File.open(@name, 'w') do |file|
-> do
@@ -567,6 +577,24 @@ describe "Process.spawn" do
end
end
+ platform_is_not :windows do
+ it "redirects non-default file descriptor to itself" do
+ File.open(@name, 'w') do |file|
+ -> do
+ Process.wait Process.spawn(
+ ruby_cmd("f = IO.new(#{file.fileno}, 'w'); f.print(:bang); f.flush"), file.fileno => file.fileno)
+ end.should output_to_fd("bang", file)
+ end
+ end
+ end
+
+ it "redirects default file descriptor to itself" do
+ -> do
+ Process.wait Process.spawn(
+ ruby_cmd("f = IO.new(#{STDOUT.fileno}, 'w'); f.print(:bang); f.flush"), STDOUT.fileno => STDOUT.fileno)
+ end.should output_to_fd("bang", STDOUT)
+ end
+
# :close_others
platform_is_not :windows do
@@ -686,7 +714,7 @@ describe "Process.spawn" do
end
it "raises an Errno::EACCES or Errno::EISDIR when passed a directory" do
- -> { Process.spawn File.dirname(__FILE__) }.should raise_error(SystemCallError) { |e|
+ -> { Process.spawn __dir__ }.should raise_error(SystemCallError) { |e|
[Errno::EACCES, Errno::EISDIR].should include(e.class)
}
end
diff --git a/spec/ruby/core/process/status/equal_value_spec.rb b/spec/ruby/core/process/status/equal_value_spec.rb
index d85bb22214..d8a2be26b8 100644
--- a/spec/ruby/core/process/status/equal_value_spec.rb
+++ b/spec/ruby/core/process/status/equal_value_spec.rb
@@ -8,7 +8,7 @@ describe "Process::Status#==" do
end
it "returns true when compared to the integer status of a terminated child" do
- ruby_exe("Process.kill(:KILL, $$); exit(29)", exit_status: platform_is(:windows) ? 0 : nil)
+ ruby_exe("Process.kill(:KILL, $$); exit(29)", exit_status: platform_is(:windows) ? 0 : :SIGKILL)
$?.to_i.should == $?
$?.should == $?.to_i
end
diff --git a/spec/ruby/core/process/status/exited_spec.rb b/spec/ruby/core/process/status/exited_spec.rb
index 059cd5b1aa..a61292b146 100644
--- a/spec/ruby/core/process/status/exited_spec.rb
+++ b/spec/ruby/core/process/status/exited_spec.rb
@@ -14,7 +14,7 @@ describe "Process::Status#exited?" do
describe "for a terminated child" do
before :each do
- ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : nil)
+ ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : :SIGKILL)
end
platform_is_not :windows do
diff --git a/spec/ruby/core/process/status/exitstatus_spec.rb b/spec/ruby/core/process/status/exitstatus_spec.rb
index 3087bd619e..5c86c2b3c8 100644
--- a/spec/ruby/core/process/status/exitstatus_spec.rb
+++ b/spec/ruby/core/process/status/exitstatus_spec.rb
@@ -11,7 +11,7 @@ describe "Process::Status#exitstatus" do
describe "for a child that raised SignalException" do
before :each do
- ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : nil)
+ ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : :SIGKILL)
end
platform_is_not :windows do
diff --git a/spec/ruby/core/process/status/signaled_spec.rb b/spec/ruby/core/process/status/signaled_spec.rb
index 389092a533..c0de7b8006 100644
--- a/spec/ruby/core/process/status/signaled_spec.rb
+++ b/spec/ruby/core/process/status/signaled_spec.rb
@@ -13,7 +13,7 @@ describe "Process::Status#signaled?" do
describe "for a terminated child" do
before :each do
- ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : nil)
+ ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : :SIGKILL)
end
platform_is_not :windows do
diff --git a/spec/ruby/core/process/status/success_spec.rb b/spec/ruby/core/process/status/success_spec.rb
index c531121f08..3589cc611f 100644
--- a/spec/ruby/core/process/status/success_spec.rb
+++ b/spec/ruby/core/process/status/success_spec.rb
@@ -23,7 +23,7 @@ describe "Process::Status#success?" do
describe "for a child that was terminated" do
before :each do
- ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : nil)
+ ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : :SIGKILL)
end
platform_is_not :windows do
diff --git a/spec/ruby/core/process/status/termsig_spec.rb b/spec/ruby/core/process/status/termsig_spec.rb
index 1c87a6f455..9a22dbea71 100644
--- a/spec/ruby/core/process/status/termsig_spec.rb
+++ b/spec/ruby/core/process/status/termsig_spec.rb
@@ -6,14 +6,14 @@ describe "Process::Status#termsig" do
ruby_exe("exit(0)")
end
- it "returns true" do
+ it "returns nil" do
$?.termsig.should be_nil
end
end
describe "for a child that raised SignalException" do
before :each do
- ruby_exe("raise SignalException, 'SIGTERM'", exit_status: nil)
+ ruby_exe("raise SignalException, 'SIGTERM'", exit_status: :SIGTERM)
end
platform_is_not :windows do
@@ -25,7 +25,7 @@ describe "Process::Status#termsig" do
describe "for a child that was sent a signal" do
before :each do
- ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : nil)
+ ruby_exe("Process.kill(:KILL, $$); exit(42)", exit_status: platform_is(:windows) ? 0 : :SIGKILL)
end
platform_is_not :windows do
diff --git a/spec/ruby/core/process/status/to_i_spec.rb b/spec/ruby/core/process/status/to_i_spec.rb
index 7cde9b915b..39f8e2d84c 100644
--- a/spec/ruby/core/process/status/to_i_spec.rb
+++ b/spec/ruby/core/process/status/to_i_spec.rb
@@ -7,7 +7,7 @@ describe "Process::Status#to_i" do
end
it "returns an integer when the child is signaled" do
- ruby_exe('raise SignalException, "TERM"', exit_status: platform_is(:windows) ? 3 : nil)
+ ruby_exe('raise SignalException, "TERM"', exit_status: platform_is(:windows) ? 3 : :SIGTERM)
$?.to_i.should be_an_instance_of(Integer)
end
end
diff --git a/spec/ruby/core/process/status/wait_spec.rb b/spec/ruby/core/process/status/wait_spec.rb
index b9d80e31f4..57d56209a9 100644
--- a/spec/ruby/core/process/status/wait_spec.rb
+++ b/spec/ruby/core/process/status/wait_spec.rb
@@ -1,102 +1,100 @@
require_relative '../../../spec_helper'
require_relative '../fixtures/common'
-ruby_version_is "3.0" do
- describe "Process::Status.wait" do
- ProcessSpecs.use_system_ruby(self)
-
- before :all do
- begin
- leaked = Process.waitall
- # Ruby-space should not see PIDs used by mjit
- raise "subprocesses leaked before wait specs: #{leaked}" unless leaked.empty?
- rescue NotImplementedError
- end
+describe "Process::Status.wait" do
+ ProcessSpecs.use_system_ruby(self)
+
+ before :all do
+ begin
+ leaked = Process.waitall
+ # Ruby-space should not see PIDs used by rjit
+ raise "subprocesses leaked before wait specs: #{leaked}" unless leaked.empty?
+ rescue NotImplementedError
end
+ end
+
+ it "returns a status with pid -1 if there are no child processes" do
+ Process::Status.wait.pid.should == -1
+ end
- it "returns a status with pid -1 if there are no child processes" do
- Process::Status.wait.pid.should == -1
+ platform_is_not :windows do
+ it "returns a status with its child pid" do
+ pid = Process.spawn(ruby_cmd('exit'))
+ status = Process::Status.wait
+ status.should be_an_instance_of(Process::Status)
+ status.pid.should == pid
end
- platform_is_not :windows do
- it "returns a status with its child pid" do
- pid = Process.spawn(ruby_cmd('exit'))
- status = Process::Status.wait
- status.should be_an_instance_of(Process::Status)
- status.pid.should == pid
- end
+ it "should not set $? to the Process::Status" do
+ pid = Process.spawn(ruby_cmd('exit'))
+ status = Process::Status.wait
+ $?.should_not equal(status)
+ end
- it "should not set $? to the Process::Status" do
- pid = Process.spawn(ruby_cmd('exit'))
- status = Process::Status.wait
- $?.should_not equal(status)
- end
+ it "should not change the value of $?" do
+ pid = Process.spawn(ruby_cmd('exit'))
+ Process.wait
+ status = $?
+ Process::Status.wait
+ status.should equal($?)
+ end
- it "should not change the value of $?" do
- pid = Process.spawn(ruby_cmd('exit'))
- Process.wait
- status = $?
- Process::Status.wait
- status.should equal($?)
- end
+ it "waits for any child process if no pid is given" do
+ pid = Process.spawn(ruby_cmd('exit'))
+ Process::Status.wait.pid.should == pid
+ -> { Process.kill(0, pid) }.should raise_error(Errno::ESRCH)
+ end
- it "waits for any child process if no pid is given" do
- pid = Process.spawn(ruby_cmd('exit'))
- Process::Status.wait.pid.should == pid
- -> { Process.kill(0, pid) }.should raise_error(Errno::ESRCH)
- end
+ it "waits for a specific child if a pid is given" do
+ pid1 = Process.spawn(ruby_cmd('exit'))
+ pid2 = Process.spawn(ruby_cmd('exit'))
+ Process::Status.wait(pid2).pid.should == pid2
+ Process::Status.wait(pid1).pid.should == pid1
+ -> { Process.kill(0, pid1) }.should raise_error(Errno::ESRCH)
+ -> { Process.kill(0, pid2) }.should raise_error(Errno::ESRCH)
+ end
- it "waits for a specific child if a pid is given" do
- pid1 = Process.spawn(ruby_cmd('exit'))
- pid2 = Process.spawn(ruby_cmd('exit'))
- Process::Status.wait(pid2).pid.should == pid2
- Process::Status.wait(pid1).pid.should == pid1
- -> { Process.kill(0, pid1) }.should raise_error(Errno::ESRCH)
- -> { Process.kill(0, pid2) }.should raise_error(Errno::ESRCH)
- end
+ it "coerces the pid to an Integer" do
+ pid1 = Process.spawn(ruby_cmd('exit'))
+ Process::Status.wait(mock_int(pid1)).pid.should == pid1
+ -> { Process.kill(0, pid1) }.should raise_error(Errno::ESRCH)
+ end
- it "coerces the pid to an Integer" do
- pid1 = Process.spawn(ruby_cmd('exit'))
- Process::Status.wait(mock_int(pid1)).pid.should == pid1
- -> { Process.kill(0, pid1) }.should raise_error(Errno::ESRCH)
- end
+ # This spec is probably system-dependent.
+ it "waits for a child whose process group ID is that of the calling process" do
+ pid1 = Process.spawn(ruby_cmd('exit'), pgroup: true)
+ pid2 = Process.spawn(ruby_cmd('exit'))
- # This spec is probably system-dependent.
- it "waits for a child whose process group ID is that of the calling process" do
- pid1 = Process.spawn(ruby_cmd('exit'), pgroup: true)
- pid2 = Process.spawn(ruby_cmd('exit'))
+ Process::Status.wait(0).pid.should == pid2
+ Process::Status.wait.pid.should == pid1
+ end
- Process::Status.wait(0).pid.should == pid2
- Process::Status.wait.pid.should == pid1
+ # This spec is probably system-dependent.
+ it "doesn't block if no child is available when WNOHANG is used" do
+ read, write = IO.pipe
+ pid = Process.fork do
+ read.close
+ Signal.trap("TERM") { Process.exit! }
+ write << 1
+ write.close
+ sleep
end
- # This spec is probably system-dependent.
- it "doesn't block if no child is available when WNOHANG is used" do
- read, write = IO.pipe
- pid = Process.fork do
- read.close
- Signal.trap("TERM") { Process.exit! }
- write << 1
- write.close
- sleep
- end
+ Process::Status.wait(pid, Process::WNOHANG).should be_nil
- Process::Status.wait(pid, Process::WNOHANG).should be_nil
+ # wait for the child to setup its TERM handler
+ write.close
+ read.read(1)
+ read.close
- # wait for the child to setup its TERM handler
- write.close
- read.read(1)
- read.close
-
- Process.kill("TERM", pid)
- Process::Status.wait.pid.should == pid
- end
+ Process.kill("TERM", pid)
+ Process::Status.wait.pid.should == pid
+ end
- it "always accepts flags=0" do
- pid = Process.spawn(ruby_cmd('exit'))
- Process::Status.wait(-1, 0).pid.should == pid
- -> { Process.kill(0, pid) }.should raise_error(Errno::ESRCH)
- end
+ it "always accepts flags=0" do
+ pid = Process.spawn(ruby_cmd('exit'))
+ Process::Status.wait(-1, 0).pid.should == pid
+ -> { Process.kill(0, pid) }.should raise_error(Errno::ESRCH)
end
end
end
diff --git a/spec/ruby/core/process/times_spec.rb b/spec/ruby/core/process/times_spec.rb
index b47189a7e7..d3bff2cda9 100644
--- a/spec/ruby/core/process/times_spec.rb
+++ b/spec/ruby/core/process/times_spec.rb
@@ -5,31 +5,15 @@ describe "Process.times" do
Process.times.should be_kind_of(Process::Tms)
end
- it "returns current cpu times" do
- t = Process.times
- user = t.utime
+ # TODO: Intel C Compiler does not work this example
+ # http://rubyci.s3.amazonaws.com/icc-x64/ruby-master/log/20221013T030005Z.fail.html.gz
+ unless RbConfig::CONFIG['CC']&.include?("icx")
+ it "returns current cpu times" do
+ t = Process.times
+ user = t.utime
- 1 until Process.times.utime > user
- Process.times.utime.should > user
- end
-
- platform_is_not :windows do
- it "uses getrusage when available to improve precision beyond milliseconds" do
- max = 10_000
- has_getrusage = max.times.find do
- time = Process.clock_gettime(:GETRUSAGE_BASED_CLOCK_PROCESS_CPUTIME_ID)
- ('%.6f' % time).end_with?('000')
- end
- unless has_getrusage
- skip "getrusage is not supported on this environment"
- end
-
- found = (max * 100).times.find do
- time = Process.times.utime
- ('%.6f' % time).end_with?('000')
- end
-
- found.should_not == nil
+ 1 until Process.times.utime > user
+ Process.times.utime.should > user
end
end
end
diff --git a/spec/ruby/core/process/wait2_spec.rb b/spec/ruby/core/process/wait2_spec.rb
index 6eb7fc6d06..8ba429dc96 100644
--- a/spec/ruby/core/process/wait2_spec.rb
+++ b/spec/ruby/core/process/wait2_spec.rb
@@ -4,14 +4,14 @@ describe "Process.wait2" do
before :all do
# HACK: this kludge is temporarily necessary because some
# misbehaving spec somewhere else does not clear processes
- # Note: background processes are unavoidable with MJIT,
+ # Note: background processes are unavoidable with RJIT,
# but we shouldn't reap them from Ruby-space
begin
Process.wait(-1, Process::WNOHANG)
$stderr.puts "Leaked process before wait2 specs! Waiting for it"
leaked = Process.waitall
$stderr.puts "leaked before wait2 specs: #{leaked}" unless leaked.empty?
- # Ruby-space should not see PIDs used by mjit
+ # Ruby-space should not see PIDs used by rjit
leaked.should be_empty
rescue Errno::ECHILD # No child processes
rescue NotImplementedError
@@ -33,4 +33,13 @@ describe "Process.wait2" do
-> { Process.wait2 }.should raise_error(Errno::ECHILD)
-> { Process.wait2 }.should raise_error(StandardError)
end
+
+ it "returns nil if the child process is still running when given the WNOHANG flag" do
+ IO.popen(ruby_cmd('STDIN.getbyte'), "w") do |io|
+ pid, status = Process.wait2(io.pid, Process::WNOHANG)
+ pid.should be_nil
+ status.should be_nil
+ io.write('a')
+ end
+ end
end
diff --git a/spec/ruby/core/process/wait_spec.rb b/spec/ruby/core/process/wait_spec.rb
index 44c95d6304..385acc9928 100644
--- a/spec/ruby/core/process/wait_spec.rb
+++ b/spec/ruby/core/process/wait_spec.rb
@@ -7,7 +7,7 @@ describe "Process.wait" do
before :all do
begin
leaked = Process.waitall
- # Ruby-space should not see PIDs used by mjit
+ # Ruby-space should not see PIDs used by rjit
raise "subprocesses leaked before wait specs: #{leaked}" unless leaked.empty?
rescue NotImplementedError
end
diff --git a/spec/ruby/core/process/waitpid_spec.rb b/spec/ruby/core/process/waitpid_spec.rb
index f7cf1a45a8..a02147b663 100644
--- a/spec/ruby/core/process/waitpid_spec.rb
+++ b/spec/ruby/core/process/waitpid_spec.rb
@@ -2,7 +2,8 @@ require_relative '../../spec_helper'
describe "Process.waitpid" do
it "returns nil when the process has not yet completed and WNOHANG is specified" do
- pid = spawn("sleep 5")
+ cmd = platform_is(:windows) ? "timeout" : "sleep"
+ pid = spawn("#{cmd} 5")
begin
Process.waitpid(pid, Process::WNOHANG).should == nil
Process.kill("KILL", pid)
diff --git a/spec/ruby/core/process/warmup_spec.rb b/spec/ruby/core/process/warmup_spec.rb
new file mode 100644
index 0000000000..b562d52d22
--- /dev/null
+++ b/spec/ruby/core/process/warmup_spec.rb
@@ -0,0 +1,11 @@
+require_relative '../../spec_helper'
+
+describe "Process.warmup" do
+ ruby_version_is "3.3" do
+ # The behavior is entirely implementation specific.
+ # Other implementations are free to just make it a noop
+ it "is implemented" do
+ Process.warmup.should == true
+ end
+ end
+end
diff --git a/spec/ruby/core/queue/deq_spec.rb b/spec/ruby/core/queue/deq_spec.rb
index 9510978eac..f84d4220ea 100644
--- a/spec/ruby/core/queue/deq_spec.rb
+++ b/spec/ruby/core/queue/deq_spec.rb
@@ -1,6 +1,13 @@
require_relative '../../spec_helper'
require_relative '../../shared/queue/deque'
+require_relative '../../shared/types/rb_num2dbl_fails'
describe "Queue#deq" do
it_behaves_like :queue_deq, :deq, -> { Queue.new }
end
+
+describe "Queue operations with timeout" do
+ ruby_version_is "3.2" do
+ it_behaves_like :rb_num2dbl_fails, nil, -> v { q = Queue.new; q.push(1); q.deq(timeout: v) }
+ end
+end
diff --git a/spec/ruby/core/queue/initialize_spec.rb b/spec/ruby/core/queue/initialize_spec.rb
index 83c7e595fe..c6c1ae63c5 100644
--- a/spec/ruby/core/queue/initialize_spec.rb
+++ b/spec/ruby/core/queue/initialize_spec.rb
@@ -7,6 +7,10 @@ describe "Queue#initialize" do
q.should.empty?
end
+ it "is a private method" do
+ Queue.private_instance_methods.include?(:initialize).should == true
+ end
+
ruby_version_is '3.1' do
it "adds all elements of the passed Enumerable to self" do
q = Queue.new([1, 2, 3])
@@ -18,21 +22,41 @@ describe "Queue#initialize" do
q.should.empty?
end
- 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?
+ describe "converts the given argument to an Array using #to_a" do
+ it "uses #to_a on the provided Enumerable" do
+ enumerable = MockObject.new('mock-enumerable')
+ enumerable.should_receive(:to_a).and_return([1, 2, 3])
+ q = Queue.new(enumerable)
+ q.size.should == 3
+ q.should_not.empty?
+ q.pop.should == 1
+ q.pop.should == 2
+ q.pop.should == 3
+ q.should.empty?
+ end
+
+ it "raises a TypeError if the given argument can't be converted to an Array" do
+ -> { Queue.new(42) }.should raise_error(TypeError)
+ -> { Queue.new(:abc) }.should raise_error(TypeError)
+ end
+
+ it "raises a NoMethodError if the given argument raises a NoMethodError during type coercion to an Array" do
+ enumerable = MockObject.new('mock-enumerable')
+ enumerable.should_receive(:to_a).and_raise(NoMethodError)
+ -> { Queue.new(enumerable) }.should raise_error(NoMethodError)
+ end
end
- it "raises if the provided Enumerable does not respond to #to_a" do
+ 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
+
+ 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
end
diff --git a/spec/ruby/core/queue/pop_spec.rb b/spec/ruby/core/queue/pop_spec.rb
index 1ce9231685..d344740834 100644
--- a/spec/ruby/core/queue/pop_spec.rb
+++ b/spec/ruby/core/queue/pop_spec.rb
@@ -1,6 +1,13 @@
require_relative '../../spec_helper'
require_relative '../../shared/queue/deque'
+require_relative '../../shared/types/rb_num2dbl_fails'
describe "Queue#pop" do
it_behaves_like :queue_deq, :pop, -> { Queue.new }
end
+
+describe "Queue operations with timeout" do
+ ruby_version_is "3.2" do
+ it_behaves_like :rb_num2dbl_fails, nil, -> v { q = Queue.new; q.push(1); q.pop(timeout: v) }
+ end
+end
diff --git a/spec/ruby/core/queue/shift_spec.rb b/spec/ruby/core/queue/shift_spec.rb
index f84058e1df..64165e0b61 100644
--- a/spec/ruby/core/queue/shift_spec.rb
+++ b/spec/ruby/core/queue/shift_spec.rb
@@ -1,6 +1,13 @@
require_relative '../../spec_helper'
require_relative '../../shared/queue/deque'
+require_relative '../../shared/types/rb_num2dbl_fails'
describe "Queue#shift" do
it_behaves_like :queue_deq, :shift, -> { Queue.new }
end
+
+describe "Queue operations with timeout" do
+ ruby_version_is "3.2" do
+ it_behaves_like :rb_num2dbl_fails, nil, -> v { q = Queue.new; q.push(1); q.shift(timeout: v) }
+ end
+end
diff --git a/spec/ruby/core/random/bytes_spec.rb b/spec/ruby/core/random/bytes_spec.rb
index 06e84d03bd..b42dc61234 100644
--- a/spec/ruby/core/random/bytes_spec.rb
+++ b/spec/ruby/core/random/bytes_spec.rb
@@ -9,7 +9,6 @@ describe "Random#bytes" do
Random.new(33).bytes(2).should == Random.new(33).bytes(2)
end
- # Should double check this is official spec
it "returns the same numeric output for a given seed across all implementations and platforms" do
rnd = Random.new(33)
rnd.bytes(2).should == "\x14\\"
@@ -18,7 +17,7 @@ describe "Random#bytes" do
end
it "returns the same numeric output for a given huge seed across all implementations and platforms" do
- rnd = Random.new(bignum_value ** 4)
+ rnd = Random.new(2 ** (63 * 4))
rnd.bytes(2).should == "_\x91"
rnd.bytes(1000) # skip some
rnd.bytes(2).should == "\x17\x12"
diff --git a/spec/ruby/core/random/default_spec.rb b/spec/ruby/core/random/default_spec.rb
index b4ffcb81f4..01d7430df8 100644
--- a/spec/ruby/core/random/default_spec.rb
+++ b/spec/ruby/core/random/default_spec.rb
@@ -14,26 +14,16 @@ describe "Random::DEFAULT" do
seed1.should != seed2
end
- ruby_version_is ''...'3.0' do
- it "returns a Random instance" do
- suppress_warning do
- Random::DEFAULT.should be_an_instance_of(Random)
- end
+ it "refers to the Random class" do
+ suppress_warning do
+ Random::DEFAULT.should.equal?(Random)
end
end
- ruby_version_is '3.0' do
- it "refers to the Random class" do
- suppress_warning do
- Random::DEFAULT.should.equal?(Random)
- end
- end
-
- it "is deprecated" do
- -> {
- Random::DEFAULT.should.equal?(Random)
- }.should complain(/constant Random::DEFAULT is deprecated/)
- end
+ it "is deprecated" do
+ -> {
+ Random::DEFAULT.should.equal?(Random)
+ }.should complain(/constant Random::DEFAULT is deprecated/)
end
end
diff --git a/spec/ruby/core/random/new_spec.rb b/spec/ruby/core/random/new_spec.rb
index 4280b5b9c3..90e2a9d6f2 100644
--- a/spec/ruby/core/random/new_spec.rb
+++ b/spec/ruby/core/random/new_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../spec_helper"
describe "Random.new" do
it "returns a new instance of Random" do
Random.new.should be_an_instance_of(Random)
diff --git a/spec/ruby/core/random/rand_spec.rb b/spec/ruby/core/random/rand_spec.rb
index 6ea7eece5f..9244177ab5 100644
--- a/spec/ruby/core/random/rand_spec.rb
+++ b/spec/ruby/core/random/rand_spec.rb
@@ -205,6 +205,11 @@ describe "Random#rand with Range" do
Random.new(42).rand(0..1.0).should be_kind_of(Float)
end
+ it "returns a float within a given float range" do
+ Random.new(42).rand(0.0...100.0).should == 37.454011884736246
+ Random.new(42).rand(-100.0...0.0).should == -62.545988115263754
+ end
+
it "raises an ArgumentError when the startpoint lacks #+ and #- methods" do
-> do
Random.new.rand(Object.new..67)
diff --git a/spec/ruby/core/range/bsearch_spec.rb b/spec/ruby/core/range/bsearch_spec.rb
index 438c7ce314..5254ab756c 100644
--- a/spec/ruby/core/range/bsearch_spec.rb
+++ b/spec/ruby/core/range/bsearch_spec.rb
@@ -9,22 +9,30 @@ describe "Range#bsearch" do
it_behaves_like :enumeratorized_with_unknown_size, :bsearch, (1..3)
it "raises a TypeError if the block returns an Object" do
- -> { (0..1).bsearch { Object.new } }.should raise_error(TypeError)
+ -> { (0..1).bsearch { Object.new } }.should raise_error(TypeError, "wrong argument type Object (must be numeric, true, false or nil)")
end
- it "raises a TypeError if the block returns a String" do
- -> { (0..1).bsearch { "1" } }.should raise_error(TypeError)
+ it "raises a TypeError if the block returns a String and boundaries are Integer values" do
+ -> { (0..1).bsearch { "1" } }.should raise_error(TypeError, "wrong argument type String (must be numeric, true, false or nil)")
+ end
+
+ it "raises a TypeError if the block returns a String and boundaries are Float values" do
+ -> { (0.0..1.0).bsearch { "1" } }.should raise_error(TypeError, "wrong argument type String (must be numeric, true, false or nil)")
end
it "raises a TypeError if the Range has Object values" do
value = mock("range bsearch")
r = Range.new value, value
- -> { r.bsearch { true } }.should raise_error(TypeError)
+ -> { r.bsearch { true } }.should raise_error(TypeError, "can't do binary search for MockObject")
end
it "raises a TypeError if the Range has String values" do
- -> { ("a".."e").bsearch { true } }.should raise_error(TypeError)
+ -> { ("a".."e").bsearch { true } }.should raise_error(TypeError, "can't do binary search for String")
+ end
+
+ it "raises TypeError when non-Numeric begin/end and block not passed" do
+ -> { ("a".."e").bsearch }.should raise_error(TypeError, "can't do binary search for String")
end
context "with Integer values" do
@@ -94,6 +102,10 @@ describe "Range#bsearch" do
(4..2).bsearch { 0 }.should == nil
(4..2).bsearch { -1 }.should == nil
end
+
+ it "returns enumerator when block not passed" do
+ (0...3).bsearch.kind_of?(Enumerator).should == true
+ end
end
context "with Float values" do
@@ -156,7 +168,6 @@ describe "Range#bsearch" do
it "returns nil if the block returns greater than zero for every element" do
(0.3..3.0).bsearch { |x| x <=> -1 }.should be_nil
-
end
it "returns nil if the block never returns zero" do
@@ -213,6 +224,10 @@ describe "Range#bsearch" do
(0...inf).bsearch { |x| x >= Float::MAX ? 0 : 1 }.should == Float::MAX
end
end
+
+ it "returns enumerator when block not passed" do
+ (0.1...2.3).bsearch.kind_of?(Enumerator).should == true
+ end
end
context "with endless ranges and Integer values" do
@@ -250,6 +265,10 @@ describe "Range#bsearch" do
[1, 2, 3].should include(result)
end
end
+
+ it "returns enumerator when block not passed" do
+ eval("(-2..)").bsearch.kind_of?(Enumerator).should == true
+ end
end
context "with endless ranges and Float values" do
@@ -327,112 +346,121 @@ describe "Range#bsearch" do
eval("(0.0...)").bsearch { 0 }.should != inf
end
end
+
+ it "returns enumerator when block not passed" do
+ eval("(0.1..)").bsearch.kind_of?(Enumerator).should == true
+ end
end
+ context "with beginless ranges and Integer values" do
+ context "with a block returning true or false" do
+ it "returns the smallest element for which block returns true" do
+ (..10).bsearch { |x| x >= 2 }.should == 2
+ (...-1).bsearch { |x| x >= -10 }.should == -10
+ end
+ end
- ruby_version_is "2.7" do
- context "with beginless ranges and Integer values" do
- context "with a block returning true or false" do
- it "returns the smallest element for which block returns true" do
- eval("(..10)").bsearch { |x| x >= 2 }.should == 2
- eval("(...-1)").bsearch { |x| x >= -10 }.should == -10
- end
+ context "with a block returning negative, zero, positive numbers" do
+ it "returns nil if the block returns greater than zero for every element" do
+ (..0).bsearch { |x| 1 }.should be_nil
end
- context "with a block returning negative, zero, positive numbers" do
- it "returns nil if the block returns greater than zero for every element" do
- eval("(..0)").bsearch { |x| 1 }.should be_nil
- end
+ it "returns nil if the block never returns zero" do
+ (..0).bsearch { |x| x > 5 ? -1 : 1 }.should be_nil
+ end
- it "returns nil if the block never returns zero" do
- eval("(..0)").bsearch { |x| x > 5 ? -1 : 1 }.should be_nil
- end
+ it "accepts Float::INFINITY from the block" do
+ (..0).bsearch { |x| Float::INFINITY }.should be_nil
+ end
- it "accepts Float::INFINITY from the block" do
- eval("(..0)").bsearch { |x| Float::INFINITY }.should be_nil
- end
+ it "returns an element at an index for which block returns 0.0" do
+ result = (..10).bsearch { |x| x < 2 ? 1.0 : x > 2 ? -1.0 : 0.0 }
+ result.should == 2
+ end
- it "returns an element at an index for which block returns 0.0" do
- result = eval("(..10)").bsearch { |x| x < 2 ? 1.0 : x > 2 ? -1.0 : 0.0 }
- result.should == 2
- end
+ it "returns an element at an index for which block returns 0" do
+ result = (...10).bsearch { |x| x < 1 ? 1 : x > 3 ? -1 : 0 }
+ [1, 2, 3].should include(result)
+ end
+ end
+
+ it "returns enumerator when block not passed" do
+ (..10).bsearch.kind_of?(Enumerator).should == true
+ end
+ end
- it "returns an element at an index for which block returns 0" do
- result = eval("(...10)").bsearch { |x| x < 1 ? 1 : x > 3 ? -1 : 0 }
- [1, 2, 3].should include(result)
- end
+ context "with beginless ranges and Float values" do
+ context "with a block returning true or false" do
+ it "returns nil if the block returns true for every element" do
+ (..-0.1).bsearch { |x| x > 0.0 }.should be_nil
+ (...-0.1).bsearch { |x| x > 0.0 }.should be_nil
+ end
+
+ it "returns nil if the block returns nil for every element" do
+ (..-0.1).bsearch { |x| nil }.should be_nil
+ (...-0.1).bsearch { |x| nil }.should be_nil
+ end
+
+ it "returns the smallest element for which block returns true" do
+ (..10).bsearch { |x| x >= 2 }.should == 2
+ (..10).bsearch { |x| x >= 1 }.should == 1
+ end
+
+ it "works with infinity bounds" do
+ inf = Float::INFINITY
+ (..inf).bsearch { |x| true }.should == -inf
+ (...inf).bsearch { |x| true }.should == -inf
+ (..-inf).bsearch { |x| true }.should == -inf
+ (...-inf).bsearch { |x| true }.should == nil
end
end
- context "with beginless ranges and Float values" do
- context "with a block returning true or false" do
- it "returns nil if the block returns true for every element" do
- eval("(..-0.1)").bsearch { |x| x > 0.0 }.should be_nil
- eval("(...-0.1)").bsearch { |x| x > 0.0 }.should be_nil
- end
-
- it "returns nil if the block returns nil for every element" do
- eval("(..-0.1)").bsearch { |x| nil }.should be_nil
- eval("(...-0.1)").bsearch { |x| nil }.should be_nil
- end
-
- it "returns the smallest element for which block returns true" do
- eval("(..10)").bsearch { |x| x >= 2 }.should == 2
- eval("(..10)").bsearch { |x| x >= 1 }.should == 1
- end
-
- it "works with infinity bounds" do
- inf = Float::INFINITY
- eval("(..inf)").bsearch { |x| true }.should == -inf
- eval("(...inf)").bsearch { |x| true }.should == -inf
- eval("(..-inf)").bsearch { |x| true }.should == -inf
- eval("(...-inf)").bsearch { |x| true }.should == nil
- end
- end
-
- context "with a block returning negative, zero, positive numbers" do
- it "returns nil if the block returns less than zero for every element" do
- eval("(..5.0)").bsearch { |x| -1 }.should be_nil
- eval("(...5.0)").bsearch { |x| -1 }.should be_nil
- end
-
- it "returns nil if the block returns greater than zero for every element" do
- eval("(..1.1)").bsearch { |x| 1 }.should be_nil
- eval("(...1.1)").bsearch { |x| 1 }.should be_nil
- end
-
- it "returns nil if the block never returns zero" do
- eval("(..6.3)").bsearch { |x| x < 2 ? 1 : -1 }.should be_nil
- end
-
- it "accepts (+/-)Float::INFINITY from the block" do
- eval("(..5.0)").bsearch { |x| Float::INFINITY }.should be_nil
- eval("(..7.0)").bsearch { |x| -Float::INFINITY }.should be_nil
- end
-
- it "returns an element at an index for which block returns 0.0" do
- result = eval("(..8.0)").bsearch { |x| x < 2 ? 1.0 : x > 2 ? -1.0 : 0.0 }
- result.should == 2
- end
-
- it "returns an element at an index for which block returns 0" do
- result = eval("(..8.0)").bsearch { |x| x < 1 ? 1 : x > 3 ? -1 : 0 }
- result.should >= 1
- result.should <= 3
- end
-
- it "works with infinity bounds" do
- inf = Float::INFINITY
- eval("(..-inf)").bsearch { |x| 1 }.should == nil
- eval("(...-inf)").bsearch { |x| 1 }.should == nil
- eval("(..inf)").bsearch { |x| x == inf ? 0 : 1 }.should == inf
- eval("(...inf)").bsearch { |x| x == inf ? 0 : 1 }.should == nil
- eval("(..-inf)").bsearch { |x| x == -inf ? 0 : -1 }.should == -inf
- eval("(...-inf)").bsearch { |x| x == -inf ? 0 : -1 }.should == nil
- eval("(..inf)").bsearch { |x| 3 - x }.should == 3
- eval("(...inf)").bsearch { |x| 3 - x }.should == 3
- end
+ context "with a block returning negative, zero, positive numbers" do
+ it "returns nil if the block returns less than zero for every element" do
+ (..5.0).bsearch { |x| -1 }.should be_nil
+ (...5.0).bsearch { |x| -1 }.should be_nil
+ end
+
+ it "returns nil if the block returns greater than zero for every element" do
+ (..1.1).bsearch { |x| 1 }.should be_nil
+ (...1.1).bsearch { |x| 1 }.should be_nil
+ end
+
+ it "returns nil if the block never returns zero" do
+ (..6.3).bsearch { |x| x < 2 ? 1 : -1 }.should be_nil
+ end
+
+ it "accepts (+/-)Float::INFINITY from the block" do
+ (..5.0).bsearch { |x| Float::INFINITY }.should be_nil
+ (..7.0).bsearch { |x| -Float::INFINITY }.should be_nil
end
+
+ it "returns an element at an index for which block returns 0.0" do
+ result = (..8.0).bsearch { |x| x < 2 ? 1.0 : x > 2 ? -1.0 : 0.0 }
+ result.should == 2
+ end
+
+ it "returns an element at an index for which block returns 0" do
+ result = (..8.0).bsearch { |x| x < 1 ? 1 : x > 3 ? -1 : 0 }
+ result.should >= 1
+ result.should <= 3
+ end
+
+ it "works with infinity bounds" do
+ inf = Float::INFINITY
+ (..-inf).bsearch { |x| 1 }.should == nil
+ (...-inf).bsearch { |x| 1 }.should == nil
+ (..inf).bsearch { |x| x == inf ? 0 : 1 }.should == inf
+ (...inf).bsearch { |x| x == inf ? 0 : 1 }.should == nil
+ (..-inf).bsearch { |x| x == -inf ? 0 : -1 }.should == -inf
+ (...-inf).bsearch { |x| x == -inf ? 0 : -1 }.should == nil
+ (..inf).bsearch { |x| 3 - x }.should == 3
+ (...inf).bsearch { |x| 3 - x }.should == 3
+ end
+ end
+
+ it "returns enumerator when block not passed" do
+ (..-0.1).bsearch.kind_of?(Enumerator).should == true
end
end
end
diff --git a/spec/ruby/core/range/case_compare_spec.rb b/spec/ruby/core/range/case_compare_spec.rb
index e795026230..65878aaabe 100644
--- a/spec/ruby/core/range/case_compare_spec.rb
+++ b/spec/ruby/core/range/case_compare_spec.rb
@@ -8,8 +8,12 @@ describe "Range#===" do
(range === RangeSpecs::WithoutSucc.new(2)).should == true
end
- ruby_version_is "2.7" do
- it_behaves_like :range_cover_and_include, :===
- it_behaves_like :range_cover, :===
+ it_behaves_like :range_cover_and_include, :===
+ it_behaves_like :range_cover, :===
+
+ ruby_bug "#19533", "3.2"..."3.3" do
+ it "returns true on any value if begin and end are both nil" do
+ (nil..nil).should === 1
+ end
end
end
diff --git a/spec/ruby/core/range/clone_spec.rb b/spec/ruby/core/range/clone_spec.rb
new file mode 100644
index 0000000000..cf6ce74da0
--- /dev/null
+++ b/spec/ruby/core/range/clone_spec.rb
@@ -0,0 +1,26 @@
+require_relative '../../spec_helper'
+
+describe "Range#clone" do
+ it "duplicates the range" do
+ original = (1..3)
+ copy = original.clone
+ copy.begin.should == 1
+ copy.end.should == 3
+ copy.should_not.exclude_end?
+ copy.should_not.equal? original
+
+ original = ("a"..."z")
+ copy = original.clone
+ copy.begin.should == "a"
+ copy.end.should == "z"
+ copy.should.exclude_end?
+ copy.should_not.equal? original
+ end
+
+ it "maintains the frozen state" do
+ (1..2).clone.frozen?.should == (1..2).frozen?
+ (1..).clone.frozen?.should == (1..).frozen?
+ Range.new(1, 2).clone.frozen?.should == Range.new(1, 2).frozen?
+ Class.new(Range).new(1, 2).clone.frozen?.should == Class.new(Range).new(1, 2).frozen?
+ end
+end
diff --git a/spec/ruby/core/range/count_spec.rb b/spec/ruby/core/range/count_spec.rb
index f6f60fa054..24d4a9caf3 100644
--- a/spec/ruby/core/range/count_spec.rb
+++ b/spec/ruby/core/range/count_spec.rb
@@ -1,14 +1,12 @@
require_relative '../../spec_helper'
describe "Range#count" do
- ruby_version_is "2.7" do
- it "returns Infinity for beginless ranges without arguments or blocks" do
- inf = Float::INFINITY
- eval("('a'...)").count.should == inf
- eval("(7..)").count.should == inf
- eval("(...'a')").count.should == inf
- eval("(...nil)").count.should == inf
- eval("(..10.0)").count.should == inf
- end
+ it "returns Infinity for beginless ranges without arguments or blocks" do
+ inf = Float::INFINITY
+ eval("('a'...)").count.should == inf
+ eval("(7..)").count.should == inf
+ (...'a').count.should == inf
+ (...nil).count.should == inf
+ (..10.0).count.should == inf
end
end
diff --git a/spec/ruby/core/range/cover_spec.rb b/spec/ruby/core/range/cover_spec.rb
index fa881607e9..eb7cddc967 100644
--- a/spec/ruby/core/range/cover_spec.rb
+++ b/spec/ruby/core/range/cover_spec.rb
@@ -7,4 +7,8 @@ describe "Range#cover?" do
it_behaves_like :range_cover_and_include, :cover?
it_behaves_like :range_cover, :cover?
it_behaves_like :range_cover_subrange, :cover?
+
+ it "covers U+9995 in the range U+0999..U+9999" do
+ ("\u{999}".."\u{9999}").cover?("\u{9995}").should be_true
+ end
end
diff --git a/spec/ruby/core/range/dup_spec.rb b/spec/ruby/core/range/dup_spec.rb
index 6c9d0c954a..fab3c3f1b2 100644
--- a/spec/ruby/core/range/dup_spec.rb
+++ b/spec/ruby/core/range/dup_spec.rb
@@ -2,14 +2,22 @@ require_relative '../../spec_helper'
describe "Range#dup" do
it "duplicates the range" do
- copy = (1..3).dup
+ original = (1..3)
+ copy = original.dup
copy.begin.should == 1
copy.end.should == 3
copy.should_not.exclude_end?
+ copy.should_not.equal?(original)
copy = ("a"..."z").dup
copy.begin.should == "a"
copy.end.should == "z"
copy.should.exclude_end?
end
+
+ it "creates an unfrozen range" do
+ (1..2).dup.should_not.frozen?
+ (1..).dup.should_not.frozen?
+ Range.new(1, 2).dup.should_not.frozen?
+ end
end
diff --git a/spec/ruby/core/range/each_spec.rb b/spec/ruby/core/range/each_spec.rb
index 6b33f57737..ecae17c881 100644
--- a/spec/ruby/core/range/each_spec.rb
+++ b/spec/ruby/core/range/each_spec.rb
@@ -58,10 +58,8 @@ describe "Range#each" do
a.should == ["A", "B", "C", "D"]
end
- ruby_version_is "2.7" do
- it "raises a TypeError beginless ranges" do
- -> { eval("(..2)").each { |x| x } }.should raise_error(TypeError)
- end
+ it "raises a TypeError beginless ranges" do
+ -> { (..2).each { |x| x } }.should raise_error(TypeError)
end
it "raises a TypeError if the first element does not respond to #succ" do
diff --git a/spec/ruby/core/range/equal_value_spec.rb b/spec/ruby/core/range/equal_value_spec.rb
index 0aaebfb59a..83dcf5cec8 100644
--- a/spec/ruby/core/range/equal_value_spec.rb
+++ b/spec/ruby/core/range/equal_value_spec.rb
@@ -12,9 +12,7 @@ describe "Range#==" do
eval("(1.0..)").should == eval("(1.0..)")
end
- ruby_version_is "2.7" do
- it "returns true if the endpoints are == for beginless ranges" do
- eval("(...10)").should == eval("(...10)")
- end
+ it "returns true if the endpoints are == for beginless ranges" do
+ (...10).should == (...10)
end
end
diff --git a/spec/ruby/core/range/first_spec.rb b/spec/ruby/core/range/first_spec.rb
index c5c90800ac..2af935f439 100644
--- a/spec/ruby/core/range/first_spec.rb
+++ b/spec/ruby/core/range/first_spec.rb
@@ -47,9 +47,7 @@ describe "Range#first" do
-> { (2..3).first("1") }.should raise_error(TypeError)
end
- ruby_version_is "2.7" do
- it "raises a RangeError when called on an beginless range" do
- -> { eval("(..1)").first }.should raise_error(RangeError)
- end
+ it "raises a RangeError when called on an beginless range" do
+ -> { (..1).first }.should raise_error(RangeError)
end
end
diff --git a/spec/ruby/core/range/frozen_spec.rb b/spec/ruby/core/range/frozen_spec.rb
new file mode 100644
index 0000000000..8dab5e5339
--- /dev/null
+++ b/spec/ruby/core/range/frozen_spec.rb
@@ -0,0 +1,25 @@
+require_relative '../../spec_helper'
+
+# There is no Range#frozen? method but this feels like the best place for these specs
+describe "Range#frozen?" do
+ it "is true for literal ranges" do
+ (1..2).should.frozen?
+ (1..).should.frozen?
+ (..1).should.frozen?
+ end
+
+ it "is true for Range.new" do
+ Range.new(1, 2).should.frozen?
+ Range.new(1, nil).should.frozen?
+ Range.new(nil, 1).should.frozen?
+ end
+
+ it "is false for instances of a subclass of Range" do
+ sub_range = Class.new(Range).new(1, 2)
+ sub_range.should_not.frozen?
+ end
+
+ it "is false for Range.allocate" do
+ Range.allocate.should_not.frozen?
+ end
+end
diff --git a/spec/ruby/core/range/include_spec.rb b/spec/ruby/core/range/include_spec.rb
index b2c7a54545..277de205d1 100644
--- a/spec/ruby/core/range/include_spec.rb
+++ b/spec/ruby/core/range/include_spec.rb
@@ -7,4 +7,8 @@ require_relative 'shared/cover'
describe "Range#include?" do
it_behaves_like :range_cover_and_include, :include?
it_behaves_like :range_include, :include?
+
+ it "does not include U+9995 in the range U+0999..U+9999" do
+ ("\u{999}".."\u{9999}").include?("\u{9995}").should be_false
+ end
end
diff --git a/spec/ruby/core/range/initialize_spec.rb b/spec/ruby/core/range/initialize_spec.rb
index 8a6ca65daa..c653caf0c6 100644
--- a/spec/ruby/core/range/initialize_spec.rb
+++ b/spec/ruby/core/range/initialize_spec.rb
@@ -27,18 +27,9 @@ describe "Range#initialize" do
-> { @range.send(:initialize, 1, 3, 5, 7, 9) }.should raise_error(ArgumentError)
end
- ruby_version_is ""..."3.0" do
- it "raises a NameError if called on an already initialized Range" do
- -> { (0..1).send(:initialize, 1, 3) }.should raise_error(NameError)
- -> { (0..1).send(:initialize, 1, 3, true) }.should raise_error(NameError)
- end
- end
-
- ruby_version_is "3.0" do
- it "raises a FrozenError if called on an already initialized Range" do
- -> { (0..1).send(:initialize, 1, 3) }.should raise_error(FrozenError)
- -> { (0..1).send(:initialize, 1, 3, true) }.should raise_error(FrozenError)
- end
+ it "raises a FrozenError if called on an already initialized Range" do
+ -> { (0..1).send(:initialize, 1, 3) }.should raise_error(FrozenError)
+ -> { (0..1).send(:initialize, 1, 3, true) }.should raise_error(FrozenError)
end
it "raises an ArgumentError if arguments don't respond to <=>" do
diff --git a/spec/ruby/core/range/inspect_spec.rb b/spec/ruby/core/range/inspect_spec.rb
index f49882e6ce..072de123b7 100644
--- a/spec/ruby/core/range/inspect_spec.rb
+++ b/spec/ruby/core/range/inspect_spec.rb
@@ -17,29 +17,13 @@ describe "Range#inspect" do
eval("(0.1...)").inspect.should == "0.1..."
end
- ruby_version_is '2.7' do
- it "works for beginless ranges" do
- eval("(..1)").inspect.should == "..1"
- eval("(...0.1)").inspect.should == "...0.1"
- end
-
- it "works for nil ... nil ranges" do
- eval("(..nil)").inspect.should == "nil..nil"
- eval("(nil...)").inspect.should == "nil...nil"
- end
+ it "works for beginless ranges" do
+ (..1).inspect.should == "..1"
+ (...0.1).inspect.should == "...0.1"
end
- ruby_version_is ''...'2.7' do
- it "returns a tainted string if either end is tainted" do
- (("a".taint)..."c").inspect.tainted?.should be_true
- ("a"...("c".taint)).inspect.tainted?.should be_true
- ("a"..."c").taint.inspect.tainted?.should be_true
- end
-
- it "returns a untrusted string if either end is untrusted" do
- (("a".untrust)..."c").inspect.untrusted?.should be_true
- ("a"...("c".untrust)).inspect.untrusted?.should be_true
- ("a"..."c").untrust.inspect.untrusted?.should be_true
- end
+ it "works for nil ... nil ranges" do
+ (..nil).inspect.should == "nil..nil"
+ eval("(nil...)").inspect.should == "nil...nil"
end
end
diff --git a/spec/ruby/core/range/last_spec.rb b/spec/ruby/core/range/last_spec.rb
index d7ef776b42..6698686dd5 100644
--- a/spec/ruby/core/range/last_spec.rb
+++ b/spec/ruby/core/range/last_spec.rb
@@ -8,6 +8,12 @@ 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
+ end
+
it "returns an empty array for an empty Range" do
(0...0).last(2).should == []
end
diff --git a/spec/ruby/core/range/max_spec.rb b/spec/ruby/core/range/max_spec.rb
index a970144d66..a3bbc31e7d 100644
--- a/spec/ruby/core/range/max_spec.rb
+++ b/spec/ruby/core/range/max_spec.rb
@@ -50,17 +50,15 @@ describe "Range#max" do
-> { eval("(1..)").max }.should raise_error(RangeError)
end
- ruby_version_is "3.0" do
- it "returns the end point for beginless ranges" do
- eval("(..1)").max.should == 1
- eval("(..1.0)").max.should == 1.0
- end
+ it "returns the end point for beginless ranges" do
+ (..1).max.should == 1
+ (..1.0).max.should == 1.0
+ end
- it "raises for an exclusive beginless range" do
- -> {
- eval("(...1)").max
- }.should raise_error(TypeError, 'cannot exclude end value with non Integer begin value')
- end
+ it "raises for an exclusive beginless range" do
+ -> {
+ (...1).max
+ }.should raise_error(TypeError, 'cannot exclude end value with non Integer begin value')
end
end
@@ -97,9 +95,7 @@ describe "Range#max given a block" do
(5...5).max {|x,y| x <=> y}.should be_nil
end
- ruby_version_is "2.7" do
- it "raises RangeError when called with custom comparison method on an beginless range" do
- -> { eval("(..1)").max {|a, b| a} }.should raise_error(RangeError)
- end
+ it "raises RangeError when called with custom comparison method on an beginless range" do
+ -> { (..1).max {|a, b| a} }.should raise_error(RangeError)
end
end
diff --git a/spec/ruby/core/range/min_spec.rb b/spec/ruby/core/range/min_spec.rb
index 6e56cc733b..89310ee589 100644
--- a/spec/ruby/core/range/min_spec.rb
+++ b/spec/ruby/core/range/min_spec.rb
@@ -44,10 +44,8 @@ describe "Range#min" do
eval("(1.0...)").min.should == 1.0
end
- ruby_version_is "2.7" do
- it "raises RangeError when called on an beginless range" do
- -> { eval("(..1)").min }.should raise_error(RangeError)
- end
+ it "raises RangeError when called on an beginless range" do
+ -> { (..1).min }.should raise_error(RangeError)
end
end
diff --git a/spec/ruby/core/range/minmax_spec.rb b/spec/ruby/core/range/minmax_spec.rb
index 1db9bfce38..6651ae3726 100644
--- a/spec/ruby/core/range/minmax_spec.rb
+++ b/spec/ruby/core/range/minmax_spec.rb
@@ -1,6 +1,5 @@
require_relative '../../spec_helper'
-# These specs use Range.new instead of the literal notation for beginless Ranges so they parse fine on Ruby < 2.7
describe 'Range#minmax' do
before(:each) do
@x = mock('x')
@@ -13,37 +12,26 @@ describe 'Range#minmax' do
end
describe 'on an inclusive range' do
- ruby_version_is ''...'2.7' do
- it 'should try to iterate endlessly on an endless range' do
- @x.should_receive(:succ).once.and_return(@y)
- range = (@x..)
-
- -> { range.minmax }.should raise_error(NoMethodError, /^undefined method `succ' for/)
- end
- end
-
- ruby_version_is '2.7' do
- it 'should raise RangeError on an endless range without iterating the range' do
- @x.should_not_receive(:succ)
-
- range = (@x..)
+ it 'should raise RangeError on an endless range without iterating the range' do
+ @x.should_not_receive(:succ)
- -> { range.minmax }.should raise_error(RangeError, 'cannot get the maximum of endless range')
- end
+ range = (@x..)
- it 'raises RangeError or ArgumentError on a beginless range' do
- range = Range.new(nil, @x)
+ -> { range.minmax }.should raise_error(RangeError, 'cannot get the maximum of endless range')
+ end
- -> { range.minmax }.should raise_error(StandardError) { |e|
- if RangeError === e
- # error from #min
- -> { raise e }.should raise_error(RangeError, 'cannot get the minimum of beginless range')
- else
- # error from #max
- -> { raise e }.should raise_error(ArgumentError, 'comparison of NilClass with MockObject failed')
- end
- }
- end
+ it 'raises RangeError or ArgumentError on a beginless range' do
+ range = (..@x)
+
+ -> { range.minmax }.should raise_error(StandardError) { |e|
+ if RangeError === e
+ # error from #min
+ -> { raise e }.should raise_error(RangeError, 'cannot get the minimum of beginless range')
+ else
+ # error from #max
+ -> { raise e }.should raise_error(ArgumentError, 'comparison of NilClass with MockObject failed')
+ end
+ }
end
it 'should return beginning of range if beginning and end are equal without iterating the range' do
@@ -58,34 +46,22 @@ describe 'Range#minmax' do
(@y..@x).minmax.should == [nil, nil]
end
- ruby_version_is ''...'2.7' do
- it 'should return the minimum and maximum values for a non-numeric range by iterating the range' do
- @x.should_receive(:succ).once.and_return(@y)
-
- (@x..@y).minmax.should == [@x, @y]
- end
- end
-
- ruby_version_is '2.7' do
- it 'should return the minimum and maximum values for a non-numeric range without iterating the range' do
- @x.should_not_receive(:succ)
+ it 'should return the minimum and maximum values for a non-numeric range without iterating the range' do
+ @x.should_not_receive(:succ)
- (@x..@y).minmax.should == [@x, @y]
- end
+ (@x..@y).minmax.should == [@x, @y]
end
it 'should return the minimum and maximum values for a numeric range' do
(1..3).minmax.should == [1, 3]
end
- ruby_version_is '2.7' do
- it 'should return the minimum and maximum values for a numeric range without iterating the range' do
- # We cannot set expectations on integers,
- # so we "prevent" iteration by picking a value that would iterate until the spec times out.
- range_end = Float::INFINITY
+ it 'should return the minimum and maximum values for a numeric range without iterating the range' do
+ # We cannot set expectations on integers,
+ # so we "prevent" iteration by picking a value that would iterate until the spec times out.
+ range_end = Float::INFINITY
- (1..range_end).minmax.should == [1, range_end]
- end
+ (1..range_end).minmax.should == [1, range_end]
end
it 'should return the minimum and maximum values according to the provided block by iterating the range' do
@@ -96,69 +72,53 @@ describe 'Range#minmax' do
end
describe 'on an exclusive range' do
- ruby_version_is ''...'2.7' do
- # Endless ranges introduced in 2.6
- it 'should try to iterate endlessly on an endless range' do
- @x.should_receive(:succ).once.and_return(@y)
- range = (@x...)
+ it 'should raise RangeError on an endless range' do
+ @x.should_not_receive(:succ)
+ range = (@x...)
- -> { range.minmax }.should raise_error(NoMethodError, /^undefined method `succ' for/)
- end
+ -> { range.minmax }.should raise_error(RangeError, 'cannot get the maximum of endless range')
end
- ruby_version_is '2.7' do
- it 'should raise RangeError on an endless range' do
- @x.should_not_receive(:succ)
- range = (@x...)
-
- -> { range.minmax }.should raise_error(RangeError, 'cannot get the maximum of endless range')
- end
-
- it 'should raise RangeError on a beginless range' do
- range = Range.new(nil, @x, true)
+ it 'should raise RangeError on a beginless range' do
+ range = (...@x)
- -> { range.minmax }.should raise_error(RangeError,
- /cannot get the maximum of beginless range with custom comparison method|cannot get the minimum of beginless range/)
- end
+ -> { range.minmax }.should raise_error(RangeError,
+ /cannot get the maximum of beginless range with custom comparison method|cannot get the minimum of beginless range/)
end
- ruby_bug "#17014", "2.7.0"..."3.0" do
- it 'should return nil pair if beginning and end are equal without iterating the range' do
- @x.should_not_receive(:succ)
+ it 'should return nil pair if beginning and end are equal without iterating the range' do
+ @x.should_not_receive(:succ)
- (@x...@x).minmax.should == [nil, nil]
- end
+ (@x...@x).minmax.should == [nil, nil]
+ end
- it 'should return nil pair if beginning is greater than end without iterating the range' do
- @y.should_not_receive(:succ)
+ it 'should return nil pair if beginning is greater than end without iterating the range' do
+ @y.should_not_receive(:succ)
- (@y...@x).minmax.should == [nil, nil]
- end
+ (@y...@x).minmax.should == [nil, nil]
+ end
- it 'should return the minimum and maximum values for a non-numeric range by iterating the range' do
- @x.should_receive(:succ).once.and_return(@y)
+ it 'should return the minimum and maximum values for a non-numeric range by iterating the range' do
+ @x.should_receive(:succ).once.and_return(@y)
- (@x...@y).minmax.should == [@x, @x]
- end
+ (@x...@y).minmax.should == [@x, @x]
end
it 'should return the minimum and maximum values for a numeric range' do
(1...3).minmax.should == [1, 2]
end
- ruby_version_is '2.7' do
- it 'should return the minimum and maximum values for a numeric range without iterating the range' do
- # We cannot set expectations on integers,
- # so we "prevent" iteration by picking a value that would iterate until the spec times out.
- range_end = bignum_value
+ it 'should return the minimum and maximum values for a numeric range without iterating the range' do
+ # We cannot set expectations on integers,
+ # so we "prevent" iteration by picking a value that would iterate until the spec times out.
+ range_end = bignum_value
- (1...range_end).minmax.should == [1, range_end - 1]
- end
+ (1...range_end).minmax.should == [1, range_end - 1]
+ end
- it 'raises TypeError if the end value is not an integer' do
- range = (0...Float::INFINITY)
- -> { range.minmax }.should raise_error(TypeError, 'cannot exclude non Integer end value')
- end
+ it 'raises TypeError if the end value is not an integer' do
+ range = (0...Float::INFINITY)
+ -> { range.minmax }.should raise_error(TypeError, 'cannot exclude non Integer end value')
end
it 'should return the minimum and maximum values according to the provided block by iterating the range' do
diff --git a/spec/ruby/core/range/new_spec.rb b/spec/ruby/core/range/new_spec.rb
index a4de4963e7..3cab887799 100644
--- a/spec/ruby/core/range/new_spec.rb
+++ b/spec/ruby/core/range/new_spec.rb
@@ -42,24 +42,16 @@ describe "Range.new" do
end
describe "beginless/endless range" do
- ruby_version_is ""..."2.7" do
- it "does not allow range without left boundary" do
- -> { Range.new(nil, 1) }.should raise_error(ArgumentError, /bad value for range/)
- end
+ it "allows beginless left boundary" do
+ range = Range.new(nil, 1)
+ range.begin.should == nil
end
- ruby_version_is "2.7" do
- it "allows beginless left boundary" do
- range = Range.new(nil, 1)
- range.begin.should == nil
- end
-
- it "distinguishes ranges with included and excluded right boundary" do
- range_exclude = Range.new(nil, 1, true)
- range_include = Range.new(nil, 1, false)
+ it "distinguishes ranges with included and excluded right boundary" do
+ range_exclude = Range.new(nil, 1, true)
+ range_include = Range.new(nil, 1, false)
- range_exclude.should_not == range_include
- end
+ range_exclude.should_not == range_include
end
it "allows endless right boundary" do
@@ -73,5 +65,13 @@ describe "Range.new" do
range_exclude.should_not == range_include
end
+
+ it "creates a frozen range if the class is Range.class" do
+ Range.new(1, 2).should.frozen?
+ end
+
+ it "does not create a frozen range if the class is not Range.class" do
+ Class.new(Range).new(1, 2).should_not.frozen?
+ end
end
end
diff --git a/spec/ruby/core/range/shared/cover.rb b/spec/ruby/core/range/shared/cover.rb
index f3c7d22668..0b41a26455 100644
--- a/spec/ruby/core/range/shared/cover.rb
+++ b/spec/ruby/core/range/shared/cover.rb
@@ -151,45 +151,43 @@ describe :range_cover_subrange, shared: true do
end
end
- ruby_version_is "2.7" do
- it "allows self to be a beginless range" do
- eval("(...10)").send(@method, (3..7)).should be_true
- eval("(...10)").send(@method, (3..15)).should be_false
+ it "allows self to be a beginless range" do
+ (...10).send(@method, (3..7)).should be_true
+ (...10).send(@method, (3..15)).should be_false
- eval("(..7.9)").send(@method, (2.5..6.5)).should be_true
- eval("(..7.9)").send(@method, (2.5..8.5)).should be_false
+ (..7.9).send(@method, (2.5..6.5)).should be_true
+ (..7.9).send(@method, (2.5..8.5)).should be_false
- eval("(..'i')").send(@method, ('d'..'f')).should be_true
- eval("(..'i')").send(@method, ('d'..'z')).should be_false
- end
+ (..'i').send(@method, ('d'..'f')).should be_true
+ (..'i').send(@method, ('d'..'z')).should be_false
+ end
- it "allows self to be a endless range" do
- eval("(0...)").send(@method, (3..7)).should be_true
- eval("(5...)").send(@method, (3..15)).should be_false
+ it "allows self to be a endless range" do
+ eval("(0...)").send(@method, (3..7)).should be_true
+ eval("(5...)").send(@method, (3..15)).should be_false
- eval("(1.1..)").send(@method, (2.5..6.5)).should be_true
- eval("(3.3..)").send(@method, (2.5..8.5)).should be_false
+ eval("(1.1..)").send(@method, (2.5..6.5)).should be_true
+ eval("(3.3..)").send(@method, (2.5..8.5)).should be_false
- eval("('a'..)").send(@method, ('d'..'f')).should be_true
- eval("('p'..)").send(@method, ('d'..'z')).should be_false
- end
+ eval("('a'..)").send(@method, ('d'..'f')).should be_true
+ eval("('p'..)").send(@method, ('d'..'z')).should be_false
+ end
- it "accepts beginless range argument" do
- eval("(..10)").send(@method, eval("(...10)")).should be_true
- (0..10).send(@method, eval("(...10)")).should be_false
+ it "accepts beginless range argument" do
+ (..10).send(@method, (...10)).should be_true
+ (0..10).send(@method, (...10)).should be_false
- (1.1..7.9).send(@method, eval("(...10.5)")).should be_false
+ (1.1..7.9).send(@method, (...10.5)).should be_false
- ('c'..'i').send(@method, eval("(..'i')")).should be_false
- end
+ ('c'..'i').send(@method, (..'i')).should be_false
+ end
- it "accepts endless range argument" do
- eval("(0..)").send(@method, eval("(0...)")).should be_true
- (0..10).send(@method, eval("(0...)")).should be_false
+ it "accepts endless range argument" do
+ eval("(0..)").send(@method, eval("(0...)")).should be_true
+ (0..10).send(@method, eval("(0...)")).should be_false
- (1.1..7.9).send(@method, eval("(0.8...)")).should be_false
+ (1.1..7.9).send(@method, eval("(0.8...)")).should be_false
- ('c'..'i').send(@method, eval("('a'..)")).should be_false
- end
+ ('c'..'i').send(@method, eval("('a'..)")).should be_false
end
end
diff --git a/spec/ruby/core/range/shared/cover_and_include.rb b/spec/ruby/core/range/shared/cover_and_include.rb
index e978e39af5..f36a2cef8b 100644
--- a/spec/ruby/core/range/shared/cover_and_include.rb
+++ b/spec/ruby/core/range/shared/cover_and_include.rb
@@ -24,11 +24,9 @@ describe :range_cover_and_include, shared: true do
eval("(0.5...)").send(@method, 2.4).should == true
end
- ruby_version_is "2.7" do
- it "returns true if other is an element of self for beginless ranges" do
- eval("(..10)").send(@method, 2.4).should == true
- eval("(...10.5)").send(@method, 2.4).should == true
- end
+ it "returns true if other is an element of self for beginless ranges" do
+ (..10).send(@method, 2.4).should == true
+ (...10.5).send(@method, 2.4).should == true
end
it "compares values using <=>" do
@@ -59,7 +57,6 @@ describe :range_cover_and_include, shared: true do
it "returns true if argument is less than the last value of the range and greater than the first value" do
(20..30).send(@method, 28).should be_true
('e'..'h').send(@method, 'g').should be_true
- ("\u{999}".."\u{9999}").send @method, "\u{9995}"
end
it "returns true if argument is sole element in the range" do
diff --git a/spec/ruby/core/range/size_spec.rb b/spec/ruby/core/range/size_spec.rb
index 0019c5ff00..a1fe3ce17d 100644
--- a/spec/ruby/core/range/size_spec.rb
+++ b/spec/ruby/core/range/size_spec.rb
@@ -4,42 +4,93 @@ describe "Range#size" do
it "returns the number of elements in the range" do
(1..16).size.should == 16
(1...16).size.should == 15
-
- (1.0..16.0).size.should == 16
- (1.0...16.0).size.should == 15
- (1.0..15.9).size.should == 15
- (1.1..16.0).size.should == 15
- (1.1..15.9).size.should == 15
end
it "returns 0 if last is less than first" do
(16..0).size.should == 0
- (16.0..0.0).size.should == 0
- (Float::INFINITY..0).size.should == 0
end
it 'returns Float::INFINITY for increasing, infinite ranges' do
(0..Float::INFINITY).size.should == Float::INFINITY
- (-Float::INFINITY..0).size.should == Float::INFINITY
- (-Float::INFINITY..Float::INFINITY).size.should == Float::INFINITY
end
it 'returns Float::INFINITY for endless ranges if the start is numeric' do
eval("(1..)").size.should == Float::INFINITY
- eval("(0.5...)").size.should == Float::INFINITY
end
it 'returns nil for endless ranges if the start is not numeric' do
eval("('z'..)").size.should == nil
- eval("([]...)").size.should == nil
end
- ruby_version_is "2.7" do
+ ruby_version_is ""..."3.2" do
it 'returns Float::INFINITY for all beginless ranges' do
- eval("(..1)").size.should == Float::INFINITY
- eval("(...0.5)").size.should == Float::INFINITY
- eval("(..nil)").size.should == Float::INFINITY
- eval("(...'o')").size.should == Float::INFINITY
+ (..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
+ it 'returns Float::INFINITY for all beginless ranges if the end is numeric' do
+ (..1).size.should == Float::INFINITY
+ (...0.5).size.should == Float::INFINITY
+ end
+
+ it 'returns nil for all beginless ranges if the end is not numeric' do
+ (...'o').size.should == nil
+ end
+
+ it 'returns nil if the start and the end is both nil' do
+ (nil..nil).size.should == nil
+ end
+ end
+
+ ruby_version_is ""..."3.4" do
+ it "returns the number of elements in the range" do
+ (1.0..16.0).size.should == 16
+ (1.0...16.0).size.should == 15
+ (1.0..15.9).size.should == 15
+ (1.1..16.0).size.should == 15
+ (1.1..15.9).size.should == 15
+ end
+
+ it "returns 0 if last is less than first" do
+ (16.0..0.0).size.should == 0
+ (Float::INFINITY..0).size.should == 0
+ end
+
+ it 'returns Float::INFINITY for increasing, infinite ranges' do
+ (-Float::INFINITY..0).size.should == Float::INFINITY
+ (-Float::INFINITY..Float::INFINITY).size.should == Float::INFINITY
+ end
+
+ it 'returns Float::INFINITY for endless ranges if the start is numeric' do
+ eval("(0.5...)").size.should == Float::INFINITY
+ end
+
+ it 'returns nil for endless ranges if the start is not numeric' do
+ eval("([]...)").size.should == nil
+ end
+ end
+
+ ruby_version_is "3.4" do
+ it 'raises TypeError if a range is not iterable' do
+ -> { (1.0..16.0).size }.should raise_error(TypeError, /can't iterate from/)
+ -> { (1.0...16.0).size }.should raise_error(TypeError, /can't iterate from/)
+ -> { (1.0..15.9).size }.should raise_error(TypeError, /can't iterate from/)
+ -> { (1.1..16.0).size }.should raise_error(TypeError, /can't iterate from/)
+ -> { (1.1..15.9).size }.should raise_error(TypeError, /can't iterate from/)
+ -> { (16.0..0.0).size }.should raise_error(TypeError, /can't iterate from/)
+ -> { (Float::INFINITY..0).size }.should raise_error(TypeError, /can't iterate from/)
+ -> { (-Float::INFINITY..0).size }.should raise_error(TypeError, /can't iterate from/)
+ -> { (-Float::INFINITY..Float::INFINITY).size }.should raise_error(TypeError, /can't iterate from/)
+ -> { (..1).size }.should raise_error(TypeError, /can't iterate from/)
+ -> { (...0.5).size }.should raise_error(TypeError, /can't iterate from/)
+ -> { (..nil).size }.should raise_error(TypeError, /can't iterate from/)
+ -> { (...'o').size }.should raise_error(TypeError, /can't iterate from/)
+ -> { eval("(0.5...)").size }.should raise_error(TypeError, /can't iterate from/)
+ -> { eval("([]...)").size }.should raise_error(TypeError, /can't iterate from/)
end
end
diff --git a/spec/ruby/core/range/step_spec.rb b/spec/ruby/core/range/step_spec.rb
index 4c69073854..64ea3de4ed 100644
--- a/spec/ruby/core/range/step_spec.rb
+++ b/spec/ruby/core/range/step_spec.rb
@@ -377,48 +377,21 @@ describe "Range#step" do
end
describe "when no block is given" do
- ruby_version_is "3.0" do
- it "raises an ArgumentError if step is 0" do
- -> { (-1..1).step(0) }.should raise_error(ArgumentError)
- end
+ it "raises an ArgumentError if step is 0" do
+ -> { (-1..1).step(0) }.should raise_error(ArgumentError)
end
describe "returned Enumerator" do
describe "size" do
- ruby_version_is ""..."3.0" do
- it "raises a TypeError if step does not respond to #to_int" do
- obj = mock("Range#step non-integer")
- enum = (1..2).step(obj)
- -> { enum.size }.should raise_error(TypeError)
- end
-
- it "raises a TypeError if #to_int does not return an Integer" do
- obj = mock("Range#step non-integer")
- obj.should_receive(:to_int).and_return("1")
- enum = (1..2).step(obj)
-
- -> { enum.size }.should raise_error(TypeError)
- end
+ it "raises a TypeError if step does not respond to #to_int" do
+ obj = mock("Range#step non-integer")
+ -> { (1..2).step(obj) }.should raise_error(TypeError)
end
- ruby_version_is "3.0" do
- it "raises a TypeError if step does not respond to #to_int" do
- obj = mock("Range#step non-integer")
- -> { (1..2).step(obj) }.should raise_error(TypeError)
- end
-
- it "raises a TypeError if #to_int does not return an Integer" do
- obj = mock("Range#step non-integer")
- obj.should_receive(:to_int).and_return("1")
- -> { (1..2).step(obj) }.should raise_error(TypeError)
- end
- end
-
- ruby_version_is ""..."3.0" do
- it "returns Float::INFINITY for zero step" do
- (-1..1).step(0).size.should == Float::INFINITY
- (-1..1).step(0.0).size.should == Float::INFINITY
- end
+ it "raises a TypeError if #to_int does not return an Integer" do
+ obj = mock("Range#step non-integer")
+ obj.should_receive(:to_int).and_return("1")
+ -> { (1..2).step(obj) }.should raise_error(TypeError)
end
it "returns the ceil of range size divided by the number of steps" do
@@ -474,42 +447,45 @@ describe "Range#step" do
end
end
+ # We use .take below to ensure the enumerator works
+ # because that's an Enumerable method and so it uses the Enumerator behavior
+ # not just a method overridden in Enumerator::ArithmeticSequence.
describe "type" do
context "when both begin and end are numerics" do
it "returns an instance of Enumerator::ArithmeticSequence" do
(1..10).step.class.should == Enumerator::ArithmeticSequence
+ (1..10).step(3).take(4).should == [1, 4, 7, 10]
end
end
- ruby_version_is "2.7" do
- context "when begin is not defined and end is numeric" do
- it "returns an instance of Enumerator::ArithmeticSequence" do
- eval("(..10)").step.class.should == Enumerator::ArithmeticSequence
- end
+ context "when begin is not defined and end is numeric" do
+ it "returns an instance of Enumerator::ArithmeticSequence" do
+ (..10).step.class.should == Enumerator::ArithmeticSequence
end
end
context "when range is endless" do
it "returns an instance of Enumerator::ArithmeticSequence when begin is numeric" do
(1..).step.class.should == Enumerator::ArithmeticSequence
+ (1..).step(2).take(3).should == [1, 3, 5]
end
it "returns an instance of Enumerator when begin is not numeric" do
("a"..).step.class.should == Enumerator
+ ("a"..).step(2).take(3).should == %w[a c e]
end
end
- ruby_version_is "2.7" do
- context "when range is beginless and endless" do
- it "returns an instance of Enumerator" do
- Range.new(nil, nil).step.class.should == Enumerator
- end
+ context "when range is beginless and endless" do
+ it "returns an instance of Enumerator" do
+ Range.new(nil, nil).step.class.should == Enumerator
end
end
context "when begin and end are not numerics" do
it "returns an instance of Enumerator" do
("a".."z").step.class.should == Enumerator
+ ("a".."z").step(3).take(4).should == %w[a d g j]
end
end
end
diff --git a/spec/ruby/core/range/to_a_spec.rb b/spec/ruby/core/range/to_a_spec.rb
index 52ebc02941..b1d3de32db 100644
--- a/spec/ruby/core/range/to_a_spec.rb
+++ b/spec/ruby/core/range/to_a_spec.rb
@@ -33,9 +33,7 @@ describe "Range#to_a" do
-> { eval("(1..)").to_a }.should raise_error(RangeError)
end
- ruby_version_is "2.7" do
- it "throws an exception for beginless ranges" do
- -> { eval("(..1)").to_a }.should raise_error(TypeError)
- end
+ it "throws an exception for beginless ranges" do
+ -> { (..1).to_a }.should raise_error(TypeError)
end
end
diff --git a/spec/ruby/core/range/to_s_spec.rb b/spec/ruby/core/range/to_s_spec.rb
index 581c2e7d90..460c330912 100644
--- a/spec/ruby/core/range/to_s_spec.rb
+++ b/spec/ruby/core/range/to_s_spec.rb
@@ -16,24 +16,8 @@ describe "Range#to_s" do
eval("(1.0...)").to_s.should == "1.0..."
end
- ruby_version_is "2.7" do
- it "can show beginless ranges" do
- eval("(..1)").to_s.should == "..1"
- eval("(...1.0)").to_s.should == "...1.0"
- end
- end
-
- ruby_version_is ''...'2.7' do
- it "returns a tainted string if either end is tainted" do
- (("a".taint)..."c").to_s.tainted?.should be_true
- ("a"...("c".taint)).to_s.tainted?.should be_true
- ("a"..."c").taint.to_s.tainted?.should be_true
- end
-
- it "returns a untrusted string if either end is untrusted" do
- (("a".untrust)..."c").to_s.untrusted?.should be_true
- ("a"...("c".untrust)).to_s.untrusted?.should be_true
- ("a"..."c").untrust.to_s.untrusted?.should be_true
- end
+ it "can show beginless ranges" do
+ (..1).to_s.should == "..1"
+ (...1.0).to_s.should == "...1.0"
end
end
diff --git a/spec/ruby/core/rational/abs_spec.rb b/spec/ruby/core/rational/abs_spec.rb
index aed7713058..7272ad2422 100644
--- a/spec/ruby/core/rational/abs_spec.rb
+++ b/spec/ruby/core/rational/abs_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../spec_helper"
require_relative '../../shared/rational/abs'
describe "Rational#abs" do
diff --git a/spec/ruby/core/rational/ceil_spec.rb b/spec/ruby/core/rational/ceil_spec.rb
index 5b0ca4a9d6..e736351604 100644
--- a/spec/ruby/core/rational/ceil_spec.rb
+++ b/spec/ruby/core/rational/ceil_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../spec_helper"
require_relative '../../shared/rational/ceil'
describe "Rational#ceil" do
diff --git a/spec/ruby/core/rational/coerce_spec.rb b/spec/ruby/core/rational/coerce_spec.rb
deleted file mode 100644
index 3f78f0bcd6..0000000000
--- a/spec/ruby/core/rational/coerce_spec.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-require_relative '../../shared/rational/coerce'
-
-describe "Rational#coerce" do
- it_behaves_like :rational_coerce, :coerce
-end
diff --git a/spec/ruby/core/rational/comparison_spec.rb b/spec/ruby/core/rational/comparison_spec.rb
index 9d8e7fd7ee..877069fb8f 100644
--- a/spec/ruby/core/rational/comparison_spec.rb
+++ b/spec/ruby/core/rational/comparison_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../spec_helper"
require_relative '../../shared/rational/comparison'
describe "Rational#<=> when passed a Rational object" do
diff --git a/spec/ruby/core/rational/denominator_spec.rb b/spec/ruby/core/rational/denominator_spec.rb
index 6214b40587..c2f49b4190 100644
--- a/spec/ruby/core/rational/denominator_spec.rb
+++ b/spec/ruby/core/rational/denominator_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../spec_helper"
require_relative '../../shared/rational/denominator'
describe "Rational#denominator" do
diff --git a/spec/ruby/core/rational/div_spec.rb b/spec/ruby/core/rational/div_spec.rb
index 1cd8606b90..bee7d01a67 100644
--- a/spec/ruby/core/rational/div_spec.rb
+++ b/spec/ruby/core/rational/div_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../spec_helper"
require_relative '../../shared/rational/div'
describe "Rational#div" do
diff --git a/spec/ruby/core/rational/divide_spec.rb b/spec/ruby/core/rational/divide_spec.rb
index d8e3a44dc2..14e8c4c195 100644
--- a/spec/ruby/core/rational/divide_spec.rb
+++ b/spec/ruby/core/rational/divide_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../spec_helper"
require_relative '../../shared/rational/divide'
require_relative '../../shared/rational/arithmetic_exception_in_coerce'
diff --git a/spec/ruby/core/rational/divmod_spec.rb b/spec/ruby/core/rational/divmod_spec.rb
index 6be1f8bd73..7ffdde74f4 100644
--- a/spec/ruby/core/rational/divmod_spec.rb
+++ b/spec/ruby/core/rational/divmod_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../spec_helper"
require_relative '../../shared/rational/divmod'
describe "Rational#divmod when passed a Rational" do
diff --git a/spec/ruby/core/rational/equal_value_spec.rb b/spec/ruby/core/rational/equal_value_spec.rb
index 8e7acb1354..c6f7f4c6a2 100644
--- a/spec/ruby/core/rational/equal_value_spec.rb
+++ b/spec/ruby/core/rational/equal_value_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../spec_helper"
require_relative '../../shared/rational/equal_value'
describe "Rational#==" do
diff --git a/spec/ruby/core/rational/exponent_spec.rb b/spec/ruby/core/rational/exponent_spec.rb
index 622cf22782..7e35b4ebc1 100644
--- a/spec/ruby/core/rational/exponent_spec.rb
+++ b/spec/ruby/core/rational/exponent_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../spec_helper"
require_relative '../../shared/rational/exponent'
describe "Rational#**" do
diff --git a/spec/ruby/core/rational/fdiv_spec.rb b/spec/ruby/core/rational/fdiv_spec.rb
index bfb321abaa..b75f39abd5 100644
--- a/spec/ruby/core/rational/fdiv_spec.rb
+++ b/spec/ruby/core/rational/fdiv_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../spec_helper"
require_relative '../../shared/rational/fdiv'
describe "Rational#fdiv" do
diff --git a/spec/ruby/core/rational/floor_spec.rb b/spec/ruby/core/rational/floor_spec.rb
index 752a2d8815..70db0499d0 100644
--- a/spec/ruby/core/rational/floor_spec.rb
+++ b/spec/ruby/core/rational/floor_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../spec_helper"
require_relative '../../shared/rational/floor'
describe "Rational#floor" do
diff --git a/spec/ruby/core/rational/hash_spec.rb b/spec/ruby/core/rational/hash_spec.rb
index 84cd31518a..7e8d30049b 100644
--- a/spec/ruby/core/rational/hash_spec.rb
+++ b/spec/ruby/core/rational/hash_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../spec_helper"
require_relative '../../shared/rational/hash'
describe "Rational#hash" do
diff --git a/spec/ruby/core/rational/inspect_spec.rb b/spec/ruby/core/rational/inspect_spec.rb
index ef337ef0ce..2cbf6cadc1 100644
--- a/spec/ruby/core/rational/inspect_spec.rb
+++ b/spec/ruby/core/rational/inspect_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../spec_helper"
require_relative '../../shared/rational/inspect'
describe "Rational#inspect" do
diff --git a/spec/ruby/core/rational/integer_spec.rb b/spec/ruby/core/rational/integer_spec.rb
index 0f9a3bdead..be7476a9dd 100644
--- a/spec/ruby/core/rational/integer_spec.rb
+++ b/spec/ruby/core/rational/integer_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../spec_helper"
describe "Rational#integer?" do
# Guard against the Mathn library
guard -> { !defined?(Math.rsqrt) } do
diff --git a/spec/ruby/core/rational/magnitude_spec.rb b/spec/ruby/core/rational/magnitude_spec.rb
index 878fc8f879..27d9af6a81 100644
--- a/spec/ruby/core/rational/magnitude_spec.rb
+++ b/spec/ruby/core/rational/magnitude_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../spec_helper"
require_relative '../../shared/rational/abs'
describe "Rational#abs" do
diff --git a/spec/ruby/core/rational/minus_spec.rb b/spec/ruby/core/rational/minus_spec.rb
index 9e0f81556b..a61b62ebe6 100644
--- a/spec/ruby/core/rational/minus_spec.rb
+++ b/spec/ruby/core/rational/minus_spec.rb
@@ -1,7 +1,51 @@
-require_relative '../../shared/rational/minus'
+require_relative '../../spec_helper'
require_relative '../../shared/rational/arithmetic_exception_in_coerce'
describe "Rational#-" do
- it_behaves_like :rational_minus, :-
it_behaves_like :rational_arithmetic_exception_in_coerce, :-
+
+ it "calls #coerce on the passed argument with self" do
+ rational = Rational(3, 4)
+ obj = mock("Object")
+ obj.should_receive(:coerce).with(rational).and_return([1, 2])
+
+ rational - obj
+ end
+
+ it "calls #- on the coerced Rational with the coerced Object" do
+ rational = Rational(3, 4)
+
+ coerced_rational = mock("Coerced Rational")
+ coerced_rational.should_receive(:-).and_return(:result)
+
+ coerced_obj = mock("Coerced Object")
+
+ obj = mock("Object")
+ obj.should_receive(:coerce).and_return([coerced_rational, coerced_obj])
+
+ (rational - obj).should == :result
+ end
+end
+
+describe "Rational#- passed a Rational" do
+ it "returns the result of subtracting other from self as a Rational" do
+ (Rational(3, 4) - Rational(0, 1)).should eql(Rational(3, 4))
+ (Rational(3, 4) - Rational(1, 4)).should eql(Rational(1, 2))
+
+ (Rational(3, 4) - Rational(2, 1)).should eql(Rational(-5, 4))
+ end
+end
+
+describe "Rational#- passed a Float" do
+ it "returns the result of subtracting other from self as a Float" do
+ (Rational(3, 4) - 0.2).should eql(0.55)
+ (Rational(3, 4) - 2.5).should eql(-1.75)
+ end
+end
+
+describe "Rational#- passed an Integer" do
+ it "returns the result of subtracting other from self as a Rational" do
+ (Rational(3, 4) - 1).should eql(Rational(-1, 4))
+ (Rational(3, 4) - 2).should eql(Rational(-5, 4))
+ end
end
diff --git a/spec/ruby/core/rational/modulo_spec.rb b/spec/ruby/core/rational/modulo_spec.rb
index c43f7788e3..7a60c176ac 100644
--- a/spec/ruby/core/rational/modulo_spec.rb
+++ b/spec/ruby/core/rational/modulo_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../spec_helper"
require_relative '../../shared/rational/modulo'
describe "Rational#%" do
diff --git a/spec/ruby/core/rational/multiply_spec.rb b/spec/ruby/core/rational/multiply_spec.rb
index ea644074e9..7413376bb1 100644
--- a/spec/ruby/core/rational/multiply_spec.rb
+++ b/spec/ruby/core/rational/multiply_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../spec_helper"
require_relative '../../shared/rational/multiply'
require_relative '../../shared/rational/arithmetic_exception_in_coerce'
diff --git a/spec/ruby/core/rational/numerator_spec.rb b/spec/ruby/core/rational/numerator_spec.rb
index 85b2ed9e86..6f9a9c0e3b 100644
--- a/spec/ruby/core/rational/numerator_spec.rb
+++ b/spec/ruby/core/rational/numerator_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../spec_helper"
require_relative '../../shared/rational/numerator'
describe "Rational#numerator" do
diff --git a/spec/ruby/core/rational/plus_spec.rb b/spec/ruby/core/rational/plus_spec.rb
index e7ef3a8f92..67c0ff63d2 100644
--- a/spec/ruby/core/rational/plus_spec.rb
+++ b/spec/ruby/core/rational/plus_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../spec_helper"
require_relative '../../shared/rational/plus'
require_relative '../../shared/rational/arithmetic_exception_in_coerce'
diff --git a/spec/ruby/core/rational/quo_spec.rb b/spec/ruby/core/rational/quo_spec.rb
index 119aca1955..181f091f7c 100644
--- a/spec/ruby/core/rational/quo_spec.rb
+++ b/spec/ruby/core/rational/quo_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../spec_helper"
require_relative '../../shared/rational/divide'
describe "Rational#quo" do
diff --git a/spec/ruby/core/rational/remainder_spec.rb b/spec/ruby/core/rational/remainder_spec.rb
index 0f9442f6f5..1c0035e5f4 100644
--- a/spec/ruby/core/rational/remainder_spec.rb
+++ b/spec/ruby/core/rational/remainder_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../spec_helper"
require_relative '../../shared/rational/remainder'
describe "Rational#remainder" do
diff --git a/spec/ruby/core/rational/to_f_spec.rb b/spec/ruby/core/rational/to_f_spec.rb
index 15bf1e88dc..a9cd1be3b5 100644
--- a/spec/ruby/core/rational/to_f_spec.rb
+++ b/spec/ruby/core/rational/to_f_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../spec_helper"
require_relative '../../shared/rational/to_f'
describe "Rational#to_f" do
diff --git a/spec/ruby/core/rational/to_i_spec.rb b/spec/ruby/core/rational/to_i_spec.rb
index 3deb3664e1..22cf02b4da 100644
--- a/spec/ruby/core/rational/to_i_spec.rb
+++ b/spec/ruby/core/rational/to_i_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../spec_helper"
require_relative '../../shared/rational/to_i'
describe "Rational#to_i" do
diff --git a/spec/ruby/core/rational/to_r_spec.rb b/spec/ruby/core/rational/to_r_spec.rb
index cc704c965e..03f204daf1 100644
--- a/spec/ruby/core/rational/to_r_spec.rb
+++ b/spec/ruby/core/rational/to_r_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../spec_helper"
require_relative '../../shared/rational/to_r'
describe "Rational#to_r" do
diff --git a/spec/ruby/core/rational/to_s_spec.rb b/spec/ruby/core/rational/to_s_spec.rb
index c5c419787c..5d90c7d80b 100644
--- a/spec/ruby/core/rational/to_s_spec.rb
+++ b/spec/ruby/core/rational/to_s_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../spec_helper"
require_relative '../../shared/rational/to_s'
describe "Rational#to_s" do
diff --git a/spec/ruby/core/rational/truncate_spec.rb b/spec/ruby/core/rational/truncate_spec.rb
index 4e72339752..47a7cdf17c 100644
--- a/spec/ruby/core/rational/truncate_spec.rb
+++ b/spec/ruby/core/rational/truncate_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../spec_helper"
require_relative '../../shared/rational/truncate'
describe "Rational#truncate" do
diff --git a/spec/ruby/core/rational/zero_spec.rb b/spec/ruby/core/rational/zero_spec.rb
index e6dd751922..af7fb391ac 100644
--- a/spec/ruby/core/rational/zero_spec.rb
+++ b/spec/ruby/core/rational/zero_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../spec_helper"
describe "Rational#zero?" do
it "returns true if the numerator is 0" do
Rational(0,26).zero?.should be_true
diff --git a/spec/ruby/core/refinement/extend_object_spec.rb b/spec/ruby/core/refinement/extend_object_spec.rb
index e44e9f46d8..6c2a0af4f3 100644
--- a/spec/ruby/core/refinement/extend_object_spec.rb
+++ b/spec/ruby/core/refinement/extend_object_spec.rb
@@ -11,8 +11,10 @@ describe "Refinement#extend_object" do
Module.new do
refine c do
called = false
- define_method(:extend_object){called = true}
- proc{c.extend(self)}.should raise_error(TypeError)
+ define_method(:extend_object) { called = true }
+ -> {
+ c.extend(self)
+ }.should raise_error(TypeError)
called.should == false
end
end
diff --git a/spec/ruby/core/refinement/fixtures/classes.rb b/spec/ruby/core/refinement/fixtures/classes.rb
new file mode 100644
index 0000000000..94324db47c
--- /dev/null
+++ b/spec/ruby/core/refinement/fixtures/classes.rb
@@ -0,0 +1,10 @@
+module RefinementSpec
+
+ module ModuleWithAncestors
+ include Module.new do
+ def indent(level)
+ " " * level + self
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/refinement/import_methods_spec.rb b/spec/ruby/core/refinement/import_methods_spec.rb
new file mode 100644
index 0000000000..614c54dff8
--- /dev/null
+++ b/spec/ruby/core/refinement/import_methods_spec.rb
@@ -0,0 +1,269 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+
+describe "Refinement#import_methods" do
+ ruby_version_is "3.1" do
+ context "when methods are defined in Ruby code" do
+ it "imports methods" do
+ str_utils = Module.new do
+ def indent(level)
+ " " * level + self
+ end
+ end
+
+ Module.new do
+ refine String do
+ import_methods str_utils
+ "foo".indent(3).should == " foo"
+ end
+ end
+ end
+
+ it "throws an exception when argument is not a module" do
+ Module.new do
+ refine String do
+ -> {
+ import_methods Integer
+ }.should raise_error(TypeError, "wrong argument type Class (expected Module)")
+ end
+ end
+ end
+
+ it "imports methods from multiple modules" do
+ str_utils = Module.new do
+ def indent(level)
+ " " * level + self
+ end
+ end
+
+ str_utils_fancy = Module.new do
+ def indent_star(level)
+ "*" * level + self
+ end
+ end
+
+ Module.new do
+ refine String do
+ import_methods str_utils, str_utils_fancy
+ "foo".indent(3).should == " foo"
+ "foo".indent_star(3).should == "***foo"
+ end
+ end
+ end
+
+ it "imports a method defined in the last module if method with same name is defined in multiple modules" do
+ str_utils = Module.new do
+ def indent(level)
+ " " * level + self
+ end
+ end
+
+ str_utils_fancy = Module.new do
+ def indent(level)
+ "*" * level + self
+ end
+ end
+
+ Module.new do
+ refine String do
+ import_methods str_utils, str_utils_fancy
+ "foo".indent(3).should == "***foo"
+ end
+ end
+ end
+
+ it "still imports methods of modules listed before a module that contains method not defined in Ruby" do
+ str_utils = Module.new do
+ def indent(level)
+ " " * level + self
+ end
+ end
+
+ string_refined = Module.new do
+ refine String do
+ -> {
+ import_methods str_utils, Kernel
+ }.should raise_error(ArgumentError)
+ end
+ end
+
+ Module.new do
+ using string_refined
+ "foo".indent(3).should == " foo"
+ end
+ end
+ end
+
+ it "warns if a module includes/prepends some other module" do
+ module1 = Module.new do
+ end
+
+ module2 = Module.new do
+ include module1
+ end
+
+ Module.new do
+ refine String do
+ -> {
+ import_methods module2
+ }.should complain(/warning: #<Module:\w*> has ancestors, but Refinement#import_methods doesn't import their methods/)
+ end
+ end
+
+ Module.new do
+ refine String do
+ -> {
+ import_methods RefinementSpec::ModuleWithAncestors
+ }.should complain(/warning: RefinementSpec::ModuleWithAncestors has ancestors, but Refinement#import_methods doesn't import their methods/)
+ end
+ end
+ end
+
+ it "doesn't import methods from included/prepended modules" do
+ Module.new do
+ refine String do
+ suppress_warning { import_methods RefinementSpec::ModuleWithAncestors }
+ end
+
+ using self
+ -> {
+ "foo".indent(3)
+ }.should raise_error(NoMethodError, /undefined method [`']indent' for ("foo":String|an instance of String)/)
+ end
+ end
+
+ it "doesn't import any methods if one of the arguments is not a module" do
+ str_utils = Module.new do
+ def indent(level)
+ " " * level + self
+ end
+ end
+
+ string_refined = Module.new do
+ refine String do
+ -> {
+ import_methods str_utils, Integer
+ }.should raise_error(TypeError)
+ end
+ end
+
+ Module.new do
+ using string_refined
+ -> {
+ "foo".indent(3)
+ }.should raise_error(NoMethodError)
+ end
+ end
+
+ it "imports methods from multiple modules so that methods see other's module's methods" do
+ str_utils = Module.new do
+ def indent(level)
+ " " * level + self
+ end
+ end
+
+ str_utils_normal = Module.new do
+ def indent_normal(level)
+ self.indent(level)
+ end
+ end
+
+ Module.new do
+ refine String do
+ import_methods str_utils, str_utils_normal
+ end
+
+ using self
+ "foo".indent_normal(3).should == " foo"
+ end
+ end
+
+ it "imports methods from module so that methods can see each other" do
+ str_utils = Module.new do
+ def indent(level)
+ " " * level + self
+ end
+
+ def indent_with_dot(level)
+ self.indent(level) + "."
+ end
+ end
+
+ Module.new do
+ refine String do
+ import_methods str_utils
+ end
+
+ using self
+ "foo".indent_with_dot(3).should == " foo."
+ end
+ end
+
+ it "doesn't import module's class methods" do
+ str_utils = Module.new do
+ def self.indent(level)
+ " " * level + self
+ end
+ end
+
+ Module.new do
+ refine String do
+ import_methods str_utils
+ end
+
+ using self
+ -> {
+ String.indent(3)
+ }.should raise_error(NoMethodError, /undefined method [`']indent' for (String:Class|class String)/)
+ end
+ end
+
+ it "imports module methods with super" do
+ class_to_refine = Class.new do
+ def foo(number)
+ 2 * number
+ end
+ end
+
+ extension = Module.new do
+ def foo(number)
+ super * 2
+ end
+ end
+
+ refinement = Module.new do
+ refine class_to_refine do
+ import_methods extension
+ end
+ end
+
+ Module.new do
+ using refinement
+ class_to_refine.new.foo(2).should == 8
+ end
+ end
+
+ context "when methods are not defined in Ruby code" do
+ it "raises ArgumentError" do
+ Module.new do
+ refine String do
+ -> {
+ import_methods Kernel
+ }.should raise_error(ArgumentError)
+ end
+ end
+ end
+
+ it "raises ArgumentError when importing methods from C extension" do
+ require 'zlib'
+ Module.new do
+ refine String do
+ -> {
+ import_methods Zlib
+ }.should raise_error(ArgumentError, /Can't import method which is not defined with Ruby code: Zlib#*/)
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/refinement/include_spec.rb b/spec/ruby/core/refinement/include_spec.rb
new file mode 100644
index 0000000000..25a53f0ec7
--- /dev/null
+++ b/spec/ruby/core/refinement/include_spec.rb
@@ -0,0 +1,27 @@
+require_relative '../../spec_helper'
+
+describe "Refinement#include" do
+ ruby_version_is "3.1"..."3.2" do
+ it "warns about deprecation" do
+ Module.new do
+ refine String do
+ -> {
+ include Module.new
+ }.should complain(/warning: Refinement#include is deprecated and will be removed in Ruby 3.2/)
+ end
+ end
+ end
+ end
+
+ ruby_version_is "3.2" do
+ it "raises a TypeError" do
+ Module.new do
+ refine String do
+ -> {
+ include Module.new
+ }.should raise_error(TypeError, "Refinement#include has been removed")
+ end
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/refinement/prepend_spec.rb b/spec/ruby/core/refinement/prepend_spec.rb
new file mode 100644
index 0000000000..27b70d392a
--- /dev/null
+++ b/spec/ruby/core/refinement/prepend_spec.rb
@@ -0,0 +1,27 @@
+require_relative '../../spec_helper'
+
+describe "Refinement#prepend" do
+ ruby_version_is "3.1"..."3.2" do
+ it "warns about deprecation" do
+ Module.new do
+ refine String do
+ -> {
+ prepend Module.new
+ }.should complain(/warning: Refinement#prepend is deprecated and will be removed in Ruby 3.2/)
+ end
+ end
+ end
+ end
+
+ ruby_version_is "3.2" do
+ it "raises a TypeError" do
+ Module.new do
+ refine String do
+ -> {
+ prepend Module.new
+ }.should raise_error(TypeError, "Refinement#prepend has been removed")
+ end
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/refinement/refined_class_spec.rb b/spec/ruby/core/refinement/refined_class_spec.rb
new file mode 100644
index 0000000000..00b65d0895
--- /dev/null
+++ b/spec/ruby/core/refinement/refined_class_spec.rb
@@ -0,0 +1,17 @@
+require_relative '../../spec_helper'
+
+describe "Refinement#refined_class" do
+ ruby_version_is "3.2"..."3.3" do
+ it "returns the class refined by the receiver" do
+ refinement_int = nil
+
+ Module.new do
+ refine Integer do
+ refinement_int = self
+ end
+ end
+
+ refinement_int.refined_class.should == Integer
+ end
+ end
+end
diff --git a/spec/ruby/core/regexp/compile_spec.rb b/spec/ruby/core/regexp/compile_spec.rb
index 329cb4f753..c41399cfbb 100644
--- a/spec/ruby/core/regexp/compile_spec.rb
+++ b/spec/ruby/core/regexp/compile_spec.rb
@@ -13,3 +13,7 @@ end
describe "Regexp.compile given a Regexp" do
it_behaves_like :regexp_new_regexp, :compile
end
+
+describe "Regexp.new given a non-String/Regexp" do
+ it_behaves_like :regexp_new_non_string_or_regexp, :compile
+end
diff --git a/spec/ruby/core/regexp/initialize_spec.rb b/spec/ruby/core/regexp/initialize_spec.rb
index 772a233e82..dd57292242 100644
--- a/spec/ruby/core/regexp/initialize_spec.rb
+++ b/spec/ruby/core/regexp/initialize_spec.rb
@@ -2,19 +2,11 @@ require_relative '../../spec_helper'
describe "Regexp#initialize" do
it "is a private method" do
- Regexp.should have_private_method(:initialize)
+ Regexp.should have_private_instance_method(:initialize)
end
- ruby_version_is ""..."3.0" do
- it "raises a SecurityError on a Regexp literal" do
- -> { //.send(:initialize, "") }.should raise_error(SecurityError)
- end
- end
-
- ruby_version_is "3.0" do
- it "raises a FrozenError on a Regexp literal" do
- -> { //.send(:initialize, "") }.should raise_error(FrozenError)
- end
+ it "raises a FrozenError on a Regexp literal" do
+ -> { //.send(:initialize, "") }.should raise_error(FrozenError)
end
it "raises a TypeError on an initialized non-literal Regexp" do
diff --git a/spec/ruby/core/regexp/linear_time_spec.rb b/spec/ruby/core/regexp/linear_time_spec.rb
new file mode 100644
index 0000000000..4dc436264f
--- /dev/null
+++ b/spec/ruby/core/regexp/linear_time_spec.rb
@@ -0,0 +1,25 @@
+require_relative '../../spec_helper'
+
+ruby_version_is "3.2" do
+ describe "Regexp.linear_time?" do
+ it "returns true if matching can be done in linear time" do
+ Regexp.linear_time?(/a/).should == true
+ Regexp.linear_time?('a').should == true
+ end
+
+ it "return false if matching can't be done in linear time" do
+ Regexp.linear_time?(/(a)\1/).should == false
+ Regexp.linear_time?("(a)\\1").should == false
+ end
+
+ it "accepts flags for string argument" do
+ Regexp.linear_time?('a', Regexp::IGNORECASE).should == true
+ end
+
+ it "warns about flags being ignored for regexp arguments" do
+ -> {
+ Regexp.linear_time?(/a/, Regexp::IGNORECASE)
+ }.should complain(/warning: flags ignored/)
+ end
+ end
+end
diff --git a/spec/ruby/core/regexp/new_spec.rb b/spec/ruby/core/regexp/new_spec.rb
index ce662b7a4f..65f612df55 100644
--- a/spec/ruby/core/regexp/new_spec.rb
+++ b/spec/ruby/core/regexp/new_spec.rb
@@ -11,17 +11,9 @@ end
describe "Regexp.new given a Regexp" do
it_behaves_like :regexp_new_regexp, :new
- it_behaves_like :regexp_new_string_binary, :compile
+ it_behaves_like :regexp_new_string_binary, :new
end
-describe "Regexp.new given an Integer" do
- it "raises a TypeError" do
- -> { Regexp.new(1) }.should raise_error(TypeError)
- end
-end
-
-describe "Regexp.new given a Float" do
- it "raises a TypeError" do
- -> { Regexp.new(1.0) }.should raise_error(TypeError)
- end
+describe "Regexp.new given a non-String/Regexp" do
+ it_behaves_like :regexp_new_non_string_or_regexp, :new
end
diff --git a/spec/ruby/core/regexp/shared/new.rb b/spec/ruby/core/regexp/shared/new.rb
index 9cbf89cd8b..7c3fabf612 100644
--- a/spec/ruby/core/regexp/shared/new.rb
+++ b/spec/ruby/core/regexp/shared/new.rb
@@ -24,6 +24,32 @@ describe :regexp_new, shared: true do
end
end
+describe :regexp_new_non_string_or_regexp, shared: true do
+ it "calls #to_str method for non-String/Regexp argument" do
+ obj = Object.new
+ def obj.to_str() "a" end
+
+ Regexp.send(@method, obj).should == /a/
+ end
+
+ it "raises TypeError if there is no #to_str method for non-String/Regexp argument" do
+ obj = Object.new
+ -> { Regexp.send(@method, obj) }.should raise_error(TypeError, "no implicit conversion of Object into String")
+
+ -> { Regexp.send(@method, 1) }.should raise_error(TypeError, "no implicit conversion of Integer into String")
+ -> { Regexp.send(@method, 1.0) }.should raise_error(TypeError, "no implicit conversion of Float into String")
+ -> { Regexp.send(@method, :symbol) }.should raise_error(TypeError, "no implicit conversion of Symbol into String")
+ -> { Regexp.send(@method, []) }.should raise_error(TypeError, "no implicit conversion of Array into String")
+ end
+
+ it "raises TypeError if #to_str returns non-String value" do
+ obj = Object.new
+ def obj.to_str() [] end
+
+ -> { Regexp.send(@method, obj) }.should raise_error(TypeError, /can't convert Object to String/)
+ end
+end
+
describe :regexp_new_string, shared: true do
it "uses the String argument as an unescaped literal to construct a Regexp object" do
Regexp.send(@method, "^hi{2,3}fo.o$").should == /^hi{2,3}fo.o$/
@@ -58,6 +84,15 @@ describe :regexp_new_string, shared: true do
end
end
+ it "sets options from second argument if it is true" do
+ r = Regexp.send(@method, 'Hi', true)
+ (r.options & Regexp::IGNORECASE).should_not == 0
+ (r.options & Regexp::MULTILINE).should == 0
+ not_supported_on :opal do
+ (r.options & Regexp::EXTENDED).should == 0
+ end
+ end
+
it "sets options from second argument if it is one of the Integer option constants" do
r = Regexp.send(@method, 'Hi', Regexp::IGNORECASE)
(r.options & Regexp::IGNORECASE).should_not == 0
@@ -88,57 +123,140 @@ describe :regexp_new_string, shared: true do
(r.options & Regexp::EXTENDED).should_not == 0
end
- it "treats any non-Integer, non-nil, non-false second argument as IGNORECASE" do
- r = Regexp.send(@method, 'Hi', Object.new)
- (r.options & Regexp::IGNORECASE).should_not == 0
- (r.options & Regexp::MULTILINE).should == 0
- not_supported_on :opal do
- (r.options & Regexp::EXTENDED).should == 0
+ 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)
+
+ ScratchPad.recorded.should == nil
end
end
- it "ignores the third argument if it is 'e' or 'euc' (case-insensitive)" do
- -> {
- Regexp.send(@method, 'Hi', nil, 'e').encoding.should == Encoding::US_ASCII
- Regexp.send(@method, 'Hi', nil, 'euc').encoding.should == Encoding::US_ASCII
- Regexp.send(@method, 'Hi', nil, 'E').encoding.should == Encoding::US_ASCII
- Regexp.send(@method, 'Hi', nil, 'EUC').encoding.should == Encoding::US_ASCII
- }.should complain(/encoding option is ignored/)
- end
+ ruby_version_is "3.2" do
+ it "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 "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/)
+ -> {
+ Regexp.send(@method, "Hi", obj)
+ }.should complain(/expected true or false as ignorecase/, {verbose: true})
+
+ ScratchPad.recorded.should == nil
+ end
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/)
+ ruby_version_is ""..."3.2" do
+ it "treats any non-Integer, non-nil, non-false second argument as IGNORECASE" do
+ r = Regexp.send(@method, 'Hi', Object.new)
+ (r.options & Regexp::IGNORECASE).should_not == 0
+ (r.options & Regexp::MULTILINE).should == 0
+ not_supported_on :opal do
+ (r.options & Regexp::EXTENDED).should == 0
+ end
+ end
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
+ 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/)
+ 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"
+ ruby_version_is ""..."3.2" do
+ it "ignores the third argument if it is 'e' or 'euc' (case-insensitive)" do
+ -> {
+ Regexp.send(@method, 'Hi', nil, 'e').encoding.should == Encoding::US_ASCII
+ Regexp.send(@method, 'Hi', nil, 'euc').encoding.should == Encoding::US_ASCII
+ Regexp.send(@method, 'Hi', nil, 'E').encoding.should == Encoding::US_ASCII
+ Regexp.send(@method, 'Hi', nil, 'EUC').encoding.should == Encoding::US_ASCII
+ }.should complain(/encoding option is ignored/)
+ end
+
+ it "ignores the third argument if it is 's' or 'sjis' (case-insensitive)" do
+ -> {
+ Regexp.send(@method, 'Hi', nil, 's').encoding.should == Encoding::US_ASCII
+ Regexp.send(@method, 'Hi', nil, 'sjis').encoding.should == Encoding::US_ASCII
+ Regexp.send(@method, 'Hi', nil, 'S').encoding.should == Encoding::US_ASCII
+ Regexp.send(@method, 'Hi', nil, 'SJIS').encoding.should == Encoding::US_ASCII
+ }.should complain(/encoding option is ignored/)
+ end
- 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
+ it "ignores the third argument if it is 'u' or 'utf8' (case-insensitive)" do
+ -> {
+ Regexp.send(@method, 'Hi', nil, 'u').encoding.should == Encoding::US_ASCII
+ Regexp.send(@method, 'Hi', nil, 'utf8').encoding.should == Encoding::US_ASCII
+ Regexp.send(@method, 'Hi', nil, 'U').encoding.should == Encoding::US_ASCII
+ Regexp.send(@method, 'Hi', nil, 'UTF8').encoding.should == Encoding::US_ASCII
+ }.should complain(/encoding option is ignored/)
+ end
+
+ it "uses US_ASCII encoding if third argument is 'n' or 'none' (case insensitive) and only ascii characters" do
+ Regexp.send(@method, 'Hi', nil, 'n').encoding.should == Encoding::US_ASCII
+ Regexp.send(@method, 'Hi', nil, 'none').encoding.should == Encoding::US_ASCII
+ Regexp.send(@method, 'Hi', nil, 'N').encoding.should == Encoding::US_ASCII
+ Regexp.send(@method, 'Hi', nil, 'NONE').encoding.should == Encoding::US_ASCII
+ end
+
+ it "uses 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
end
describe "with escaped characters" do
@@ -330,6 +448,10 @@ describe :regexp_new_string, shared: true do
Regexp.send(@method, "\056\x42\u3042\x52\076").should == /#{"\x2e\x42\u3042\x52\x3e"}/
end
+ it "accepts a multiple byte character which need not be escaped" do
+ Regexp.send(@method, "\").should == /#{""}/
+ end
+
it "raises a RegexpError if less than four digits are given for \\uHHHH" do
-> { Regexp.send(@method, "\\" + "u304") }.should raise_error(RegexpError)
end
@@ -367,12 +489,12 @@ describe :regexp_new_string, shared: true do
end
it "returns a Regexp with the input String's encoding" do
- str = "\x82\xa0".force_encoding(Encoding::Shift_JIS)
+ str = "\x82\xa0".dup.force_encoding(Encoding::Shift_JIS)
Regexp.send(@method, str).encoding.should == Encoding::Shift_JIS
end
it "returns a Regexp with source String having the input String's encoding" do
- str = "\x82\xa0".force_encoding(Encoding::Shift_JIS)
+ str = "\x82\xa0".dup.force_encoding(Encoding::Shift_JIS)
Regexp.send(@method, str).source.encoding.should == Encoding::Shift_JIS
end
end
@@ -498,8 +620,10 @@ describe :regexp_new_regexp, shared: true do
Regexp.send(@method, /Hi/n).encoding.should == Encoding::US_ASCII
end
- it "sets the encoding to source String's encoding if the Regexp literal has the 'n' option and the source String is not ASCII only" do
- Regexp.send(@method, Regexp.new("\\xff", nil, 'n')).encoding.should == Encoding::BINARY
+ 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 a55adb5bf2..b5ecc35f04 100644
--- a/spec/ruby/core/regexp/shared/quote.rb
+++ b/spec/ruby/core/regexp/shared/quote.rb
@@ -12,19 +12,29 @@ describe :regexp_quote, shared: true do
Regexp.send(@method, :symbol).should == 'symbol'
end
+ it "works with substrings" do
+ str = ".+[]()"[1...-1]
+ Regexp.send(@method, str).should == '\+\[\]\('
+ end
+
+ it "works for broken strings" do
+ Regexp.send(@method, "a.\x85b.".dup.force_encoding("US-ASCII")).should =="a\\.\x85b\\.".dup.force_encoding("US-ASCII")
+ Regexp.send(@method, "a.\x80".dup.force_encoding("UTF-8")).should == "a\\.\x80".dup.force_encoding("UTF-8")
+ end
+
it "sets the encoding of the result to US-ASCII if there are only US-ASCII characters present in the input String" do
- str = "abc".force_encoding("euc-jp")
+ str = "abc".dup.force_encoding("euc-jp")
Regexp.send(@method, str).encoding.should == Encoding::US_ASCII
end
it "sets the encoding of the result to the encoding of the String if any non-US-ASCII characters are present in an input String with valid encoding" do
- str = "ありがとう".force_encoding("utf-8")
+ str = "ありがとう".dup.force_encoding("utf-8")
str.valid_encoding?.should be_true
Regexp.send(@method, str).encoding.should == Encoding::UTF_8
end
it "sets the encoding of the result to BINARY if any non-US-ASCII characters are present in an input String with invalid encoding" do
- str = "\xff".force_encoding "us-ascii"
+ str = "\xff".dup.force_encoding "us-ascii"
str.valid_encoding?.should be_false
Regexp.send(@method, "\xff").encoding.should == Encoding::BINARY
end
diff --git a/spec/ruby/core/regexp/source_spec.rb b/spec/ruby/core/regexp/source_spec.rb
index 709fee49b3..5f253da9ea 100644
--- a/spec/ruby/core/regexp/source_spec.rb
+++ b/spec/ruby/core/regexp/source_spec.rb
@@ -9,8 +9,26 @@ describe "Regexp#source" do
/x(.)xz/.source.should == "x(.)xz"
end
- it "will remove escape characters" do
- /foo\/bar/.source.should == "foo/bar"
+ it "keeps escape sequences as is" do
+ /\x20\+/.source.should == '\x20\+'
+ end
+
+ describe "escaping" do
+ it "keeps escaping of metacharacter" do
+ /\$/.source.should == "\\$"
+ end
+
+ it "keeps escaping of metacharacter used as a terminator" do
+ %r+\++.source.should == "\\+"
+ end
+
+ it "removes escaping of non-metacharacter used as a terminator" do
+ %r@\@@.source.should == "@"
+ end
+
+ it "keeps escaping of non-metacharacter not used as a terminator" do
+ /\@/.source.should == "\\@"
+ end
end
not_supported_on :opal do
diff --git a/spec/ruby/core/regexp/timeout_spec.rb b/spec/ruby/core/regexp/timeout_spec.rb
new file mode 100644
index 0000000000..6fce261814
--- /dev/null
+++ b/spec/ruby/core/regexp/timeout_spec.rb
@@ -0,0 +1,35 @@
+require_relative '../../spec_helper'
+
+ruby_version_is "3.2" do
+ describe "Regexp.timeout" do
+ after :each do
+ Regexp.timeout = nil
+ end
+
+ it "returns global timeout" do
+ Regexp.timeout = 3
+ Regexp.timeout.should == 3
+ end
+
+ it "raises Regexp::TimeoutError after global timeout elapsed" do
+ Regexp.timeout = 0.001
+ Regexp.timeout.should == 0.001
+
+ -> {
+ # A typical ReDoS case
+ /^(a*)*$/ =~ "a" * 1000000 + "x"
+ }.should raise_error(Regexp::TimeoutError, "regexp match timeout")
+ end
+
+ it "raises Regexp::TimeoutError after timeout keyword value elapsed" do
+ Regexp.timeout = 3 # This should be ignored
+ Regexp.timeout.should == 3
+
+ re = Regexp.new("^a*b?a*$", timeout: 0.001)
+
+ -> {
+ re =~ "a" * 1000000 + "x"
+ }.should raise_error(Regexp::TimeoutError, "regexp match timeout")
+ end
+ end
+end
diff --git a/spec/ruby/core/regexp/try_convert_spec.rb b/spec/ruby/core/regexp/try_convert_spec.rb
index be567e2130..e775dbe971 100644
--- a/spec/ruby/core/regexp/try_convert_spec.rb
+++ b/spec/ruby/core/regexp/try_convert_spec.rb
@@ -18,4 +18,10 @@ describe "Regexp.try_convert" do
rex.should_receive(:to_regexp).and_return(/(p(a)t[e]rn)/)
Regexp.try_convert(rex).should == /(p(a)t[e]rn)/
end
+
+ it "raises a TypeError if the object does not return an Regexp from #to_regexp" do
+ obj = mock("regexp")
+ obj.should_receive(:to_regexp).and_return("string")
+ -> { Regexp.try_convert(obj) }.should raise_error(TypeError, "can't convert MockObject to Regexp (MockObject#to_regexp gives String)")
+ end
end
diff --git a/spec/ruby/core/regexp/union_spec.rb b/spec/ruby/core/regexp/union_spec.rb
index 8076836471..ea5a5053f7 100644
--- a/spec/ruby/core/regexp/union_spec.rb
+++ b/spec/ruby/core/regexp/union_spec.rb
@@ -43,6 +43,27 @@ describe "Regexp.union" do
Regexp.union("\u00A9".encode("ISO-8859-1"), "a".encode("UTF-8")).encoding.should == Encoding::ISO_8859_1
end
+ it "returns ASCII-8BIT if the regexp encodings are ASCII-8BIT and at least one has non-ASCII characters" do
+ us_ascii_implicit, us_ascii_explicit, binary = /abc/, /[\x00-\x7f]/n, /[\x80-\xBF]/n
+ us_ascii_implicit.encoding.should == Encoding::US_ASCII
+ us_ascii_explicit.encoding.should == Encoding::US_ASCII
+ binary.encoding.should == Encoding::BINARY
+
+ Regexp.union(us_ascii_implicit, us_ascii_explicit, binary).encoding.should == Encoding::BINARY
+ Regexp.union(us_ascii_implicit, binary, us_ascii_explicit).encoding.should == Encoding::BINARY
+ Regexp.union(us_ascii_explicit, us_ascii_implicit, binary).encoding.should == Encoding::BINARY
+ Regexp.union(us_ascii_explicit, binary, us_ascii_implicit).encoding.should == Encoding::BINARY
+ Regexp.union(binary, us_ascii_implicit, us_ascii_explicit).encoding.should == Encoding::BINARY
+ Regexp.union(binary, us_ascii_explicit, us_ascii_implicit).encoding.should == Encoding::BINARY
+ end
+
+ it "return US-ASCII if all patterns are ASCII-only" do
+ Regexp.union(/abc/e, /def/e).encoding.should == Encoding::US_ASCII
+ Regexp.union(/abc/n, /def/n).encoding.should == Encoding::US_ASCII
+ Regexp.union(/abc/s, /def/s).encoding.should == Encoding::US_ASCII
+ Regexp.union(/abc/u, /def/u).encoding.should == Encoding::US_ASCII
+ end
+
it "returns a Regexp with UTF-8 if one part is UTF-8" do
Regexp.union(/probl[éeè]me/i, /help/i).encoding.should == Encoding::UTF_8
end
@@ -54,83 +75,83 @@ describe "Regexp.union" do
it "raises ArgumentError if the arguments include conflicting ASCII-incompatible Strings" do
-> {
Regexp.union("a".encode("UTF-16LE"), "b".encode("UTF-16BE"))
- }.should raise_error(ArgumentError)
+ }.should raise_error(ArgumentError, 'incompatible encodings: UTF-16LE and UTF-16BE')
end
it "raises ArgumentError if the arguments include conflicting ASCII-incompatible Regexps" do
-> {
Regexp.union(Regexp.new("a".encode("UTF-16LE")),
Regexp.new("b".encode("UTF-16BE")))
- }.should raise_error(ArgumentError)
+ }.should raise_error(ArgumentError, 'incompatible encodings: UTF-16LE and UTF-16BE')
end
it "raises ArgumentError if the arguments include conflicting fixed encoding Regexps" do
-> {
Regexp.union(Regexp.new("a".encode("UTF-8"), Regexp::FIXEDENCODING),
Regexp.new("b".encode("US-ASCII"), Regexp::FIXEDENCODING))
- }.should raise_error(ArgumentError)
+ }.should raise_error(ArgumentError, 'incompatible encodings: UTF-8 and US-ASCII')
end
it "raises ArgumentError if the arguments include a fixed encoding Regexp and a String containing non-ASCII-compatible characters in a different encoding" do
-> {
Regexp.union(Regexp.new("a".encode("UTF-8"), Regexp::FIXEDENCODING),
"\u00A9".encode("ISO-8859-1"))
- }.should raise_error(ArgumentError)
+ }.should raise_error(ArgumentError, 'incompatible encodings: UTF-8 and ISO-8859-1')
end
it "raises ArgumentError if the arguments include a String containing non-ASCII-compatible characters and a fixed encoding Regexp in a different encoding" do
-> {
Regexp.union("\u00A9".encode("ISO-8859-1"),
Regexp.new("a".encode("UTF-8"), Regexp::FIXEDENCODING))
- }.should raise_error(ArgumentError)
+ }.should raise_error(ArgumentError, 'incompatible encodings: ISO-8859-1 and UTF-8')
end
it "raises ArgumentError if the arguments include an ASCII-incompatible String and an ASCII-only String" do
-> {
Regexp.union("a".encode("UTF-16LE"), "b".encode("UTF-8"))
- }.should raise_error(ArgumentError)
+ }.should raise_error(ArgumentError, /ASCII incompatible encoding: UTF-16LE|incompatible encodings: UTF-16LE and US-ASCII/)
end
it "raises ArgumentError if the arguments include an ASCII-incompatible Regexp and an ASCII-only String" do
-> {
Regexp.union(Regexp.new("a".encode("UTF-16LE")), "b".encode("UTF-8"))
- }.should raise_error(ArgumentError)
+ }.should raise_error(ArgumentError, /ASCII incompatible encoding: UTF-16LE|incompatible encodings: UTF-16LE and US-ASCII/)
end
it "raises ArgumentError if the arguments include an ASCII-incompatible String and an ASCII-only Regexp" do
-> {
Regexp.union("a".encode("UTF-16LE"), Regexp.new("b".encode("UTF-8")))
- }.should raise_error(ArgumentError)
+ }.should raise_error(ArgumentError, /ASCII incompatible encoding: UTF-16LE|incompatible encodings: UTF-16LE and US-ASCII/)
end
it "raises ArgumentError if the arguments include an ASCII-incompatible Regexp and an ASCII-only Regexp" do
-> {
Regexp.union(Regexp.new("a".encode("UTF-16LE")), Regexp.new("b".encode("UTF-8")))
- }.should raise_error(ArgumentError)
+ }.should raise_error(ArgumentError, /ASCII incompatible encoding: UTF-16LE|incompatible encodings: UTF-16LE and US-ASCII/)
end
it "raises ArgumentError if the arguments include an ASCII-incompatible String and a String containing non-ASCII-compatible characters in a different encoding" do
-> {
Regexp.union("a".encode("UTF-16LE"), "\u00A9".encode("ISO-8859-1"))
- }.should raise_error(ArgumentError)
+ }.should raise_error(ArgumentError, 'incompatible encodings: UTF-16LE and ISO-8859-1')
end
it "raises ArgumentError if the arguments include an ASCII-incompatible Regexp and a String containing non-ASCII-compatible characters in a different encoding" do
-> {
Regexp.union(Regexp.new("a".encode("UTF-16LE")), "\u00A9".encode("ISO-8859-1"))
- }.should raise_error(ArgumentError)
+ }.should raise_error(ArgumentError, 'incompatible encodings: UTF-16LE and ISO-8859-1')
end
it "raises ArgumentError if the arguments include an ASCII-incompatible String and a Regexp containing non-ASCII-compatible characters in a different encoding" do
-> {
Regexp.union("a".encode("UTF-16LE"), Regexp.new("\u00A9".encode("ISO-8859-1")))
- }.should raise_error(ArgumentError)
+ }.should raise_error(ArgumentError, 'incompatible encodings: UTF-16LE and ISO-8859-1')
end
it "raises ArgumentError if the arguments include an ASCII-incompatible Regexp and a Regexp containing non-ASCII-compatible characters in a different encoding" do
-> {
Regexp.union(Regexp.new("a".encode("UTF-16LE")), Regexp.new("\u00A9".encode("ISO-8859-1")))
- }.should raise_error(ArgumentError)
+ }.should raise_error(ArgumentError, 'incompatible encodings: UTF-16LE and ISO-8859-1')
end
it "uses to_str to convert arguments (if not Regexp)" do
@@ -154,6 +175,8 @@ describe "Regexp.union" do
not_supported_on :opal do
Regexp.union([/dogs/, /cats/i]).should == /(?-mix:dogs)|(?i-mx:cats)/
end
- ->{Regexp.union(["skiing", "sledding"], [/dogs/, /cats/i])}.should raise_error(TypeError)
+ -> {
+ Regexp.union(["skiing", "sledding"], [/dogs/, /cats/i])
+ }.should raise_error(TypeError, 'no implicit conversion of Array into String')
end
end
diff --git a/spec/ruby/core/signal/signame_spec.rb b/spec/ruby/core/signal/signame_spec.rb
index b66de9fc85..adfe895d97 100644
--- a/spec/ruby/core/signal/signame_spec.rb
+++ b/spec/ruby/core/signal/signame_spec.rb
@@ -9,10 +9,22 @@ describe "Signal.signame" do
Signal.signame(-1).should == nil
end
+ it "calls #to_int on an object to convert to an Integer" do
+ obj = mock('signal')
+ obj.should_receive(:to_int).and_return(0)
+ Signal.signame(obj).should == "EXIT"
+ end
+
it "raises a TypeError when the passed argument can't be coerced to Integer" do
-> { Signal.signame("hello") }.should raise_error(TypeError)
end
+ it "raises a TypeError when the passed argument responds to #to_int but does not return an Integer" do
+ obj = mock('signal')
+ obj.should_receive(:to_int).and_return('not an int')
+ -> { Signal.signame(obj) }.should raise_error(TypeError)
+ end
+
platform_is_not :windows do
it "the original should take precedence over alias when looked up by number" do
Signal.signame(Signal.list["ABRT"]).should == "ABRT"
diff --git a/spec/ruby/core/signal/trap_spec.rb b/spec/ruby/core/signal/trap_spec.rb
index 3c78922694..6d654a99be 100644
--- a/spec/ruby/core/signal/trap_spec.rb
+++ b/spec/ruby/core/signal/trap_spec.rb
@@ -221,6 +221,37 @@ describe "Signal.trap" do
Signal.trap(:HUP, @saved_trap).should equal(@proc)
end
+ it "calls #to_str on an object to convert to a String" do
+ obj = mock("signal")
+ obj.should_receive(:to_str).exactly(2).times.and_return("HUP")
+ Signal.trap obj, @proc
+ Signal.trap(obj, @saved_trap).should equal(@proc)
+ end
+
+ it "accepts Integer values" do
+ hup = Signal.list["HUP"]
+ Signal.trap hup, @proc
+ Signal.trap(hup, @saved_trap).should equal(@proc)
+ end
+
+ it "does not call #to_int on an object to convert to an Integer" do
+ obj = mock("signal")
+ obj.should_not_receive(:to_int)
+ -> { Signal.trap obj, @proc }.should raise_error(ArgumentError, /bad signal type/)
+ end
+
+ it "raises ArgumentError when passed unknown signal" do
+ -> { Signal.trap(300) { } }.should raise_error(ArgumentError, "invalid signal number (300)")
+ -> { Signal.trap("USR10") { } }.should raise_error(ArgumentError, /\Aunsupported signal [`']SIGUSR10'\z/)
+ -> { Signal.trap("SIGUSR10") { } }.should raise_error(ArgumentError, /\Aunsupported signal [`']SIGUSR10'\z/)
+ end
+
+ it "raises ArgumentError when passed signal is not Integer, String or Symbol" do
+ -> { Signal.trap(nil) { } }.should raise_error(ArgumentError, "bad signal type NilClass")
+ -> { Signal.trap(100.0) { } }.should raise_error(ArgumentError, "bad signal type Float")
+ -> { Signal.trap(Rational(100)) { } }.should raise_error(ArgumentError, "bad signal type Rational")
+ end
+
# See man 2 signal
%w[KILL STOP].each do |signal|
it "raises ArgumentError or Errno::EINVAL for SIG#{signal}" do
@@ -233,6 +264,14 @@ describe "Signal.trap" do
end
end
+ %w[SEGV BUS ILL FPE VTALRM].each do |signal|
+ it "raises ArgumentError for SIG#{signal} which is reserved by Ruby" do
+ -> {
+ Signal.trap(signal, -> {})
+ }.should raise_error(ArgumentError, "can't trap reserved signal: SIG#{signal}")
+ end
+ end
+
it "allows to register a handler for all known signals, except reserved signals for which it raises ArgumentError" do
out = ruby_exe(fixture(__FILE__, "trap_all.rb"), args: "2>&1")
out.should == "OK\n"
@@ -254,12 +293,10 @@ describe "Signal.trap" do
r.close
loop { w.write("a"*1024) }
RUBY
- out = ruby_exe(code, exit_status: nil)
+ out = ruby_exe(code, exit_status: :SIGPIPE)
status = $?
out.should == "nil\n"
status.should.signaled?
- status.termsig.should be_kind_of(Integer)
- Signal.signame(status.termsig).should == "PIPE"
end
end
diff --git a/spec/ruby/core/sizedqueue/append_spec.rb b/spec/ruby/core/sizedqueue/append_spec.rb
index ca79068930..6fffe2f272 100644
--- a/spec/ruby/core/sizedqueue/append_spec.rb
+++ b/spec/ruby/core/sizedqueue/append_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
require_relative '../../shared/queue/enque'
require_relative '../../shared/sizedqueue/enque'
+require_relative '../../shared/types/rb_num2dbl_fails'
describe "SizedQueue#<<" do
it_behaves_like :queue_enq, :<<, -> { SizedQueue.new(10) }
@@ -9,3 +10,9 @@ end
describe "SizedQueue#<<" do
it_behaves_like :sizedqueue_enq, :<<, -> n { SizedQueue.new(n) }
end
+
+describe "SizedQueue operations with timeout" do
+ ruby_version_is "3.2" do
+ it_behaves_like :rb_num2dbl_fails, nil, -> v { q = SizedQueue.new(1); q.send(:<<, 1, timeout: v) }
+ end
+end
diff --git a/spec/ruby/core/sizedqueue/deq_spec.rb b/spec/ruby/core/sizedqueue/deq_spec.rb
index 5e1bd9f746..985d654bb3 100644
--- a/spec/ruby/core/sizedqueue/deq_spec.rb
+++ b/spec/ruby/core/sizedqueue/deq_spec.rb
@@ -1,6 +1,13 @@
require_relative '../../spec_helper'
require_relative '../../shared/queue/deque'
+require_relative '../../shared/types/rb_num2dbl_fails'
describe "SizedQueue#deq" do
it_behaves_like :queue_deq, :deq, -> { SizedQueue.new(10) }
end
+
+describe "SizedQueue operations with timeout" do
+ ruby_version_is "3.2" do
+ it_behaves_like :rb_num2dbl_fails, nil, -> v { q = SizedQueue.new(10); q.push(1); q.deq(timeout: v) }
+ end
+end
diff --git a/spec/ruby/core/sizedqueue/enq_spec.rb b/spec/ruby/core/sizedqueue/enq_spec.rb
index 3821afac95..619373e46b 100644
--- a/spec/ruby/core/sizedqueue/enq_spec.rb
+++ b/spec/ruby/core/sizedqueue/enq_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
require_relative '../../shared/queue/enque'
require_relative '../../shared/sizedqueue/enque'
+require_relative '../../shared/types/rb_num2dbl_fails'
describe "SizedQueue#enq" do
it_behaves_like :queue_enq, :enq, -> { SizedQueue.new(10) }
@@ -9,3 +10,9 @@ end
describe "SizedQueue#enq" do
it_behaves_like :sizedqueue_enq, :enq, -> n { SizedQueue.new(n) }
end
+
+describe "SizedQueue operations with timeout" do
+ ruby_version_is "3.2" do
+ it_behaves_like :rb_num2dbl_fails, nil, -> v { q = SizedQueue.new(1); q.enq(1, timeout: v) }
+ end
+end
diff --git a/spec/ruby/core/sizedqueue/pop_spec.rb b/spec/ruby/core/sizedqueue/pop_spec.rb
index a0cf6f509c..5e7cfea8fb 100644
--- a/spec/ruby/core/sizedqueue/pop_spec.rb
+++ b/spec/ruby/core/sizedqueue/pop_spec.rb
@@ -1,6 +1,13 @@
require_relative '../../spec_helper'
require_relative '../../shared/queue/deque'
+require_relative '../../shared/types/rb_num2dbl_fails'
describe "SizedQueue#pop" do
it_behaves_like :queue_deq, :pop, -> { SizedQueue.new(10) }
end
+
+describe "SizedQueue operations with timeout" do
+ ruby_version_is "3.2" do
+ it_behaves_like :rb_num2dbl_fails, nil, -> v { q = SizedQueue.new(10); q.push(1); q.pop(timeout: v) }
+ end
+end
diff --git a/spec/ruby/core/sizedqueue/push_spec.rb b/spec/ruby/core/sizedqueue/push_spec.rb
index bba9be9e3f..ce61e89b53 100644
--- a/spec/ruby/core/sizedqueue/push_spec.rb
+++ b/spec/ruby/core/sizedqueue/push_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
require_relative '../../shared/queue/enque'
require_relative '../../shared/sizedqueue/enque'
+require_relative '../../shared/types/rb_num2dbl_fails'
describe "SizedQueue#push" do
it_behaves_like :queue_enq, :push, -> { SizedQueue.new(10) }
@@ -9,3 +10,9 @@ end
describe "SizedQueue#push" do
it_behaves_like :sizedqueue_enq, :push, -> n { SizedQueue.new(n) }
end
+
+describe "SizedQueue operations with timeout" do
+ ruby_version_is "3.2" do
+ it_behaves_like :rb_num2dbl_fails, nil, -> v { q = SizedQueue.new(1); q.push(1, timeout: v) }
+ end
+end
diff --git a/spec/ruby/core/sizedqueue/shift_spec.rb b/spec/ruby/core/sizedqueue/shift_spec.rb
index 5138e68258..3220801f3a 100644
--- a/spec/ruby/core/sizedqueue/shift_spec.rb
+++ b/spec/ruby/core/sizedqueue/shift_spec.rb
@@ -1,6 +1,13 @@
require_relative '../../spec_helper'
require_relative '../../shared/queue/deque'
+require_relative '../../shared/types/rb_num2dbl_fails'
describe "SizedQueue#shift" do
it_behaves_like :queue_deq, :shift, -> { SizedQueue.new(10) }
end
+
+describe "SizedQueue operations with timeout" do
+ ruby_version_is "3.2" do
+ it_behaves_like :rb_num2dbl_fails, nil, -> v { q = SizedQueue.new(10); q.push(1); q.shift(timeout: v) }
+ end
+end
diff --git a/spec/ruby/core/string/append_spec.rb b/spec/ruby/core/string/append_spec.rb
index 1e1667f617..8497ce8262 100644
--- a/spec/ruby/core/string/append_spec.rb
+++ b/spec/ruby/core/string/append_spec.rb
@@ -5,4 +5,10 @@ require_relative 'shared/concat'
describe "String#<<" do
it_behaves_like :string_concat, :<<
it_behaves_like :string_concat_encoding, :<<
+ it_behaves_like :string_concat_type_coercion, :<<
+
+ it "raises an ArgumentError when given the incorrect number of arguments" do
+ -> { "hello".send(:<<) }.should raise_error(ArgumentError)
+ -> { "hello".send(:<<, "one", "two") }.should raise_error(ArgumentError)
+ end
end
diff --git a/spec/ruby/core/string/ascii_only_spec.rb b/spec/ruby/core/string/ascii_only_spec.rb
index c7e02fd874..88a0559cfd 100644
--- a/spec/ruby/core/string/ascii_only_spec.rb
+++ b/spec/ruby/core/string/ascii_only_spec.rb
@@ -7,12 +7,12 @@ describe "String#ascii_only?" do
it "returns true if the encoding is UTF-8" do
[ ["hello", true],
["hello".encode('UTF-8'), true],
- ["hello".force_encoding('UTF-8'), true],
+ ["hello".dup.force_encoding('UTF-8'), true],
].should be_computed_by(:ascii_only?)
end
it "returns true if the encoding is US-ASCII" do
- "hello".force_encoding(Encoding::US_ASCII).ascii_only?.should be_true
+ "hello".dup.force_encoding(Encoding::US_ASCII).ascii_only?.should be_true
"hello".encode(Encoding::US_ASCII).ascii_only?.should be_true
end
@@ -34,13 +34,13 @@ describe "String#ascii_only?" do
[ ["\u{6666}", false],
["hello, \u{6666}", false],
["\u{6666}".encode('UTF-8'), false],
- ["\u{6666}".force_encoding('UTF-8'), false],
+ ["\u{6666}".dup.force_encoding('UTF-8'), false],
].should be_computed_by(:ascii_only?)
end
it "returns false if the encoding is US-ASCII" do
- [ ["\u{6666}".force_encoding(Encoding::US_ASCII), false],
- ["hello, \u{6666}".force_encoding(Encoding::US_ASCII), false],
+ [ ["\u{6666}".dup.force_encoding(Encoding::US_ASCII), false],
+ ["hello, \u{6666}".dup.force_encoding(Encoding::US_ASCII), false],
].should be_computed_by(:ascii_only?)
end
end
@@ -51,17 +51,16 @@ describe "String#ascii_only?" do
end
it "returns false for the empty String with a non-ASCII-compatible encoding" do
- "".force_encoding('UTF-16LE').ascii_only?.should be_false
+ "".dup.force_encoding('UTF-16LE').ascii_only?.should be_false
"".encode('UTF-16BE').ascii_only?.should be_false
end
it "returns false for a non-empty String with non-ASCII-compatible encoding" do
- "\x78\x00".force_encoding("UTF-16LE").ascii_only?.should be_false
+ "\x78\x00".dup.force_encoding("UTF-16LE").ascii_only?.should be_false
end
it "returns false when interpolating non ascii strings" do
- base = "EU currency is"
- base.force_encoding(Encoding::US_ASCII)
+ base = "EU currency is".dup.force_encoding(Encoding::US_ASCII)
euro = "\u20AC"
interp = "#{base} #{euro}"
euro.ascii_only?.should be_false
@@ -70,14 +69,14 @@ describe "String#ascii_only?" do
end
it "returns false after appending non ASCII characters to an empty String" do
- ("" << "λ").ascii_only?.should be_false
+ ("".dup << "λ").ascii_only?.should be_false
end
it "returns false when concatenating an ASCII and non-ASCII String" do
- "".concat("λ").ascii_only?.should be_false
+ "".dup.concat("λ").ascii_only?.should be_false
end
it "returns false when replacing an ASCII String with a non-ASCII String" do
- "".replace("λ").ascii_only?.should be_false
+ "".dup.replace("λ").ascii_only?.should be_false
end
end
diff --git a/spec/ruby/core/string/b_spec.rb b/spec/ruby/core/string/b_spec.rb
index b2e3d326ba..4b1fafff11 100644
--- a/spec/ruby/core/string/b_spec.rb
+++ b/spec/ruby/core/string/b_spec.rb
@@ -1,4 +1,5 @@
# -*- encoding: utf-8 -*-
+# frozen_string_literal: false
require_relative '../../spec_helper'
describe "String#b" do
@@ -12,13 +13,4 @@ describe "String#b" do
str.b.should_not equal(str)
str.should == "こんちには"
end
-
- ruby_version_is ''...'2.7' do
- it "copies own tainted/untrusted status to the returning value" do
- utf_8 = "こんちには".taint.untrust
- ret = utf_8.b
- ret.tainted?.should be_true
- ret.untrusted?.should be_true
- end
- end
end
diff --git a/spec/ruby/core/string/byteindex_spec.rb b/spec/ruby/core/string/byteindex_spec.rb
new file mode 100644
index 0000000000..47c7be1029
--- /dev/null
+++ b/spec/ruby/core/string/byteindex_spec.rb
@@ -0,0 +1,304 @@
+# -*- encoding: utf-8 -*-
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative 'shared/byte_index_common.rb'
+
+describe "String#byteindex" do
+ ruby_version_is "3.2" do
+ it "calls #to_str to convert the first argument" do
+ char = mock("string index char")
+ char.should_receive(:to_str).and_return("b")
+ "abc".byteindex(char).should == 1
+ end
+
+ it "calls #to_int to convert the second argument" do
+ offset = mock("string index offset")
+ offset.should_receive(:to_int).and_return(1)
+ "abc".byteindex("c", offset).should == 2
+ end
+
+ it "does not raise IndexError when byte offset is correct or on string boundary" do
+ "わ".byteindex("").should == 0
+ "わ".byteindex("", 0).should == 0
+ "わ".byteindex("", 3).should == 3
+ end
+
+ it_behaves_like :byte_index_common, :byteindex
+ end
+end
+
+describe "String#byteindex with String" do
+ ruby_version_is "3.2" do
+ it "behaves the same as String#byteindex(char) for one-character strings" do
+ "blablabla hello cruel world...!".split("").uniq.each do |str|
+ chr = str[0]
+ str.byteindex(str).should == str.byteindex(chr)
+
+ 0.upto(str.size + 1) do |start|
+ str.byteindex(str, start).should == str.byteindex(chr, start)
+ end
+
+ (-str.size - 1).upto(-1) do |start|
+ str.byteindex(str, start).should == str.byteindex(chr, start)
+ end
+ end
+ end
+
+ it "returns the byteindex of the first occurrence of the given substring" do
+ "blablabla".byteindex("").should == 0
+ "blablabla".byteindex("b").should == 0
+ "blablabla".byteindex("bla").should == 0
+ "blablabla".byteindex("blabla").should == 0
+ "blablabla".byteindex("blablabla").should == 0
+
+ "blablabla".byteindex("l").should == 1
+ "blablabla".byteindex("la").should == 1
+ "blablabla".byteindex("labla").should == 1
+ "blablabla".byteindex("lablabla").should == 1
+
+ "blablabla".byteindex("a").should == 2
+ "blablabla".byteindex("abla").should == 2
+ "blablabla".byteindex("ablabla").should == 2
+ end
+
+ it "treats the offset as a byteindex" do
+ "aaaaa".byteindex("a", 0).should == 0
+ "aaaaa".byteindex("a", 2).should == 2
+ "aaaaa".byteindex("a", 4).should == 4
+ end
+
+ it "ignores string subclasses" do
+ "blablabla".byteindex(StringSpecs::MyString.new("bla")).should == 0
+ StringSpecs::MyString.new("blablabla").byteindex("bla").should == 0
+ StringSpecs::MyString.new("blablabla").byteindex(StringSpecs::MyString.new("bla")).should == 0
+ end
+
+ it "starts the search at the given offset" do
+ "blablabla".byteindex("bl", 0).should == 0
+ "blablabla".byteindex("bl", 1).should == 3
+ "blablabla".byteindex("bl", 2).should == 3
+ "blablabla".byteindex("bl", 3).should == 3
+
+ "blablabla".byteindex("bla", 0).should == 0
+ "blablabla".byteindex("bla", 1).should == 3
+ "blablabla".byteindex("bla", 2).should == 3
+ "blablabla".byteindex("bla", 3).should == 3
+
+ "blablabla".byteindex("blab", 0).should == 0
+ "blablabla".byteindex("blab", 1).should == 3
+ "blablabla".byteindex("blab", 2).should == 3
+ "blablabla".byteindex("blab", 3).should == 3
+
+ "blablabla".byteindex("la", 1).should == 1
+ "blablabla".byteindex("la", 2).should == 4
+ "blablabla".byteindex("la", 3).should == 4
+ "blablabla".byteindex("la", 4).should == 4
+
+ "blablabla".byteindex("lab", 1).should == 1
+ "blablabla".byteindex("lab", 2).should == 4
+ "blablabla".byteindex("lab", 3).should == 4
+ "blablabla".byteindex("lab", 4).should == 4
+
+ "blablabla".byteindex("ab", 2).should == 2
+ "blablabla".byteindex("ab", 3).should == 5
+ "blablabla".byteindex("ab", 4).should == 5
+ "blablabla".byteindex("ab", 5).should == 5
+
+ "blablabla".byteindex("", 0).should == 0
+ "blablabla".byteindex("", 1).should == 1
+ "blablabla".byteindex("", 2).should == 2
+ "blablabla".byteindex("", 7).should == 7
+ "blablabla".byteindex("", 8).should == 8
+ "blablabla".byteindex("", 9).should == 9
+ end
+
+ it "starts the search at offset + self.length if offset is negative" do
+ str = "blablabla"
+
+ ["bl", "bla", "blab", "la", "lab", "ab", ""].each do |needle|
+ (-str.length .. -1).each do |offset|
+ str.byteindex(needle, offset).should ==
+ str.byteindex(needle, offset + str.length)
+ end
+ end
+ end
+
+ it "returns nil if the substring isn't found" do
+ "blablabla".byteindex("B").should == nil
+ "blablabla".byteindex("z").should == nil
+ "blablabla".byteindex("BLA").should == nil
+ "blablabla".byteindex("blablablabla").should == nil
+ "blablabla".byteindex("", 10).should == nil
+
+ "hello".byteindex("he", 1).should == nil
+ "hello".byteindex("he", 2).should == nil
+ "I’ve got a multibyte character.\n".byteindex("\n\n").should == nil
+ end
+
+ it "returns the character byteindex of a multibyte character" do
+ "ありがとう".byteindex("が").should == 6
+ end
+
+ it "returns the character byteindex after offset" do
+ "われわれ".byteindex("わ", 3).should == 6
+ "ありがとうありがとう".byteindex("が", 9).should == 21
+ end
+
+ it "returns the character byteindex after a partial first match" do
+ "</</h".byteindex("</h").should == 2
+ end
+
+ it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
+ char = "れ".encode Encoding::EUC_JP
+ -> do
+ "あれ".byteindex(char)
+ end.should raise_error(Encoding::CompatibilityError)
+ end
+
+ it "handles a substring in a superset encoding" do
+ 'abc'.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
+ end
+end
+
+describe "String#byteindex with Regexp" do
+ ruby_version_is "3.2" do
+ it "behaves the same as String#byteindex(string) for escaped string regexps" do
+ ["blablabla", "hello cruel world...!"].each do |str|
+ ["", "b", "bla", "lab", "o c", "d."].each do |needle|
+ regexp = Regexp.new(Regexp.escape(needle))
+ str.byteindex(regexp).should == str.byteindex(needle)
+
+ 0.upto(str.size + 1) do |start|
+ str.byteindex(regexp, start).should == str.byteindex(needle, start)
+ end
+
+ (-str.size - 1).upto(-1) do |start|
+ str.byteindex(regexp, start).should == str.byteindex(needle, start)
+ end
+ end
+ end
+ end
+
+ it "returns the byteindex of the first match of regexp" do
+ "blablabla".byteindex(/bla/).should == 0
+ "blablabla".byteindex(/BLA/i).should == 0
+
+ "blablabla".byteindex(/.{0}/).should == 0
+ "blablabla".byteindex(/.{6}/).should == 0
+ "blablabla".byteindex(/.{9}/).should == 0
+
+ "blablabla".byteindex(/.*/).should == 0
+ "blablabla".byteindex(/.+/).should == 0
+
+ "blablabla".byteindex(/lab|b/).should == 0
+
+ not_supported_on :opal do
+ "blablabla".byteindex(/\A/).should == 0
+ "blablabla".byteindex(/\Z/).should == 9
+ "blablabla".byteindex(/\z/).should == 9
+ "blablabla\n".byteindex(/\Z/).should == 9
+ "blablabla\n".byteindex(/\z/).should == 10
+ end
+
+ "blablabla".byteindex(/^/).should == 0
+ "\nblablabla".byteindex(/^/).should == 0
+ "b\nablabla".byteindex(/$/).should == 1
+ "bl\nablabla".byteindex(/$/).should == 2
+
+ "blablabla".byteindex(/.l./).should == 0
+ end
+
+ it "starts the search at the given offset" do
+ "blablabla".byteindex(/.{0}/, 5).should == 5
+ "blablabla".byteindex(/.{1}/, 5).should == 5
+ "blablabla".byteindex(/.{2}/, 5).should == 5
+ "blablabla".byteindex(/.{3}/, 5).should == 5
+ "blablabla".byteindex(/.{4}/, 5).should == 5
+
+ "blablabla".byteindex(/.{0}/, 3).should == 3
+ "blablabla".byteindex(/.{1}/, 3).should == 3
+ "blablabla".byteindex(/.{2}/, 3).should == 3
+ "blablabla".byteindex(/.{5}/, 3).should == 3
+ "blablabla".byteindex(/.{6}/, 3).should == 3
+
+ "blablabla".byteindex(/.l./, 0).should == 0
+ "blablabla".byteindex(/.l./, 1).should == 3
+ "blablabla".byteindex(/.l./, 2).should == 3
+ "blablabla".byteindex(/.l./, 3).should == 3
+
+ "xblaxbla".byteindex(/x./, 0).should == 0
+ "xblaxbla".byteindex(/x./, 1).should == 4
+ "xblaxbla".byteindex(/x./, 2).should == 4
+
+ not_supported_on :opal do
+ "blablabla\n".byteindex(/\Z/, 9).should == 9
+ end
+ end
+
+ it "starts the search at offset + self.length if offset is negative" do
+ str = "blablabla"
+
+ ["bl", "bla", "blab", "la", "lab", "ab", ""].each do |needle|
+ (-str.length .. -1).each do |offset|
+ str.byteindex(needle, offset).should ==
+ str.byteindex(needle, offset + str.length)
+ end
+ end
+ end
+
+ it "returns nil if the substring isn't found" do
+ "blablabla".byteindex(/BLA/).should == nil
+
+ "blablabla".byteindex(/.{10}/).should == nil
+ "blaxbla".byteindex(/.x/, 3).should == nil
+ "blaxbla".byteindex(/..x/, 2).should == nil
+ end
+
+ it "returns nil if the Regexp matches the empty string and the offset is out of range" do
+ "ruby".byteindex(//, 12).should be_nil
+ end
+
+ it "supports \\G which matches at the given start offset" do
+ "helloYOU.".byteindex(/\GYOU/, 5).should == 5
+ "helloYOU.".byteindex(/\GYOU/).should == nil
+
+ re = /\G.+YOU/
+ # The # marks where \G will match.
+ [
+ ["#hi!YOUall.", 0],
+ ["h#i!YOUall.", 1],
+ ["hi#!YOUall.", 2],
+ ["hi!#YOUall.", nil]
+ ].each do |spec|
+
+ start = spec[0].byteindex("#")
+ str = spec[0].delete("#")
+
+ str.byteindex(re, start).should == spec[1]
+ end
+ end
+
+ it "converts start_offset to an integer via to_int" do
+ obj = mock('1')
+ obj.should_receive(:to_int).and_return(1)
+ "RWOARW".byteindex(/R./, obj).should == 4
+ end
+
+ it "returns the character byteindex of a multibyte character" do
+ "ありがとう".byteindex(/が/).should == 6
+ end
+
+ it "returns the character byteindex after offset" do
+ "われわれ".byteindex(/わ/, 3).should == 6
+ end
+
+ it "treats the offset as a byteindex" do
+ "われわわれ".byteindex(/わ/, 6).should == 6
+ end
+ end
+end
diff --git a/spec/ruby/core/string/byterindex_spec.rb b/spec/ruby/core/string/byterindex_spec.rb
new file mode 100644
index 0000000000..150f709b90
--- /dev/null
+++ b/spec/ruby/core/string/byterindex_spec.rb
@@ -0,0 +1,359 @@
+# -*- encoding: utf-8 -*-
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require_relative 'shared/byte_index_common.rb'
+
+describe "String#byterindex with object" do
+ ruby_version_is "3.2" do
+ it "tries to convert obj to a string via to_str" do
+ obj = mock('lo')
+ def obj.to_str() "lo" end
+ "hello".byterindex(obj).should == "hello".byterindex("lo")
+
+ obj = mock('o')
+ def obj.respond_to?(arg, *) true end
+ def obj.method_missing(*args) "o" end
+ "hello".byterindex(obj).should == "hello".byterindex("o")
+ end
+
+ it "calls #to_int to convert the second argument" do
+ offset = mock("string index offset")
+ offset.should_receive(:to_int).and_return(3)
+ "abc".byterindex("c", offset).should == 2
+ end
+
+ it "does not raise IndexError when byte offset is correct or on string boundary" do
+ "わ".byterindex("", 0).should == 0
+ "わ".byterindex("", 3).should == 3
+ "わ".byterindex("").should == 3
+ end
+
+ it_behaves_like :byte_index_common, :byterindex
+ end
+end
+
+describe "String#byterindex with String" do
+ ruby_version_is "3.2" do
+ it "behaves the same as String#byterindex(char) for one-character strings" do
+ "blablabla hello cruel world...!".split("").uniq.each do |str|
+ chr = str[0]
+ str.byterindex(str).should == str.byterindex(chr)
+
+ 0.upto(str.size + 1) do |start|
+ str.byterindex(str, start).should == str.byterindex(chr, start)
+ end
+
+ (-str.size - 1).upto(-1) do |start|
+ str.byterindex(str, start).should == str.byterindex(chr, start)
+ end
+ end
+ end
+
+ it "behaves the same as String#byterindex(?char) for one-character strings" do
+ "blablabla hello cruel world...!".split("").uniq.each do |str|
+ chr = str[0] =~ / / ? str[0] : eval("?#{str[0]}")
+ str.byterindex(str).should == str.byterindex(chr)
+
+ 0.upto(str.size + 1) do |start|
+ str.byterindex(str, start).should == str.byterindex(chr, start)
+ end
+
+ (-str.size - 1).upto(-1) do |start|
+ str.byterindex(str, start).should == str.byterindex(chr, start)
+ end
+ end
+ end
+
+ it "returns the index of the last occurrence of the given substring" do
+ "blablabla".byterindex("").should == 9
+ "blablabla".byterindex("a").should == 8
+ "blablabla".byterindex("la").should == 7
+ "blablabla".byterindex("bla").should == 6
+ "blablabla".byterindex("abla").should == 5
+ "blablabla".byterindex("labla").should == 4
+ "blablabla".byterindex("blabla").should == 3
+ "blablabla".byterindex("ablabla").should == 2
+ "blablabla".byterindex("lablabla").should == 1
+ "blablabla".byterindex("blablabla").should == 0
+
+ "blablabla".byterindex("l").should == 7
+ "blablabla".byterindex("bl").should == 6
+ "blablabla".byterindex("abl").should == 5
+ "blablabla".byterindex("labl").should == 4
+ "blablabla".byterindex("blabl").should == 3
+ "blablabla".byterindex("ablabl").should == 2
+ "blablabla".byterindex("lablabl").should == 1
+ "blablabla".byterindex("blablabl").should == 0
+
+ "blablabla".byterindex("b").should == 6
+ "blablabla".byterindex("ab").should == 5
+ "blablabla".byterindex("lab").should == 4
+ "blablabla".byterindex("blab").should == 3
+ "blablabla".byterindex("ablab").should == 2
+ "blablabla".byterindex("lablab").should == 1
+ "blablabla".byterindex("blablab").should == 0
+ end
+
+ it "ignores string subclasses" do
+ "blablabla".byterindex(StringSpecs::MyString.new("bla")).should == 6
+ StringSpecs::MyString.new("blablabla").byterindex("bla").should == 6
+ StringSpecs::MyString.new("blablabla").byterindex(StringSpecs::MyString.new("bla")).should == 6
+ end
+
+ it "starts the search at the given offset" do
+ "blablabla".byterindex("bl", 0).should == 0
+ "blablabla".byterindex("bl", 1).should == 0
+ "blablabla".byterindex("bl", 2).should == 0
+ "blablabla".byterindex("bl", 3).should == 3
+
+ "blablabla".byterindex("bla", 0).should == 0
+ "blablabla".byterindex("bla", 1).should == 0
+ "blablabla".byterindex("bla", 2).should == 0
+ "blablabla".byterindex("bla", 3).should == 3
+
+ "blablabla".byterindex("blab", 0).should == 0
+ "blablabla".byterindex("blab", 1).should == 0
+ "blablabla".byterindex("blab", 2).should == 0
+ "blablabla".byterindex("blab", 3).should == 3
+ "blablabla".byterindex("blab", 6).should == 3
+ "blablablax".byterindex("blab", 6).should == 3
+
+ "blablabla".byterindex("la", 1).should == 1
+ "blablabla".byterindex("la", 2).should == 1
+ "blablabla".byterindex("la", 3).should == 1
+ "blablabla".byterindex("la", 4).should == 4
+
+ "blablabla".byterindex("lab", 1).should == 1
+ "blablabla".byterindex("lab", 2).should == 1
+ "blablabla".byterindex("lab", 3).should == 1
+ "blablabla".byterindex("lab", 4).should == 4
+
+ "blablabla".byterindex("ab", 2).should == 2
+ "blablabla".byterindex("ab", 3).should == 2
+ "blablabla".byterindex("ab", 4).should == 2
+ "blablabla".byterindex("ab", 5).should == 5
+
+ "blablabla".byterindex("", 0).should == 0
+ "blablabla".byterindex("", 1).should == 1
+ "blablabla".byterindex("", 2).should == 2
+ "blablabla".byterindex("", 7).should == 7
+ "blablabla".byterindex("", 8).should == 8
+ "blablabla".byterindex("", 9).should == 9
+ "blablabla".byterindex("", 10).should == 9
+ end
+
+ it "starts the search at offset + self.length if offset is negative" do
+ str = "blablabla"
+
+ ["bl", "bla", "blab", "la", "lab", "ab", ""].each do |needle|
+ (-str.length .. -1).each do |offset|
+ str.byterindex(needle, offset).should ==
+ str.byterindex(needle, offset + str.length)
+ end
+ end
+ end
+
+ it "returns nil if the substring isn't found" do
+ "blablabla".byterindex("B").should == nil
+ "blablabla".byterindex("z").should == nil
+ "blablabla".byterindex("BLA").should == nil
+ "blablabla".byterindex("blablablabla").should == nil
+
+ "hello".byterindex("lo", 0).should == nil
+ "hello".byterindex("lo", 1).should == nil
+ "hello".byterindex("lo", 2).should == nil
+
+ "hello".byterindex("llo", 0).should == nil
+ "hello".byterindex("llo", 1).should == nil
+
+ "hello".byterindex("el", 0).should == nil
+ "hello".byterindex("ello", 0).should == nil
+
+ "hello".byterindex("", -6).should == nil
+ "hello".byterindex("", -7).should == nil
+
+ "hello".byterindex("h", -6).should == nil
+ end
+
+ it "tries to convert start_offset to an integer via to_int" do
+ obj = mock('5')
+ def obj.to_int() 5 end
+ "str".byterindex("st", obj).should == 0
+
+ obj = mock('5')
+ def obj.respond_to?(arg, *) true end
+ def obj.method_missing(*args) 5 end
+ "str".byterindex("st", obj).should == 0
+ end
+
+ it "raises a TypeError when given offset is nil" do
+ -> { "str".byterindex("st", nil) }.should raise_error(TypeError)
+ end
+
+ it "handles a substring in a superset encoding" do
+ 'abc'.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
+ end
+end
+
+describe "String#byterindex with Regexp" do
+ ruby_version_is "3.2" do
+ it "behaves the same as String#byterindex(string) for escaped string regexps" do
+ ["blablabla", "hello cruel world...!"].each do |str|
+ ["", "b", "bla", "lab", "o c", "d."].each do |needle|
+ regexp = Regexp.new(Regexp.escape(needle))
+ str.byterindex(regexp).should == str.byterindex(needle)
+
+ 0.upto(str.size + 1) do |start|
+ str.byterindex(regexp, start).should == str.byterindex(needle, start)
+ end
+
+ (-str.size - 1).upto(-1) do |start|
+ str.byterindex(regexp, start).should == str.byterindex(needle, start)
+ end
+ end
+ end
+ end
+
+ it "returns the index of the first match from the end of string of regexp" do
+ "blablabla".byterindex(/bla/).should == 6
+ "blablabla".byterindex(/BLA/i).should == 6
+
+ "blablabla".byterindex(/.{0}/).should == 9
+ "blablabla".byterindex(/.{1}/).should == 8
+ "blablabla".byterindex(/.{2}/).should == 7
+ "blablabla".byterindex(/.{6}/).should == 3
+ "blablabla".byterindex(/.{9}/).should == 0
+
+ "blablabla".byterindex(/.*/).should == 9
+ "blablabla".byterindex(/.+/).should == 8
+
+ "blablabla".byterindex(/bla|a/).should == 8
+
+ not_supported_on :opal do
+ "blablabla".byterindex(/\A/).should == 0
+ "blablabla".byterindex(/\Z/).should == 9
+ "blablabla".byterindex(/\z/).should == 9
+ "blablabla\n".byterindex(/\Z/).should == 10
+ "blablabla\n".byterindex(/\z/).should == 10
+ end
+
+ "blablabla".byterindex(/^/).should == 0
+ not_supported_on :opal do
+ "\nblablabla".byterindex(/^/).should == 1
+ "b\nlablabla".byterindex(/^/).should == 2
+ end
+ "blablabla".byterindex(/$/).should == 9
+
+ "blablabla".byterindex(/.l./).should == 6
+ end
+
+ it "starts the search at the given offset" do
+ "blablabla".byterindex(/.{0}/, 5).should == 5
+ "blablabla".byterindex(/.{1}/, 5).should == 5
+ "blablabla".byterindex(/.{2}/, 5).should == 5
+ "blablabla".byterindex(/.{3}/, 5).should == 5
+ "blablabla".byterindex(/.{4}/, 5).should == 5
+
+ "blablabla".byterindex(/.{0}/, 3).should == 3
+ "blablabla".byterindex(/.{1}/, 3).should == 3
+ "blablabla".byterindex(/.{2}/, 3).should == 3
+ "blablabla".byterindex(/.{5}/, 3).should == 3
+ "blablabla".byterindex(/.{6}/, 3).should == 3
+
+ "blablabla".byterindex(/.l./, 0).should == 0
+ "blablabla".byterindex(/.l./, 1).should == 0
+ "blablabla".byterindex(/.l./, 2).should == 0
+ "blablabla".byterindex(/.l./, 3).should == 3
+
+ "blablablax".byterindex(/.x/, 10).should == 8
+ "blablablax".byterindex(/.x/, 9).should == 8
+ "blablablax".byterindex(/.x/, 8).should == 8
+
+ "blablablax".byterindex(/..x/, 10).should == 7
+ "blablablax".byterindex(/..x/, 9).should == 7
+ "blablablax".byterindex(/..x/, 8).should == 7
+ "blablablax".byterindex(/..x/, 7).should == 7
+
+ not_supported_on :opal do
+ "blablabla\n".byterindex(/\Z/, 9).should == 9
+ end
+ end
+
+ it "starts the search at offset + self.length if offset is negative" do
+ str = "blablabla"
+
+ ["bl", "bla", "blab", "la", "lab", "ab", ""].each do |needle|
+ (-str.length .. -1).each do |offset|
+ str.byterindex(needle, offset).should ==
+ str.byterindex(needle, offset + str.length)
+ end
+ end
+ end
+
+ it "returns nil if the substring isn't found" do
+ "blablabla".byterindex(/BLA/).should == nil
+ "blablabla".byterindex(/.{10}/).should == nil
+ "blablablax".byterindex(/.x/, 7).should == nil
+ "blablablax".byterindex(/..x/, 6).should == nil
+
+ not_supported_on :opal do
+ "blablabla".byterindex(/\Z/, 5).should == nil
+ "blablabla".byterindex(/\z/, 5).should == nil
+ "blablabla\n".byterindex(/\z/, 9).should == nil
+ end
+ end
+
+ not_supported_on :opal do
+ it "supports \\G which matches at the given start offset" do
+ "helloYOU.".byterindex(/YOU\G/, 8).should == 5
+ "helloYOU.".byterindex(/YOU\G/).should == nil
+
+ idx = "helloYOUall!".index("YOU")
+ re = /YOU.+\G.+/
+ # The # marks where \G will match.
+ [
+ ["helloYOU#all.", nil],
+ ["helloYOUa#ll.", idx],
+ ["helloYOUal#l.", idx],
+ ["helloYOUall#.", idx],
+ ["helloYOUall.#", nil]
+ ].each do |i|
+ start = i[0].index("#")
+ str = i[0].delete("#")
+
+ str.byterindex(re, start).should == i[1]
+ end
+ end
+ end
+
+ it "tries to convert start_offset to an integer" do
+ obj = mock('5')
+ def obj.to_int() 5 end
+ "str".byterindex(/../, obj).should == 1
+
+ obj = mock('5')
+ def obj.respond_to?(arg, *) true end
+ def obj.method_missing(*args); 5; end
+ "str".byterindex(/../, obj).should == 1
+ end
+
+ it "raises a TypeError when given offset is nil" do
+ -> { "str".byterindex(/../, nil) }.should raise_error(TypeError)
+ end
+
+ it "returns the reverse byte index of a multibyte character" do
+ "ありがりがとう".byterindex("が").should == 12
+ "ありがりがとう".byterindex(/が/).should == 12
+ end
+
+ it "returns the character index before the finish" do
+ "ありがりがとう".byterindex("が", 9).should == 6
+ "ありがりがとう".byterindex(/が/, 9).should == 6
+ end
+ end
+end
diff --git a/spec/ruby/core/string/bytes_spec.rb b/spec/ruby/core/string/bytes_spec.rb
index 859b346550..02151eebbc 100644
--- a/spec/ruby/core/string/bytes_spec.rb
+++ b/spec/ruby/core/string/bytes_spec.rb
@@ -50,6 +50,6 @@ describe "String#bytes" do
end
it "is unaffected by #force_encoding" do
- @utf8.force_encoding('ASCII').bytes.to_a.should == @utf8.bytes.to_a
+ @utf8.dup.force_encoding('ASCII').bytes.to_a.should == @utf8.bytes.to_a
end
end
diff --git a/spec/ruby/core/string/bytesize_spec.rb b/spec/ruby/core/string/bytesize_spec.rb
index a31f3ae671..2bbefc0820 100644
--- a/spec/ruby/core/string/bytesize_spec.rb
+++ b/spec/ruby/core/string/bytesize_spec.rb
@@ -13,21 +13,21 @@ describe "String#bytesize" do
end
it "works with pseudo-ASCII strings containing single UTF-8 characters" do
- "\u{6666}".force_encoding('ASCII').bytesize.should == 3
+ "\u{6666}".dup.force_encoding('ASCII').bytesize.should == 3
end
it "works with strings containing UTF-8 characters" do
- "c \u{6666}".force_encoding('UTF-8').bytesize.should == 5
+ "c \u{6666}".dup.force_encoding('UTF-8').bytesize.should == 5
"c \u{6666}".bytesize.should == 5
end
it "works with pseudo-ASCII strings containing UTF-8 characters" do
- "c \u{6666}".force_encoding('ASCII').bytesize.should == 5
+ "c \u{6666}".dup.force_encoding('ASCII').bytesize.should == 5
end
it "returns 0 for the empty string" do
"".bytesize.should == 0
- "".force_encoding('ASCII').bytesize.should == 0
- "".force_encoding('UTF-8').bytesize.should == 0
+ "".dup.force_encoding('ASCII').bytesize.should == 0
+ "".dup.force_encoding('UTF-8').bytesize.should == 0
end
end
diff --git a/spec/ruby/core/string/byteslice_spec.rb b/spec/ruby/core/string/byteslice_spec.rb
index a49da040eb..5b1027f4a5 100644
--- a/spec/ruby/core/string/byteslice_spec.rb
+++ b/spec/ruby/core/string/byteslice_spec.rb
@@ -19,9 +19,15 @@ end
describe "String#byteslice on on non ASCII strings" do
it "returns byteslice of unicode strings" do
- "\u3042".byteslice(1).should == "\x81".force_encoding("UTF-8")
- "\u3042".byteslice(1, 2).should == "\x81\x82".force_encoding("UTF-8")
- "\u3042".byteslice(1..2).should == "\x81\x82".force_encoding("UTF-8")
- "\u3042".byteslice(-1).should == "\x82".force_encoding("UTF-8")
+ "\u3042".byteslice(1).should == "\x81".dup.force_encoding("UTF-8")
+ "\u3042".byteslice(1, 2).should == "\x81\x82".dup.force_encoding("UTF-8")
+ "\u3042".byteslice(1..2).should == "\x81\x82".dup.force_encoding("UTF-8")
+ "\u3042".byteslice(-1).should == "\x82".dup.force_encoding("UTF-8")
+ end
+
+ it "returns a String in the same encoding as self" do
+ "ruby".encode("UTF-8").slice(0).encoding.should == Encoding::UTF_8
+ "ruby".encode("US-ASCII").slice(0).encoding.should == Encoding::US_ASCII
+ "ruby".encode("Windows-1251").slice(0).encoding.should == Encoding::Windows_1251
end
end
diff --git a/spec/ruby/core/string/bytesplice_spec.rb b/spec/ruby/core/string/bytesplice_spec.rb
new file mode 100644
index 0000000000..967edcba29
--- /dev/null
+++ b/spec/ruby/core/string/bytesplice_spec.rb
@@ -0,0 +1,134 @@
+# -*- encoding: utf-8 -*-
+# frozen_string_literal: false
+require_relative '../../spec_helper'
+
+describe "String#bytesplice" do
+ ruby_version_is "3.2" do
+ it "raises IndexError when index is less than -bytesize" do
+ -> { "hello".bytesplice(-6, 0, "xxx") }.should raise_error(IndexError, "index -6 out of string")
+ end
+
+ it "raises IndexError when index is greater than bytesize" do
+ -> { "hello".bytesplice(6, 0, "xxx") }.should raise_error(IndexError, "index 6 out of string")
+ end
+
+ it "raises IndexError for negative length" do
+ -> { "abc".bytesplice(0, -2, "") }.should raise_error(IndexError, "negative length -2")
+ end
+
+ it "replaces with integer indices" do
+ "hello".bytesplice(-5, 0, "xxx").should == "xxxhello"
+ "hello".bytesplice(0, 0, "xxx").should == "xxxhello"
+ "hello".bytesplice(0, 1, "xxx").should == "xxxello"
+ "hello".bytesplice(0, 5, "xxx").should == "xxx"
+ "hello".bytesplice(0, 6, "xxx").should == "xxx"
+ end
+
+ it "raises RangeError when range left boundary is less than -bytesize" do
+ -> { "hello".bytesplice(-6...-6, "xxx") }.should raise_error(RangeError, "-6...-6 out of range")
+ end
+
+ it "replaces with ranges" do
+ "hello".bytesplice(-5...-5, "xxx").should == "xxxhello"
+ "hello".bytesplice(0...0, "xxx").should == "xxxhello"
+ "hello".bytesplice(0..0, "xxx").should == "xxxello"
+ "hello".bytesplice(0...1, "xxx").should == "xxxello"
+ "hello".bytesplice(0..1, "xxx").should == "xxxllo"
+ "hello".bytesplice(0..-1, "xxx").should == "xxx"
+ "hello".bytesplice(0...5, "xxx").should == "xxx"
+ "hello".bytesplice(0...6, "xxx").should == "xxx"
+ end
+
+ it "raises TypeError when integer index is provided without length argument" do
+ -> { "hello".bytesplice(0, "xxx") }.should raise_error(TypeError, "wrong argument type Integer (expected Range)")
+ end
+
+ it "replaces on an empty string" do
+ "".bytesplice(0, 0, "").should == ""
+ "".bytesplice(0, 0, "xxx").should == "xxx"
+ end
+
+ it "mutates self" do
+ s = "hello"
+ s.bytesplice(2, 1, "xxx").should.equal?(s)
+ end
+
+ it "raises when string is frozen" do
+ s = "hello".freeze
+ -> { s.bytesplice(2, 1, "xxx") }.should raise_error(FrozenError, "can't modify frozen String: \"hello\"")
+ end
+ end
+end
+
+describe "String#bytesplice with multibyte characters" do
+ ruby_version_is "3.2" do
+ it "raises IndexError when index is out of byte size boundary" do
+ -> { "こんにちは".bytesplice(-16, 0, "xxx") }.should raise_error(IndexError, "index -16 out of string")
+ end
+
+ it "raises IndexError when index is not on a codepoint boundary" do
+ -> { "こんにちは".bytesplice(1, 0, "xxx") }.should raise_error(IndexError, "offset 1 does not land on character boundary")
+ end
+
+ it "raises IndexError when length is not matching the codepoint boundary" do
+ -> { "こんにちは".bytesplice(0, 1, "xxx") }.should raise_error(IndexError, "offset 1 does not land on character boundary")
+ -> { "こんにちは".bytesplice(0, 2, "xxx") }.should raise_error(IndexError, "offset 2 does not land on character boundary")
+ end
+
+ it "replaces with integer indices" do
+ "こんにちは".bytesplice(-15, 0, "xxx").should == "xxxこんにちは"
+ "こんにちは".bytesplice(0, 0, "xxx").should == "xxxこんにちは"
+ "こんにちは".bytesplice(0, 3, "xxx").should == "xxxんにちは"
+ "こんにちは".bytesplice(3, 3, "はは").should == "こははにちは"
+ "こんにちは".bytesplice(15, 0, "xxx").should == "こんにちはxxx"
+ end
+
+ it "replaces with range" do
+ "こんにちは".bytesplice(-15...-16, "xxx").should == "xxxこんにちは"
+ "こんにちは".bytesplice(0...0, "xxx").should == "xxxこんにちは"
+ "こんにちは".bytesplice(0..2, "xxx").should == "xxxんにちは"
+ "こんにちは".bytesplice(0...3, "xxx").should == "xxxんにちは"
+ "こんにちは".bytesplice(0..5, "xxx").should == "xxxにちは"
+ "こんにちは".bytesplice(0..-1, "xxx").should == "xxx"
+ "こんにちは".bytesplice(0...15, "xxx").should == "xxx"
+ "こんにちは".bytesplice(0...18, "xxx").should == "xxx"
+ end
+
+ it "treats negative length for range as 0" do
+ "こんにちは".bytesplice(0...-100, "xxx").should == "xxxこんにちは"
+ "こんにちは".bytesplice(3...-100, "xxx").should == "こxxxんにちは"
+ "こんにちは".bytesplice(-15...-100, "xxx").should == "xxxこんにちは"
+ end
+
+ it "raises when ranges not match codepoint boundaries" do
+ -> { "こんにちは".bytesplice(0..0, "x") }.should raise_error(IndexError, "offset 1 does not land on character boundary")
+ -> { "こんにちは".bytesplice(0..1, "x") }.should raise_error(IndexError, "offset 2 does not land on character boundary")
+ # Begin is incorrect
+ -> { "こんにちは".bytesplice(-4..-1, "x") }.should raise_error(IndexError, "offset 11 does not land on character boundary")
+ -> { "こんにちは".bytesplice(-5..-1, "x") }.should raise_error(IndexError, "offset 10 does not land on character boundary")
+ # End is incorrect
+ -> { "こんにちは".bytesplice(-3..-2, "x") }.should raise_error(IndexError, "offset 14 does not land on character boundary")
+ -> { "こんにちは".bytesplice(-3..-3, "x") }.should raise_error(IndexError, "offset 13 does not land on character boundary")
+ end
+
+ it "deals with a different encoded argument" do
+ s = "こんにちは"
+ s.encoding.should == Encoding::UTF_8
+ sub = "xxxxxx"
+ sub.force_encoding(Encoding::US_ASCII)
+
+ result = s.bytesplice(0, 3, sub)
+ result.should == "xxxxxxんにちは"
+ result.encoding.should == Encoding::UTF_8
+
+ s = "xxxxxx"
+ s.force_encoding(Encoding::US_ASCII)
+ sub = "こんにちは"
+ sub.encoding.should == Encoding::UTF_8
+
+ result = s.bytesplice(0, 3, sub)
+ result.should == "こんにちはxxx"
+ result.encoding.should == Encoding::UTF_8
+ end
+ end
+end
diff --git a/spec/ruby/core/string/capitalize_spec.rb b/spec/ruby/core/string/capitalize_spec.rb
index 21df18a5ae..5e59b656c5 100644
--- a/spec/ruby/core/string/capitalize_spec.rb
+++ b/spec/ruby/core/string/capitalize_spec.rb
@@ -10,13 +10,7 @@ describe "String#capitalize" do
"hello".capitalize.should == "Hello"
"HELLO".capitalize.should == "Hello"
"123ABC".capitalize.should == "123abc"
- end
-
- ruby_version_is ''...'2.7' do
- it "taints resulting string when self is tainted" do
- "".taint.capitalize.should.tainted?
- "hello".taint.capitalize.should.tainted?
- end
+ "abcdef"[1...-1].capitalize.should == "Bcde"
end
describe "full Unicode case mapping" do
@@ -42,6 +36,10 @@ describe "String#capitalize" do
it "does not capitalize non-ASCII characters" do
"ßet".capitalize(:ascii).should == "ßet"
end
+
+ it "handles non-ASCII substrings properly" do
+ "garçon"[1...-1].capitalize(:ascii).should == "Arço"
+ end
end
describe "full Unicode case mapping adapted for Turkic languages" do
@@ -80,24 +78,19 @@ describe "String#capitalize" do
-> { "abc".capitalize(:invalid_option) }.should raise_error(ArgumentError)
end
- ruby_version_is ''...'3.0' do
- it "returns subclass instances when called on a subclass" do
- StringSpecs::MyString.new("hello").capitalize.should be_an_instance_of(StringSpecs::MyString)
- StringSpecs::MyString.new("Hello").capitalize.should be_an_instance_of(StringSpecs::MyString)
- end
+ it "returns String instances when called on a subclass" do
+ StringSpecs::MyString.new("hello").capitalize.should be_an_instance_of(String)
+ StringSpecs::MyString.new("Hello").capitalize.should be_an_instance_of(String)
end
- ruby_version_is '3.0' do
- it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new("hello").capitalize.should be_an_instance_of(String)
- StringSpecs::MyString.new("Hello").capitalize.should be_an_instance_of(String)
- end
+ it "returns a String in the same encoding as self" do
+ "h".encode("US-ASCII").capitalize.encoding.should == Encoding::US_ASCII
end
end
describe "String#capitalize!" do
it "capitalizes self in place" do
- a = "hello"
+ a = +"hello"
a.capitalize!.should equal(a)
a.should == "Hello"
end
@@ -110,13 +103,13 @@ describe "String#capitalize!" do
describe "full Unicode case mapping" do
it "modifies self in place for all of Unicode with no option" do
- a = "äöÜ"
+ a = +"äöÜ"
a.capitalize!
a.should == "Äöü"
end
it "only capitalizes the first resulting character when upcasing a character produces a multi-character sequence" do
- a = "ß"
+ a = +"ß"
a.capitalize!
a.should == "Ss"
end
@@ -128,7 +121,7 @@ describe "String#capitalize!" do
end
it "updates string metadata" do
- capitalized = "ßeT"
+ capitalized = +"ßeT"
capitalized.capitalize!
capitalized.should == "Sset"
@@ -140,7 +133,7 @@ describe "String#capitalize!" do
describe "modifies self in place for ASCII-only case mapping" do
it "does not capitalize non-ASCII characters" do
- a = "ßet"
+ a = +"ßet"
a.capitalize!(:ascii)
a.should == "ßet"
end
@@ -154,13 +147,13 @@ describe "String#capitalize!" do
describe "modifies self in place for full Unicode case mapping adapted for Turkic languages" do
it "capitalizes ASCII characters according to Turkic semantics" do
- a = "iSa"
+ a = +"iSa"
a.capitalize!(:turkic)
a.should == "İsa"
end
it "allows Lithuanian as an extra option" do
- a = "iSa"
+ a = +"iSa"
a.capitalize!(:turkic, :lithuanian)
a.should == "İsa"
end
@@ -172,13 +165,13 @@ describe "String#capitalize!" do
describe "modifies self in place for full Unicode case mapping adapted for Lithuanian" do
it "currently works the same as full Unicode case mapping" do
- a = "iß"
+ a = +"iß"
a.capitalize!(:lithuanian)
a.should == "Iß"
end
it "allows Turkic as an extra option (and applies Turkic semantics)" do
- a = "iß"
+ a = +"iß"
a.capitalize!(:lithuanian, :turkic)
a.should == "İß"
end
@@ -197,12 +190,12 @@ describe "String#capitalize!" do
end
it "returns nil when no changes are made" do
- a = "Hello"
+ a = +"Hello"
a.capitalize!.should == nil
a.should == "Hello"
- "".capitalize!.should == nil
- "H".capitalize!.should == nil
+ (+"").capitalize!.should == nil
+ (+"H").capitalize!.should == nil
end
it "raises a FrozenError when self is frozen" do
diff --git a/spec/ruby/core/string/casecmp_spec.rb b/spec/ruby/core/string/casecmp_spec.rb
index 986fbc8718..81ebea557c 100644
--- a/spec/ruby/core/string/casecmp_spec.rb
+++ b/spec/ruby/core/string/casecmp_spec.rb
@@ -117,6 +117,11 @@ describe "String#casecmp independent of case" do
"B".casecmp(a).should == 1
end
end
+
+ it "returns 0 for empty strings in different encodings" do
+ ''.b.casecmp('').should == 0
+ ''.b.casecmp(''.encode("UTF-32LE")).should == 0
+ end
end
describe 'String#casecmp? independent of case' do
@@ -191,4 +196,9 @@ describe 'String#casecmp? independent of case' do
it "returns nil if other can't be converted to a string" do
"abc".casecmp?(mock('abc')).should be_nil
end
+
+ it "returns true for empty strings in different encodings" do
+ ''.b.should.casecmp?('')
+ ''.b.should.casecmp?(''.encode("UTF-32LE"))
+ end
end
diff --git a/spec/ruby/core/string/center_spec.rb b/spec/ruby/core/string/center_spec.rb
index b66015172c..1667b59327 100644
--- a/spec/ruby/core/string/center_spec.rb
+++ b/spec/ruby/core/string/center_spec.rb
@@ -47,16 +47,6 @@ describe "String#center with length, padding" do
"radiology".center(8, '-').should == "radiology"
end
- ruby_version_is ''...'2.7' do
- it "taints result when self or padstr is tainted" do
- "x".taint.center(4).should.tainted?
- "x".taint.center(0).should.tainted?
- "".taint.center(0).should.tainted?
- "x".taint.center(4, "*").should.tainted?
- "x".center(4, "*".taint).should.tainted?
- end
- end
-
it "calls #to_int to convert length to an integer" do
"_".center(3.8, "^").should == "^_^"
@@ -91,39 +81,18 @@ describe "String#center with length, padding" do
-> { "hello".center(0, "") }.should raise_error(ArgumentError)
end
- ruby_version_is ''...'3.0' do
- it "returns subclass instances when called on subclasses" do
- StringSpecs::MyString.new("").center(10).should be_an_instance_of(StringSpecs::MyString)
- StringSpecs::MyString.new("foo").center(10).should be_an_instance_of(StringSpecs::MyString)
- StringSpecs::MyString.new("foo").center(10, StringSpecs::MyString.new("x")).should be_an_instance_of(StringSpecs::MyString)
-
- "".center(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
- "foo".center(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
- end
- end
+ it "returns String instances when called on subclasses" do
+ StringSpecs::MyString.new("").center(10).should be_an_instance_of(String)
+ StringSpecs::MyString.new("foo").center(10).should be_an_instance_of(String)
+ StringSpecs::MyString.new("foo").center(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
- ruby_version_is '3.0' do
- it "returns String instances when called on subclasses" do
- StringSpecs::MyString.new("").center(10).should be_an_instance_of(String)
- StringSpecs::MyString.new("foo").center(10).should be_an_instance_of(String)
- StringSpecs::MyString.new("foo").center(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
-
- "".center(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
- "foo".center(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
- end
- end
-
- ruby_version_is ''...'2.7' do
- it "when padding is tainted and self is untainted returns a tainted string if and only if length is longer than self" do
- "hello".center(4, 'X'.taint).tainted?.should be_false
- "hello".center(5, 'X'.taint).tainted?.should be_false
- "hello".center(6, 'X'.taint).tainted?.should be_true
- end
+ "".center(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
+ "foo".center(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
end
describe "with width" do
it "returns a String in the same encoding as the original" do
- str = "abc".force_encoding Encoding::IBM437
+ str = "abc".dup.force_encoding Encoding::IBM437
result = str.center 6
result.should == " abc "
result.encoding.should equal(Encoding::IBM437)
@@ -132,7 +101,7 @@ describe "String#center with length, padding" do
describe "with width, pattern" do
it "returns a String in the compatible encoding" do
- str = "abc".force_encoding Encoding::IBM437
+ str = "abc".dup.force_encoding Encoding::IBM437
result = str.center 6, "あ"
result.should == "あabcああ"
result.encoding.should equal(Encoding::UTF_8)
diff --git a/spec/ruby/core/string/chars_spec.rb b/spec/ruby/core/string/chars_spec.rb
index e4f26bc0cc..ee85430574 100644
--- a/spec/ruby/core/string/chars_spec.rb
+++ b/spec/ruby/core/string/chars_spec.rb
@@ -1,5 +1,5 @@
+require_relative "../../spec_helper"
require_relative 'shared/chars'
-require_relative 'shared/each_char_without_block'
describe "String#chars" do
it_behaves_like :string_chars, :chars
@@ -7,4 +7,10 @@ describe "String#chars" do
it "returns an array when no block given" do
"hello".chars.should == ['h', 'e', 'l', 'l', 'o']
end
+
+ it "returns Strings in the same encoding as self" do
+ "hello".encode("US-ASCII").chars.each do |c|
+ c.encoding.should == Encoding::US_ASCII
+ end
+ end
end
diff --git a/spec/ruby/core/string/chilled_string_spec.rb b/spec/ruby/core/string/chilled_string_spec.rb
new file mode 100644
index 0000000000..8de4fc421b
--- /dev/null
+++ b/spec/ruby/core/string/chilled_string_spec.rb
@@ -0,0 +1,69 @@
+require_relative '../../spec_helper'
+
+describe "chilled String" do
+ guard -> { ruby_version_is "3.4" and !"test".equal?("test") } do
+ describe "#frozen?" do
+ it "returns true" do
+ "chilled".frozen?.should == true
+ end
+ end
+
+ describe "#-@" do
+ it "returns a different instance" do
+ input = "chilled"
+ interned = (-input)
+ interned.frozen?.should == true
+ interned.object_id.should_not == input.object_id
+ end
+ end
+
+ describe "#+@" do
+ it "returns a different instance" do
+ input = "chilled"
+ duped = (+input)
+ duped.frozen?.should == false
+ duped.object_id.should_not == input.object_id
+ end
+ end
+
+ describe "#clone" do
+ it "preserves chilled status" do
+ input = "chilled".clone
+ -> {
+ input << "-mutated"
+ }.should complain(/literal string will be frozen in the future/)
+ input.should == "chilled-mutated"
+ end
+ end
+
+ describe "mutation" do
+ it "emits a warning" do
+ input = "chilled"
+ -> {
+ input << "-mutated"
+ }.should complain(/literal string will be frozen in the future/)
+ input.should == "chilled-mutated"
+ end
+
+ it "emits a warning on singleton_class creaation" do
+ -> {
+ "chilled".singleton_class
+ }.should complain(/literal string will be frozen in the future/)
+ end
+
+ it "emits a warning on instance variable assignment" do
+ -> {
+ "chilled".instance_variable_set(:@ivar, 42)
+ }.should complain(/literal string will be frozen in the future/)
+ end
+
+ it "raises FrozenError after the string was explictly frozen" do
+ input = "chilled"
+ input.freeze
+ -> {
+ input << "mutated"
+ }.should raise_error(FrozenError)
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/string/chomp_spec.rb b/spec/ruby/core/string/chomp_spec.rb
index 3d6207f876..d27c84c6f6 100644
--- a/spec/ruby/core/string/chomp_spec.rb
+++ b/spec/ruby/core/string/chomp_spec.rb
@@ -1,4 +1,5 @@
# -*- encoding: utf-8 -*-
+# frozen_string_literal: false
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
@@ -40,24 +41,13 @@ describe "String#chomp" do
"".chomp.should == ""
end
- ruby_version_is ''...'2.7' do
- it "taints the result if self is tainted" do
- "abc".taint.chomp.tainted?.should be_true
- end
+ it "returns a String in the same encoding as self" do
+ "abc\n\n".encode("US-ASCII").chomp.encoding.should == Encoding::US_ASCII
end
- ruby_version_is ''...'3.0' do
- it "returns subclass instances when called on a subclass" do
- str = StringSpecs::MyString.new("hello\n").chomp
- str.should be_an_instance_of(StringSpecs::MyString)
- end
- end
-
- ruby_version_is '3.0' do
- it "returns String instances when called on a subclass" do
- str = StringSpecs::MyString.new("hello\n").chomp
- str.should be_an_instance_of(String)
- end
+ it "returns String instances when called on a subclass" do
+ str = StringSpecs::MyString.new("hello\n").chomp
+ str.should be_an_instance_of(String)
end
it "removes trailing characters that match $/ when it has been assigned a value" do
@@ -80,12 +70,6 @@ describe "String#chomp" do
str.chomp(nil).should_not equal(str)
end
- ruby_version_is ''...'2.7' do
- it "taints the result if self is tainted" do
- "abc".taint.chomp(nil).tainted?.should be_true
- end
- end
-
it "returns an empty String when self is empty" do
"".chomp(nil).should == ""
end
@@ -112,12 +96,6 @@ describe "String#chomp" do
"abc\r\n\r\n\r\n".chomp("").should == "abc"
end
- ruby_version_is ''...'2.7' do
- it "taints the result if self is tainted" do
- "abc".taint.chomp("").tainted?.should be_true
- end
- end
-
it "returns an empty String when self is empty" do
"".chomp("").should == ""
end
@@ -140,12 +118,6 @@ describe "String#chomp" do
"abc\r\n\r\n".chomp("\n").should == "abc\r\n"
end
- ruby_version_is ''...'2.7' do
- it "taints the result if self is tainted" do
- "abc".taint.chomp("\n").tainted?.should be_true
- end
- end
-
it "returns an empty String when self is empty" do
"".chomp("\n").should == ""
end
@@ -178,16 +150,6 @@ describe "String#chomp" do
"".chomp("abc").should == ""
end
- ruby_version_is ''...'2.7' do
- it "taints the result if self is tainted" do
- "abc".taint.chomp("abc").tainted?.should be_true
- end
-
- it "does not taint the result when the argument is tainted" do
- "abc".chomp("abc".taint).tainted?.should be_false
- end
- end
-
it "returns an empty String when the argument equals self" do
"abc".chomp("abc").should == ""
end
@@ -232,12 +194,6 @@ describe "String#chomp!" do
"".chomp!.should be_nil
end
- ruby_version_is ''...'2.7' do
- it "taints the result if self is tainted" do
- "abc\n".taint.chomp!.tainted?.should be_true
- end
- end
-
it "returns subclass instances when called on a subclass" do
str = StringSpecs::MyString.new("hello\n").chomp!
str.should be_an_instance_of(StringSpecs::MyString)
@@ -280,12 +236,6 @@ describe "String#chomp!" do
"abc\r\n\r\n\r\n".chomp!("").should == "abc"
end
- ruby_version_is ''...'2.7' do
- it "taints the result if self is tainted" do
- "abc\n".taint.chomp!("").tainted?.should be_true
- end
- end
-
it "returns nil when self is empty" do
"".chomp!("").should be_nil
end
@@ -304,12 +254,6 @@ describe "String#chomp!" do
"abc\r\n\r\n".chomp!("\n").should == "abc\r\n"
end
- ruby_version_is ''...'2.7' do
- it "taints the result if self is tainted" do
- "abc\n".taint.chomp!("\n").tainted?.should be_true
- end
- end
-
it "returns nil when self is empty" do
"".chomp!("\n").should be_nil
end
@@ -341,16 +285,6 @@ describe "String#chomp!" do
it "returns nil when self is empty" do
"".chomp!("abc").should be_nil
end
-
- ruby_version_is ''...'2.7' do
- it "taints the result if self is tainted" do
- "abc".taint.chomp!("abc").tainted?.should be_true
- end
-
- it "does not taint the result when the argument is tainted" do
- "abc".chomp!("abc".taint).tainted?.should be_false
- end
- end
end
it "raises a FrozenError on a frozen instance when it is modified" do
diff --git a/spec/ruby/core/string/chop_spec.rb b/spec/ruby/core/string/chop_spec.rb
index 9b4e7363c6..99c2c82190 100644
--- a/spec/ruby/core/string/chop_spec.rb
+++ b/spec/ruby/core/string/chop_spec.rb
@@ -1,4 +1,5 @@
# -*- encoding: utf-8 -*-
+# frozen_string_literal: false
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
@@ -49,28 +50,12 @@ describe "String#chop" do
s.chop.should_not equal(s)
end
- ruby_version_is ''...'2.7' do
- it "taints result when self is tainted" do
- "hello".taint.chop.should.tainted?
- "".taint.chop.should.tainted?
- end
-
- it "untrusts result when self is untrusted" do
- "hello".untrust.chop.should.untrusted?
- "".untrust.chop.should.untrusted?
- end
- end
-
- ruby_version_is ''...'3.0' do
- it "returns subclass instances when called on a subclass" do
- StringSpecs::MyString.new("hello\n").chop.should be_an_instance_of(StringSpecs::MyString)
- end
+ it "returns String instances when called on a subclass" do
+ StringSpecs::MyString.new("hello\n").chop.should be_an_instance_of(String)
end
- ruby_version_is '3.0' do
- it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new("hello\n").chop.should be_an_instance_of(String)
- end
+ it "returns a String in the same encoding as self" do
+ "abc\n\n".encode("US-ASCII").chop.encoding.should == Encoding::US_ASCII
end
end
diff --git a/spec/ruby/core/string/clear_spec.rb b/spec/ruby/core/string/clear_spec.rb
index e1d68e03bd..152986fd0f 100644
--- a/spec/ruby/core/string/clear_spec.rb
+++ b/spec/ruby/core/string/clear_spec.rb
@@ -1,3 +1,4 @@
+# frozen_string_literal: false
require_relative '../../spec_helper'
describe "String#clear" do
diff --git a/spec/ruby/core/string/clone_spec.rb b/spec/ruby/core/string/clone_spec.rb
index f8d40423f0..a2ba2f9877 100644
--- a/spec/ruby/core/string/clone_spec.rb
+++ b/spec/ruby/core/string/clone_spec.rb
@@ -54,4 +54,8 @@ describe "String#clone" do
orig.should == "xtring"
clone.should == "string"
end
+
+ it "returns a String in the same encoding as self" do
+ "a".encode("US-ASCII").clone.encoding.should == Encoding::US_ASCII
+ end
end
diff --git a/spec/ruby/core/string/codepoints_spec.rb b/spec/ruby/core/string/codepoints_spec.rb
index 0b6cde82f7..b276d0baa8 100644
--- a/spec/ruby/core/string/codepoints_spec.rb
+++ b/spec/ruby/core/string/codepoints_spec.rb
@@ -11,7 +11,7 @@ describe "String#codepoints" do
end
it "raises an ArgumentError when no block is given if self has an invalid encoding" do
- s = "\xDF".force_encoding(Encoding::UTF_8)
+ s = "\xDF".dup.force_encoding(Encoding::UTF_8)
s.valid_encoding?.should be_false
-> { s.codepoints }.should raise_error(ArgumentError)
end
diff --git a/spec/ruby/core/string/comparison_spec.rb b/spec/ruby/core/string/comparison_spec.rb
index 01199274b6..9db0cff5ee 100644
--- a/spec/ruby/core/string/comparison_spec.rb
+++ b/spec/ruby/core/string/comparison_spec.rb
@@ -61,12 +61,12 @@ describe "String#<=> with String" do
end
it "ignores encoding difference" do
- ("ÄÖÛ".force_encoding("utf-8") <=> "ÄÖÜ".force_encoding("iso-8859-1")).should == -1
- ("ÄÖÜ".force_encoding("utf-8") <=> "ÄÖÛ".force_encoding("iso-8859-1")).should == 1
+ ("ÄÖÛ".dup.force_encoding("utf-8") <=> "ÄÖÜ".dup.force_encoding("iso-8859-1")).should == -1
+ ("ÄÖÜ".dup.force_encoding("utf-8") <=> "ÄÖÛ".dup.force_encoding("iso-8859-1")).should == 1
end
it "returns 0 with identical ASCII-compatible bytes of different encodings" do
- ("abc".force_encoding("utf-8") <=> "abc".force_encoding("iso-8859-1")).should == 0
+ ("abc".dup.force_encoding("utf-8") <=> "abc".dup.force_encoding("iso-8859-1")).should == 0
end
it "compares the indices of the encodings when the strings have identical non-ASCII-compatible bytes" do
@@ -75,6 +75,10 @@ describe "String#<=> with String" do
(xff_1 <=> xff_2).should == -1
(xff_2 <=> xff_1).should == 1
end
+
+ it "returns 0 when comparing 2 empty strings but one is not ASCII-compatible" do
+ ("" <=> "".dup.force_encoding('iso-2022-jp')).should == 0
+ end
end
# Note: This is inconsistent with Array#<=> which calls #to_ary instead of
diff --git a/spec/ruby/core/string/concat_spec.rb b/spec/ruby/core/string/concat_spec.rb
index 5f6daadad7..cbd7df54e2 100644
--- a/spec/ruby/core/string/concat_spec.rb
+++ b/spec/ruby/core/string/concat_spec.rb
@@ -5,21 +5,22 @@ require_relative 'shared/concat'
describe "String#concat" do
it_behaves_like :string_concat, :concat
it_behaves_like :string_concat_encoding, :concat
+ it_behaves_like :string_concat_type_coercion, :concat
it "takes multiple arguments" do
- str = "hello "
+ str = +"hello "
str.concat "wo", "", "rld"
str.should == "hello world"
end
it "concatenates the initial value when given arguments contain 2 self" do
- str = "hello"
+ str = +"hello"
str.concat str, str
str.should == "hellohellohello"
end
it "returns self when given no arguments" do
- str = "hello"
+ str = +"hello"
str.concat.should equal(str)
str.should == "hello"
end
diff --git a/spec/ruby/core/string/crypt_spec.rb b/spec/ruby/core/string/crypt_spec.rb
index b947702492..06f84c70a4 100644
--- a/spec/ruby/core/string/crypt_spec.rb
+++ b/spec/ruby/core/string/crypt_spec.rb
@@ -25,21 +25,6 @@ describe "String#crypt" do
"mypassword".crypt(obj).should == "$2a$04$0WVaz0pV3jzfZ5G5tpmHWuBQGbkjzgtSc3gJbmdy0GAGMa45MFM2."
end
- ruby_version_is ''...'2.7' do
- it "taints the result if either salt or self is tainted" do
- tainted_salt = "$2a$04$0WVaz0pV3jzfZ5G5tpmHWu"
- tainted_str = "mypassword"
-
- tainted_salt.taint
- tainted_str.taint
-
- "mypassword".crypt("$2a$04$0WVaz0pV3jzfZ5G5tpmHWu").should_not.tainted?
- tainted_str.crypt("$2a$04$0WVaz0pV3jzfZ5G5tpmHWu").should.tainted?
- "mypassword".crypt(tainted_salt).should.tainted?
- tainted_str.crypt(tainted_salt).should.tainted?
- end
- end
-
it "doesn't return subclass instances" do
StringSpecs::MyString.new("mypassword").crypt("$2a$04$0WVaz0pV3jzfZ5G5tpmHWu").should be_an_instance_of(String)
"mypassword".crypt(StringSpecs::MyString.new("$2a$04$0WVaz0pV3jzfZ5G5tpmHWu")).should be_an_instance_of(String)
@@ -85,21 +70,6 @@ describe "String#crypt" do
"".crypt(obj).should == "aaQSqAReePlq6"
end
- ruby_version_is ''...'2.7' do
- it "taints the result if either salt or self is tainted" do
- tainted_salt = "aa"
- tainted_str = "hello"
-
- tainted_salt.taint
- tainted_str.taint
-
- "hello".crypt("aa").should_not.tainted?
- tainted_str.crypt("aa").should.tainted?
- "hello".crypt(tainted_salt).should.tainted?
- tainted_str.crypt(tainted_salt).should.tainted?
- end
- end
-
it "doesn't return subclass instances" do
StringSpecs::MyString.new("hello").crypt("aa").should be_an_instance_of(String)
"hello".crypt(StringSpecs::MyString.new("aa")).should be_an_instance_of(String)
diff --git a/spec/ruby/core/string/dedup_spec.rb b/spec/ruby/core/string/dedup_spec.rb
new file mode 100644
index 0000000000..57d2be2cfd
--- /dev/null
+++ b/spec/ruby/core/string/dedup_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../spec_helper'
+require_relative 'shared/dedup'
+
+describe 'String#dedup' do
+ ruby_version_is '3.2' do
+ it_behaves_like :string_dedup, :dedup
+ end
+end
diff --git a/spec/ruby/core/string/delete_prefix_spec.rb b/spec/ruby/core/string/delete_prefix_spec.rb
index 8469791f74..ee7f044905 100644
--- a/spec/ruby/core/string/delete_prefix_spec.rb
+++ b/spec/ruby/core/string/delete_prefix_spec.rb
@@ -1,4 +1,5 @@
# -*- encoding: utf-8 -*-
+# frozen_string_literal: false
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
@@ -21,11 +22,8 @@ describe "String#delete_prefix" do
r.should == s
end
- ruby_version_is ''...'2.7' do
- it "taints resulting strings when other is tainted" do
- 'hello'.taint.delete_prefix('hell').should.tainted?
- 'hello'.taint.delete_prefix('').should.tainted?
- end
+ it "does not remove partial bytes, only full characters" do
+ "\xe3\x81\x82".delete_prefix("\xe3").should == "\xe3\x81\x82"
end
it "doesn't set $~" do
@@ -41,18 +39,13 @@ describe "String#delete_prefix" do
'hello'.delete_prefix(o).should == 'o'
end
- ruby_version_is ''...'3.0' do
- it "returns a subclass instance when called on a subclass instance" do
- s = StringSpecs::MyString.new('hello')
- s.delete_prefix('hell').should be_an_instance_of(StringSpecs::MyString)
- end
+ it "returns a String instance when called on a subclass instance" do
+ s = StringSpecs::MyString.new('hello')
+ s.delete_prefix('hell').should be_an_instance_of(String)
end
- ruby_version_is '3.0' do
- it "returns a String instance when called on a subclass instance" do
- s = StringSpecs::MyString.new('hello')
- s.delete_prefix('hell').should be_an_instance_of(String)
- end
+ it "returns a String in the same encoding as self" do
+ 'hello'.encode("US-ASCII").delete_prefix('hell').encoding.should == Encoding::US_ASCII
end
end
diff --git a/spec/ruby/core/string/delete_spec.rb b/spec/ruby/core/string/delete_spec.rb
index ebca0b7dae..6d359776e4 100644
--- a/spec/ruby/core/string/delete_spec.rb
+++ b/spec/ruby/core/string/delete_spec.rb
@@ -1,4 +1,5 @@
# -*- encoding: utf-8 -*-
+# frozen_string_literal: false
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
@@ -68,15 +69,6 @@ describe "String#delete" do
-> { "hello".delete("^h-e") }.should raise_error(ArgumentError)
end
- ruby_version_is ''...'2.7' do
- it "taints result when self is tainted" do
- "hello".taint.delete("e").should.tainted?
- "hello".taint.delete("a-z").should.tainted?
-
- "hello".delete("e".taint).should_not.tainted?
- end
- end
-
it "tries to convert each set arg to a string using to_str" do
other_string = mock('lo')
other_string.should_receive(:to_str).and_return("lo")
@@ -93,16 +85,12 @@ describe "String#delete" do
-> { "hello world".delete(mock('x')) }.should raise_error(TypeError)
end
- ruby_version_is ''...'3.0' do
- it "returns subclass instances when called on a subclass" do
- StringSpecs::MyString.new("oh no!!!").delete("!").should be_an_instance_of(StringSpecs::MyString)
- end
+ it "returns String instances when called on a subclass" do
+ StringSpecs::MyString.new("oh no!!!").delete("!").should be_an_instance_of(String)
end
- ruby_version_is '3.0' do
- it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new("oh no!!!").delete("!").should be_an_instance_of(String)
- end
+ it "returns a String in the same encoding as self" do
+ "hello".encode("US-ASCII").delete("lo").encoding.should == Encoding::US_ASCII
end
end
diff --git a/spec/ruby/core/string/delete_suffix_spec.rb b/spec/ruby/core/string/delete_suffix_spec.rb
index 12d0ee175e..1842d75aa5 100644
--- a/spec/ruby/core/string/delete_suffix_spec.rb
+++ b/spec/ruby/core/string/delete_suffix_spec.rb
@@ -1,4 +1,5 @@
# -*- encoding: utf-8 -*-
+# frozen_string_literal: false
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
@@ -21,11 +22,8 @@ describe "String#delete_suffix" do
r.should == s
end
- ruby_version_is ''...'2.7' do
- it "taints resulting strings when other is tainted" do
- 'hello'.taint.delete_suffix('ello').should.tainted?
- 'hello'.taint.delete_suffix('').should.tainted?
- end
+ it "does not remove partial bytes, only full characters" do
+ "\xe3\x81\x82".delete_suffix("\x82").should == "\xe3\x81\x82"
end
it "doesn't set $~" do
@@ -41,18 +39,13 @@ describe "String#delete_suffix" do
'hello'.delete_suffix(o).should == 'h'
end
- ruby_version_is ''...'3.0' do
- it "returns a subclass instance when called on a subclass instance" do
- s = StringSpecs::MyString.new('hello')
- s.delete_suffix('ello').should be_an_instance_of(StringSpecs::MyString)
- end
+ it "returns a String instance when called on a subclass instance" do
+ s = StringSpecs::MyString.new('hello')
+ s.delete_suffix('ello').should be_an_instance_of(String)
end
- ruby_version_is '3.0' do
- it "returns a String instance when called on a subclass instance" do
- s = StringSpecs::MyString.new('hello')
- s.delete_suffix('ello').should be_an_instance_of(String)
- end
+ it "returns a String in the same encoding as self" do
+ "hello".encode("US-ASCII").delete_suffix("ello").encoding.should == Encoding::US_ASCII
end
end
diff --git a/spec/ruby/core/string/downcase_spec.rb b/spec/ruby/core/string/downcase_spec.rb
index 4427c9df10..2d260f23f1 100644
--- a/spec/ruby/core/string/downcase_spec.rb
+++ b/spec/ruby/core/string/downcase_spec.rb
@@ -1,4 +1,5 @@
# -*- encoding: utf-8 -*-
+# frozen_string_literal: false
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
@@ -8,6 +9,10 @@ describe "String#downcase" do
"hello".downcase.should == "hello"
end
+ it "returns a String in the same encoding as self" do
+ "hELLO".encode("US-ASCII").downcase.encoding.should == Encoding::US_ASCII
+ end
+
describe "full Unicode case mapping" do
it "works for all of Unicode with no option" do
"ÄÖÜ".downcase.should == "äöü"
@@ -27,6 +32,10 @@ describe "String#downcase" do
it "does not downcase non-ASCII characters" do
"CÅR".downcase(:ascii).should == "cÅr"
end
+
+ it "works with substrings" do
+ "prefix TÉ"[-2..-1].downcase(:ascii).should == "tÉ"
+ end
end
describe "full Unicode case mapping adapted for Turkic languages" do
@@ -68,24 +77,8 @@ describe "String#downcase" do
-> { "ABC".downcase(:invalid_option) }.should raise_error(ArgumentError)
end
- ruby_version_is ''...'2.7' do
- it "taints result when self is tainted" do
- "".taint.downcase.should.tainted?
- "x".taint.downcase.should.tainted?
- "X".taint.downcase.should.tainted?
- end
- end
-
- ruby_version_is ''...'3.0' do
- it "returns a subclass instance for subclasses" do
- StringSpecs::MyString.new("FOObar").downcase.should be_an_instance_of(StringSpecs::MyString)
- end
- end
-
- ruby_version_is '3.0' do
- it "returns a String instance for subclasses" do
- StringSpecs::MyString.new("FOObar").downcase.should be_an_instance_of(String)
- end
+ it "returns a String instance for subclasses" do
+ StringSpecs::MyString.new("FOObar").downcase.should be_an_instance_of(String)
end
end
diff --git a/spec/ruby/core/string/dump_spec.rb b/spec/ruby/core/string/dump_spec.rb
index 817dec6c4d..cab8beff5a 100644
--- a/spec/ruby/core/string/dump_spec.rb
+++ b/spec/ruby/core/string/dump_spec.rb
@@ -3,32 +3,12 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "String#dump" do
- ruby_version_is ''...'2.7' do
- it "taints the result if self is tainted" do
- "foo".taint.dump.should.tainted?
- "foo\n".taint.dump.should.tainted?
- end
-
- it "untrusts the result if self is untrusted" do
- "foo".untrust.dump.should.untrusted?
- "foo\n".untrust.dump.should.untrusted?
- end
- end
-
it "does not take into account if a string is frozen" do
"foo".freeze.dump.should_not.frozen?
end
- ruby_version_is ''...'3.0' do
- it "returns a subclass instance" do
- StringSpecs::MyString.new.dump.should be_an_instance_of(StringSpecs::MyString)
- end
- end
-
- ruby_version_is '3.0' do
- it "returns a String instance" do
- StringSpecs::MyString.new.dump.should be_an_instance_of(String)
- end
+ it "returns a String instance" do
+ StringSpecs::MyString.new.dump.should be_an_instance_of(String)
end
it "wraps string with \"" do
@@ -362,7 +342,7 @@ describe "String#dump" do
].should be_computed_by(:dump)
end
- it "returns a string with multi-byte UTF-8 characters replaced by \\u{} notation with upper-case hex digits" do
+ it "returns a string with multi-byte UTF-8 characters less than or equal 0xFFFF replaced by \\uXXXX notation with upper-case hex digits" do
[ [0200.chr('utf-8'), '"\u0080"'],
[0201.chr('utf-8'), '"\u0081"'],
[0202.chr('utf-8'), '"\u0082"'],
@@ -394,15 +374,21 @@ describe "String#dump" do
[0235.chr('utf-8'), '"\u009D"'],
[0236.chr('utf-8'), '"\u009E"'],
[0237.chr('utf-8'), '"\u009F"'],
+ [0177777.chr('utf-8'), '"\uFFFF"'],
].should be_computed_by(:dump)
end
+ it "returns a string with multi-byte UTF-8 characters greater than 0xFFFF replaced by \\u{XXXXXX} notation with upper-case hex digits" do
+ 0x10000.chr('utf-8').dump.should == '"\u{10000}"'
+ 0x10FFFF.chr('utf-8').dump.should == '"\u{10FFFF}"'
+ end
+
it "includes .force_encoding(name) if the encoding isn't ASCII compatible" do
"\u{876}".encode('utf-16be').dump.should.end_with?(".force_encoding(\"UTF-16BE\")")
"\u{876}".encode('utf-16le').dump.should.end_with?(".force_encoding(\"UTF-16LE\")")
end
- it "keeps origin encoding" do
+ it "returns a String in the same encoding as self" do
"foo".encode("ISO-8859-1").dump.encoding.should == Encoding::ISO_8859_1
"foo".encode('windows-1251').dump.encoding.should == Encoding::Windows_1251
1.chr.dump.encoding.should == Encoding::US_ASCII
diff --git a/spec/ruby/core/string/dup_spec.rb b/spec/ruby/core/string/dup_spec.rb
index d650788210..073802d84b 100644
--- a/spec/ruby/core/string/dup_spec.rb
+++ b/spec/ruby/core/string/dup_spec.rb
@@ -49,4 +49,17 @@ describe "String#dup" do
orig.should == "xtring"
dup.should == "string"
end
+
+ it "does not modify the original setbyte-mutated string when changing dupped string" do
+ orig = +"a"
+ orig.setbyte 0, "b".ord
+ copy = orig.dup
+ orig.setbyte 0, "c".ord
+ orig.should == "c"
+ copy.should == "b"
+ end
+
+ it "returns a String in the same encoding as self" do
+ "hello".encode("US-ASCII").dup.encoding.should == Encoding::US_ASCII
+ end
end
diff --git a/spec/ruby/core/string/each_byte_spec.rb b/spec/ruby/core/string/each_byte_spec.rb
index e04dca807f..7b3db265ac 100644
--- a/spec/ruby/core/string/each_byte_spec.rb
+++ b/spec/ruby/core/string/each_byte_spec.rb
@@ -9,26 +9,26 @@ describe "String#each_byte" do
end
it "keeps iterating from the old position (to new string end) when self changes" do
- r = ""
- s = "hello world"
+ r = +""
+ s = +"hello world"
s.each_byte do |c|
r << c
s.insert(0, "<>") if r.size < 3
end
r.should == "h><>hello world"
- r = ""
- s = "hello world"
+ r = +""
+ s = +"hello world"
s.each_byte { |c| s.slice!(-1); r << c }
r.should == "hello "
- r = ""
- s = "hello world"
+ r = +""
+ s = +"hello world"
s.each_byte { |c| s.slice!(0); r << c }
r.should == "hlowrd"
- r = ""
- s = "hello world"
+ r = +""
+ s = +"hello world"
s.each_byte { |c| s.slice!(0..-1); r << c }
r.should == "h"
end
diff --git a/spec/ruby/core/string/each_char_spec.rb b/spec/ruby/core/string/each_char_spec.rb
index aff98c0a5c..36219f79db 100644
--- a/spec/ruby/core/string/each_char_spec.rb
+++ b/spec/ruby/core/string/each_char_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../spec_helper"
require_relative 'shared/chars'
require_relative 'shared/each_char_without_block'
diff --git a/spec/ruby/core/string/each_grapheme_cluster_spec.rb b/spec/ruby/core/string/each_grapheme_cluster_spec.rb
index b45d89ecb0..e1fa4ae67b 100644
--- a/spec/ruby/core/string/each_grapheme_cluster_spec.rb
+++ b/spec/ruby/core/string/each_grapheme_cluster_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../spec_helper"
require_relative 'shared/chars'
require_relative 'shared/grapheme_clusters'
require_relative 'shared/each_char_without_block'
@@ -7,11 +8,9 @@ describe "String#each_grapheme_cluster" do
it_behaves_like :string_grapheme_clusters, :each_grapheme_cluster
it_behaves_like :string_each_char_without_block, :each_grapheme_cluster
- ruby_version_is '3.0' do
- it "yields String instances for subclasses" do
- a = []
- StringSpecs::MyString.new("abc").each_grapheme_cluster { |s| a << s.class }
- a.should == [String, String, String]
- end
+ it "yields String instances for subclasses" do
+ a = []
+ StringSpecs::MyString.new("abc").each_grapheme_cluster { |s| a << s.class }
+ a.should == [String, String, String]
end
end
diff --git a/spec/ruby/core/string/element_set_spec.rb b/spec/ruby/core/string/element_set_spec.rb
index 0aabbacd0e..e7599f832c 100644
--- a/spec/ruby/core/string/element_set_spec.rb
+++ b/spec/ruby/core/string/element_set_spec.rb
@@ -1,4 +1,5 @@
# -*- encoding: utf-8 -*-
+# frozen_string_literal: false
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
@@ -14,18 +15,6 @@ describe "String#[]= with Integer index" do
a.should == "bamelo"
end
- ruby_version_is ''...'2.7' do
- it "taints self if other_str is tainted" do
- a = "hello"
- a[0] = "".taint
- a.should.tainted?
-
- a = "hello"
- a[0] = "x".taint
- a.should.tainted?
- end
- end
-
it "raises an IndexError without changing self if idx is outside of self" do
str = "hello"
@@ -369,11 +358,11 @@ describe "String#[]= with a Range index" do
end
it "raises a RangeError if negative Range begin is out of range" do
- -> { "abc"[-4..-2] = "x" }.should raise_error(RangeError)
+ -> { "abc"[-4..-2] = "x" }.should raise_error(RangeError, "-4..-2 out of range")
end
it "raises a RangeError if positive Range begin is greater than String size" do
- -> { "abc"[4..2] = "x" }.should raise_error(RangeError)
+ -> { "abc"[4..2] = "x" }.should raise_error(RangeError, "4..2 out of range")
end
it "uses the Range end as an index rather than a count" do
@@ -493,18 +482,6 @@ describe "String#[]= with Integer index, count" do
a.should == "hellobob"
end
- ruby_version_is ''...'2.7' do
- it "taints self if other_str is tainted" do
- a = "hello"
- a[0, 0] = "".taint
- a.should.tainted?
-
- a = "hello"
- a[1, 4] = "x".taint
- a.should.tainted?
- end
- end
-
it "calls #to_int to convert the index and count objects" do
index = mock("string element set index")
index.should_receive(:to_int).and_return(-4)
diff --git a/spec/ruby/core/string/encode_spec.rb b/spec/ruby/core/string/encode_spec.rb
index 5604ab7210..97dd753b62 100644
--- a/spec/ruby/core/string/encode_spec.rb
+++ b/spec/ruby/core/string/encode_spec.rb
@@ -34,8 +34,8 @@ describe "String#encode" do
it "encodes an ascii substring of a binary string to UTF-8" do
x82 = [0x82].pack('C')
- str = "#{x82}foo".force_encoding("binary")[1..-1].encode("utf-8")
- str.should == "foo".force_encoding("utf-8")
+ str = "#{x82}foo".dup.force_encoding("binary")[1..-1].encode("utf-8")
+ str.should == "foo".dup.force_encoding("utf-8")
str.encoding.should equal(Encoding::UTF_8)
end
end
@@ -49,7 +49,7 @@ describe "String#encode" do
end
it "round trips a String" do
- str = "abc def".force_encoding Encoding::US_ASCII
+ str = "abc def".dup.force_encoding Encoding::US_ASCII
str.encode("utf-32be").encode("ascii").should == "abc def"
end
end
@@ -79,6 +79,10 @@ describe "String#encode" do
encoded.encode("UTF-8").should == "ちfoofoo"
end
+ it "replace multiple invalid bytes at the end with a single replacement character" do
+ "\xE3\x81\x93\xE3\x81".encode("UTF-8", invalid: :replace).should == "\u3053\ufffd"
+ end
+
it "replaces invalid encoding in source using a specified replacement even when a fallback is given" do
encoded = "ち\xE3\x81\xFF".encode("UTF-16LE", invalid: :replace, replace: "foo", fallback: -> c { "bar" })
encoded.should == "\u3061foofoo".encode("UTF-16LE")
@@ -118,8 +122,7 @@ describe "String#encode" do
describe "when passed to, from" do
it "returns a copy in the destination encoding when both encodings are the same" do
- str = "あ"
- str.force_encoding("binary")
+ str = "あ".dup.force_encoding("binary")
encoded = str.encode("utf-8", "utf-8")
encoded.should_not equal(str)
@@ -151,8 +154,7 @@ describe "String#encode" do
end
it "returns a copy in the destination encoding when both encodings are the same" do
- str = "あ"
- str.force_encoding("binary")
+ str = "あ".dup.force_encoding("binary")
encoded = str.encode("utf-8", "utf-8", invalid: :replace)
encoded.should_not equal(str)
@@ -187,13 +189,13 @@ describe "String#encode!" do
describe "when passed no options" do
it "returns self when Encoding.default_internal is nil" do
Encoding.default_internal = nil
- str = "あ"
+ str = +"あ"
str.encode!.should equal(str)
end
it "returns self for a ASCII-only String when Encoding.default_internal is nil" do
Encoding.default_internal = nil
- str = "abc"
+ str = +"abc"
str.encode!.should equal(str)
end
end
@@ -201,14 +203,14 @@ describe "String#encode!" do
describe "when passed options" do
it "returns self for ASCII-only String when Encoding.default_internal is nil" do
Encoding.default_internal = nil
- str = "abc"
+ str = +"abc"
str.encode!(invalid: :replace).should equal(str)
end
end
describe "when passed to encoding" do
it "returns self" do
- str = "abc"
+ str = +"abc"
result = str.encode!(Encoding::BINARY)
result.encoding.should equal(Encoding::BINARY)
result.should equal(str)
@@ -217,7 +219,7 @@ describe "String#encode!" do
describe "when passed to, from" do
it "returns self" do
- str = "ああ"
+ str = +"ああ"
result = str.encode!("euc-jp", "utf-8")
result.encoding.should equal(Encoding::EUC_JP)
result.should equal(str)
diff --git a/spec/ruby/core/string/encoding_spec.rb b/spec/ruby/core/string/encoding_spec.rb
index 4d17a39f29..f6e8fd3470 100644
--- a/spec/ruby/core/string/encoding_spec.rb
+++ b/spec/ruby/core/string/encoding_spec.rb
@@ -10,14 +10,15 @@ describe "String#encoding" do
it "is equal to the source encoding by default" do
s = StringSpecs::ISO88599Encoding.new
s.cedilla.encoding.should == s.source_encoding
+ s.cedilla.encode("utf-8").should == 350.chr(Encoding::UTF_8) # S-cedilla
end
it "returns the given encoding if #force_encoding has been called" do
- "a".force_encoding(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
+ "a".dup.force_encoding(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
end
it "returns the given encoding if #encode!has been called" do
- "a".encode!(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
+ "a".dup.encode!(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
end
end
@@ -107,13 +108,13 @@ describe "String#encoding for Strings with \\u escapes" do
end
it "returns the given encoding if #force_encoding has been called" do
- "\u{20}".force_encoding(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
- "\u{2020}".force_encoding(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
+ "\u{20}".dup.force_encoding(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
+ "\u{2020}".dup.force_encoding(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
end
it "returns the given encoding if #encode!has been called" do
- "\u{20}".encode!(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
- "\u{2020}".encode!(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
+ "\u{20}".dup.encode!(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
+ "\u{2020}".dup.encode!(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
end
end
@@ -172,16 +173,12 @@ describe "String#encoding for Strings with \\x escapes" do
end
it "returns the given encoding if #force_encoding has been called" do
- x50 = "\x50"
- x50.force_encoding(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
- xD4 = [212].pack('C')
- xD4.force_encoding(Encoding::ISO_8859_9).encoding.should == Encoding::ISO_8859_9
+ "\x50".dup.force_encoding(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
+ [212].pack('C').force_encoding(Encoding::ISO_8859_9).encoding.should == Encoding::ISO_8859_9
end
it "returns the given encoding if #encode!has been called" do
- x50 = "\x50"
- x50.encode!(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
- x00 = "x\00"
- x00.encode!(Encoding::UTF_8).encoding.should == Encoding::UTF_8
+ "\x50".dup.encode!(Encoding::SHIFT_JIS).encoding.should == Encoding::SHIFT_JIS
+ "x\00".dup.encode!(Encoding::UTF_8).encoding.should == Encoding::UTF_8
end
end
diff --git a/spec/ruby/core/string/fixtures/iso-8859-9-encoding.rb b/spec/ruby/core/string/fixtures/iso-8859-9-encoding.rb
index 61a691ff78..cfa91dedc3 100644
--- a/spec/ruby/core/string/fixtures/iso-8859-9-encoding.rb
+++ b/spec/ruby/core/string/fixtures/iso-8859-9-encoding.rb
@@ -4,6 +4,6 @@ module StringSpecs
def source_encoding; __ENCODING__; end
def x_escape; [0xDF].pack('C').force_encoding("iso-8859-9"); end
def ascii_only; "glark"; end
- def cedilla; "Ş"; end
+ def cedilla; ""; end # S-cedilla
end
end
diff --git a/spec/ruby/core/string/fixtures/to_c.rb b/spec/ruby/core/string/fixtures/to_c.rb
new file mode 100644
index 0000000000..7776933263
--- /dev/null
+++ b/spec/ruby/core/string/fixtures/to_c.rb
@@ -0,0 +1,5 @@
+module StringSpecs
+ def self.to_c_method(string)
+ string.to_c
+ end
+end
diff --git a/spec/ruby/core/string/fixtures/utf-8-encoding.rb b/spec/ruby/core/string/fixtures/utf-8-encoding.rb
deleted file mode 100644
index fd243ec522..0000000000
--- a/spec/ruby/core/string/fixtures/utf-8-encoding.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-# -*- encoding: utf-8 -*-
-module StringSpecs
- class UTF8Encoding
- def self.source_encoding; __ENCODING__; end
- def self.egrave; "é"; end
- end
-end
diff --git a/spec/ruby/core/string/force_encoding_spec.rb b/spec/ruby/core/string/force_encoding_spec.rb
index f37aaf9eb4..2259dcf3cf 100644
--- a/spec/ruby/core/string/force_encoding_spec.rb
+++ b/spec/ruby/core/string/force_encoding_spec.rb
@@ -1,3 +1,4 @@
+# frozen_string_literal: false
require_relative '../../spec_helper'
describe "String#force_encoding" do
diff --git a/spec/ruby/core/string/freeze_spec.rb b/spec/ruby/core/string/freeze_spec.rb
index 04d1e9513c..2e8e70386d 100644
--- a/spec/ruby/core/string/freeze_spec.rb
+++ b/spec/ruby/core/string/freeze_spec.rb
@@ -1,3 +1,4 @@
+# frozen_string_literal: false
require_relative '../../spec_helper'
describe "String#freeze" do
diff --git a/spec/ruby/core/string/grapheme_clusters_spec.rb b/spec/ruby/core/string/grapheme_clusters_spec.rb
index 3046265a12..380a245083 100644
--- a/spec/ruby/core/string/grapheme_clusters_spec.rb
+++ b/spec/ruby/core/string/grapheme_clusters_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../spec_helper"
require_relative 'shared/chars'
require_relative 'shared/grapheme_clusters'
diff --git a/spec/ruby/core/string/gsub_spec.rb b/spec/ruby/core/string/gsub_spec.rb
index ad41b7e0a2..0d9f32eca2 100644
--- a/spec/ruby/core/string/gsub_spec.rb
+++ b/spec/ruby/core/string/gsub_spec.rb
@@ -1,4 +1,5 @@
# -*- encoding: utf-8 -*-
+# frozen_string_literal: false
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
@@ -160,56 +161,12 @@ describe "String#gsub with pattern and replacement" do
it_behaves_like :string_gsub_named_capture, :gsub
- ruby_version_is ''...'2.7' do
- it "taints the result if the original string or replacement is tainted" do
- hello = "hello"
- hello_t = "hello"
- a = "a"
- a_t = "a"
- empty = ""
- empty_t = ""
-
- hello_t.taint; a_t.taint; empty_t.taint
-
- hello_t.gsub(/./, a).should.tainted?
- hello_t.gsub(/./, empty).should.tainted?
-
- hello.gsub(/./, a_t).should.tainted?
- hello.gsub(/./, empty_t).should.tainted?
- hello.gsub(//, empty_t).should.tainted?
-
- hello.gsub(//.taint, "foo").should_not.tainted?
- end
- end
-
it "handles pattern collapse" do
str = "こにちわ"
reg = %r!!
str.gsub(reg, ".").should == ".こ.に.ち.わ."
end
- ruby_version_is ''...'2.7' do
- it "untrusts the result if the original string or replacement is untrusted" do
- hello = "hello"
- hello_t = "hello"
- a = "a"
- a_t = "a"
- empty = ""
- empty_t = ""
-
- hello_t.untrust; a_t.untrust; empty_t.untrust
-
- hello_t.gsub(/./, a).should.untrusted?
- hello_t.gsub(/./, empty).should.untrusted?
-
- hello.gsub(/./, a_t).should.untrusted?
- hello.gsub(/./, empty_t).should.untrusted?
- hello.gsub(//, empty_t).should.untrusted?
-
- hello.gsub(//.untrust, "foo").should_not.untrusted?
- end
- end
-
it "tries to convert pattern to a string using to_str" do
pattern = mock('.')
def pattern.to_str() "." end
@@ -236,26 +193,13 @@ describe "String#gsub with pattern and replacement" do
-> { "hello".gsub(/[aeiou]/, nil) }.should raise_error(TypeError)
end
- ruby_version_is ''...'3.0' do
- it "returns subclass instances when called on a subclass" do
- StringSpecs::MyString.new("").gsub(//, "").should be_an_instance_of(StringSpecs::MyString)
- StringSpecs::MyString.new("").gsub(/foo/, "").should be_an_instance_of(StringSpecs::MyString)
- StringSpecs::MyString.new("foo").gsub(/foo/, "").should be_an_instance_of(StringSpecs::MyString)
- StringSpecs::MyString.new("foo").gsub("foo", "").should be_an_instance_of(StringSpecs::MyString)
- end
+ it "returns String instances when called on a subclass" do
+ StringSpecs::MyString.new("").gsub(//, "").should be_an_instance_of(String)
+ StringSpecs::MyString.new("").gsub(/foo/, "").should be_an_instance_of(String)
+ StringSpecs::MyString.new("foo").gsub(/foo/, "").should be_an_instance_of(String)
+ StringSpecs::MyString.new("foo").gsub("foo", "").should be_an_instance_of(String)
end
- ruby_version_is '3.0' do
- it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new("").gsub(//, "").should be_an_instance_of(String)
- StringSpecs::MyString.new("").gsub(/foo/, "").should be_an_instance_of(String)
- StringSpecs::MyString.new("foo").gsub(/foo/, "").should be_an_instance_of(String)
- StringSpecs::MyString.new("foo").gsub("foo", "").should be_an_instance_of(String)
- end
- end
-
- # Note: $~ cannot be tested because mspec messes with it
-
it "sets $~ to MatchData of last match and nil when there's none" do
'hello.'.gsub('hello', 'x')
$~[0].should == 'hello'
@@ -269,6 +213,18 @@ describe "String#gsub with pattern and replacement" do
'hello.'.gsub(/not/, 'x')
$~.should == nil
end
+
+ it "handles a pattern in a superset encoding" do
+ result = 'abc'.force_encoding(Encoding::US_ASCII).gsub('é', 'è')
+ result.should == 'abc'
+ result.encoding.should == Encoding::US_ASCII
+ end
+
+ it "handles a pattern in a subset encoding" do
+ result = 'été'.gsub('t'.force_encoding(Encoding::US_ASCII), 'u')
+ result.should == 'éué'
+ result.encoding.should == Encoding::UTF_8
+ end
end
describe "String#gsub with pattern and Hash" do
@@ -336,28 +292,6 @@ describe "String#gsub with pattern and Hash" do
repl = '\& \0 \1 \` \\\' \+ \\\\ foo'
"hello".gsub(/(.+)/, 'hello' => repl ).should == repl
end
-
- ruby_version_is ''...'2.7' do
- it "untrusts the result if the original string is untrusted" do
- str = "Ghana".untrust
- str.gsub(/[Aa]na/, 'ana' => '').untrusted?.should be_true
- end
-
- it "untrusts the result if a hash value is untrusted" do
- str = "Ghana"
- str.gsub(/a$/, 'a' => 'di'.untrust).untrusted?.should be_true
- end
-
- it "taints the result if the original string is tainted" do
- str = "Ghana".taint
- str.gsub(/[Aa]na/, 'ana' => '').tainted?.should be_true
- end
-
- it "taints the result if a hash value is tainted" do
- str = "Ghana"
- str.gsub(/a$/, 'a' => 'di'.taint).tainted?.should be_true
- end
- end
end
describe "String#gsub! with pattern and Hash" do
@@ -426,28 +360,6 @@ describe "String#gsub! with pattern and Hash" do
repl = '\& \0 \1 \` \\\' \+ \\\\ foo'
"hello".gsub!(/(.+)/, 'hello' => repl ).should == repl
end
-
- ruby_version_is ''...'2.7' do
- it "keeps untrusted state" do
- str = "Ghana".untrust
- str.gsub!(/[Aa]na/, 'ana' => '').untrusted?.should be_true
- end
-
- it "untrusts self if a hash value is untrusted" do
- str = "Ghana"
- str.gsub!(/a$/, 'a' => 'di'.untrust).untrusted?.should be_true
- end
-
- it "keeps tainted state" do
- str = "Ghana".taint
- str.gsub!(/[Aa]na/, 'ana' => '').tainted?.should be_true
- end
-
- it "taints self if a hash value is tainted" do
- str = "Ghana"
- str.gsub!(/a$/, 'a' => 'di'.taint).tainted?.should be_true
- end
- end
end
describe "String#gsub with pattern and block" do
@@ -526,28 +438,6 @@ describe "String#gsub with pattern and block" do
"hello".gsub(/.+/) { obj }.should == "ok"
end
- ruby_version_is ''...'2.7' do
- it "untrusts the result if the original string or replacement is untrusted" do
- hello = "hello"
- hello_t = "hello"
- a = "a"
- a_t = "a"
- empty = ""
- empty_t = ""
-
- hello_t.untrust; a_t.untrust; empty_t.untrust
-
- hello_t.gsub(/./) { a }.should.untrusted?
- hello_t.gsub(/./) { empty }.should.untrusted?
-
- hello.gsub(/./) { a_t }.should.untrusted?
- hello.gsub(/./) { empty_t }.should.untrusted?
- hello.gsub(//) { empty_t }.should.untrusted?
-
- hello.gsub(//.untrust) { "foo" }.should_not.untrusted?
- end
- end
-
it "uses the compatible encoding if they are compatible" do
s = "hello"
s2 = "#{195.chr}#{192.chr}#{195.chr}"
@@ -615,20 +505,6 @@ describe "String#gsub! with pattern and replacement" do
a.should == "*¿** **é*?*"
end
- ruby_version_is ''...'2.7' do
- it "taints self if replacement is tainted" do
- a = "hello"
- a.gsub!(/./.taint, "foo").should_not.tainted?
- a.gsub!(/./, "foo".taint).should.tainted?
- end
-
- it "untrusts self if replacement is untrusted" do
- a = "hello"
- a.gsub!(/./.untrust, "foo").should_not.untrusted?
- a.gsub!(/./, "foo".untrust).should.untrusted?
- end
- end
-
it "returns nil if no modifications were made" do
a = "hello"
a.gsub!(/z/, '*').should == nil
@@ -645,6 +521,27 @@ describe "String#gsub! with pattern and replacement" do
-> { s.gsub!(/e/, "e") }.should raise_error(FrozenError)
-> { s.gsub!(/[aeiou]/, '*') }.should raise_error(FrozenError)
end
+
+ it "handles a pattern in a superset encoding" do
+ string = 'abc'.force_encoding(Encoding::US_ASCII)
+
+ result = string.gsub!('é', 'è')
+
+ result.should == nil
+ string.should == 'abc'
+ string.encoding.should == Encoding::US_ASCII
+ end
+
+ it "handles a pattern in a subset encoding" do
+ string = 'été'
+ pattern = 't'.force_encoding(Encoding::US_ASCII)
+
+ result = string.gsub!(pattern, 'u')
+
+ result.should == string
+ string.should == 'éué'
+ string.encoding.should == Encoding::UTF_8
+ end
end
describe "String#gsub! with pattern and block" do
@@ -654,20 +551,6 @@ describe "String#gsub! with pattern and block" do
a.should == "h*ll*"
end
- ruby_version_is ''...'2.7' do
- it "taints self if block's result is tainted" do
- a = "hello"
- a.gsub!(/./.taint) { "foo" }.should_not.tainted?
- a.gsub!(/./) { "foo".taint }.should.tainted?
- end
-
- it "untrusts self if block's result is untrusted" do
- a = "hello"
- a.gsub!(/./.untrust) { "foo" }.should_not.untrusted?
- a.gsub!(/./) { "foo".untrust }.should.untrusted?
- end
- end
-
it "returns nil if no modifications were made" do
a = "hello"
a.gsub!(/z/) { '*' }.should == nil
diff --git a/spec/ruby/core/string/include_spec.rb b/spec/ruby/core/string/include_spec.rb
index e32eb17c29..9781140a55 100644
--- a/spec/ruby/core/string/include_spec.rb
+++ b/spec/ruby/core/string/include_spec.rb
@@ -13,6 +13,20 @@ describe "String#include? with String" do
StringSpecs::MyString.new("hello").include?(StringSpecs::MyString.new("lo")).should == true
end
+ it "returns true if both strings are empty" do
+ "".should.include?("")
+ "".dup.force_encoding("EUC-JP").should.include?("")
+ "".should.include?("".dup.force_encoding("EUC-JP"))
+ "".dup.force_encoding("EUC-JP").should.include?("".dup.force_encoding("EUC-JP"))
+ end
+
+ it "returns true if the RHS is empty" do
+ "a".should.include?("")
+ "a".dup.force_encoding("EUC-JP").should.include?("")
+ "a".should.include?("".dup.force_encoding("EUC-JP"))
+ "a".dup.force_encoding("EUC-JP").should.include?("".dup.force_encoding("EUC-JP"))
+ end
+
it "tries to convert other to string using to_str" do
other = mock('lo')
other.should_receive(:to_str).and_return("lo")
diff --git a/spec/ruby/core/string/index_spec.rb b/spec/ruby/core/string/index_spec.rb
index 5d77a88e4e..be79708045 100644
--- a/spec/ruby/core/string/index_spec.rb
+++ b/spec/ruby/core/string/index_spec.rb
@@ -159,6 +159,21 @@ describe "String#index with String" do
"あれ".index char
end.should raise_error(Encoding::CompatibilityError)
end
+
+ it "handles a substring in a superset encoding" do
+ 'abc'.dup.force_encoding(Encoding::US_ASCII).index('é').should == nil
+ end
+
+ it "handles a substring in a subset encoding" do
+ 'été'.index('t'.dup.force_encoding(Encoding::US_ASCII)).should == 1
+ end
+
+ it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
+ str = 'abc'.dup.force_encoding("ISO-2022-JP")
+ pattern = 'b'.dup.force_encoding("EUC-JP")
+
+ -> { str.index(pattern) }.should raise_error(Encoding::CompatibilityError, "incompatible character encodings: ISO-2022-JP and EUC-JP")
+ end
end
describe "String#index with Regexp" do
@@ -304,6 +319,17 @@ describe "String#index with Regexp" do
"われわわれ".index(/わ/, 3).should == 3
end
+ ruby_bug "#19763", ""..."3.3.0" do
+ it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
+ re = Regexp.new "れ".encode(Encoding::EUC_JP)
+ -> do
+ "あれ".index re
+ end.should raise_error(Encoding::CompatibilityError, "incompatible encoding regexp match (EUC-JP regexp with UTF-8 string)")
+ end
+ end
+
+ # The exception message was incorrectly "incompatible character encodings: UTF-8 and EUC-JP" before 3.3.0
+ # Still test that the right exception class is used before that.
it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
re = Regexp.new "れ".encode(Encoding::EUC_JP)
-> do
diff --git a/spec/ruby/core/string/insert_spec.rb b/spec/ruby/core/string/insert_spec.rb
index 752cbb2f37..483f3c9367 100644
--- a/spec/ruby/core/string/insert_spec.rb
+++ b/spec/ruby/core/string/insert_spec.rb
@@ -1,5 +1,5 @@
# -*- encoding: utf-8 -*-
-
+# frozen_string_literal: false
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
@@ -41,18 +41,6 @@ describe "String#insert with index, other" do
"abcd".insert(-3, other).should == "abXYZcd"
end
- ruby_version_is ''...'2.7' do
- it "taints self if string to insert is tainted" do
- str = "abcd"
- str.insert(0, "T".taint).should.tainted?
-
- str = "abcd"
- other = mock('T')
- def other.to_str() "T".taint end
- str.insert(0, other).should.tainted?
- end
- end
-
it "raises a TypeError if other can't be converted to string" do
-> { "abcd".insert(-6, Object.new)}.should raise_error(TypeError)
-> { "abcd".insert(-6, []) }.should raise_error(TypeError)
@@ -81,4 +69,13 @@ describe "String#insert with index, other" do
"あれ".insert 0, pat
end.should raise_error(Encoding::CompatibilityError)
end
+
+ it "should not call subclassed string methods" do
+ cls = Class.new(String) do
+ def replace(arg)
+ raise "should not call replace"
+ end
+ end
+ cls.new("abcd").insert(0, 'X').should == "Xabcd"
+ end
end
diff --git a/spec/ruby/core/string/inspect_spec.rb b/spec/ruby/core/string/inspect_spec.rb
index 98b5b32b61..15db06c7f5 100644
--- a/spec/ruby/core/string/inspect_spec.rb
+++ b/spec/ruby/core/string/inspect_spec.rb
@@ -3,18 +3,6 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "String#inspect" do
- ruby_version_is ''...'2.7' do
- it "taints the result if self is tainted" do
- "foo".taint.inspect.should.tainted?
- "foo\n".taint.inspect.should.tainted?
- end
-
- it "untrusts the result if self is untrusted" do
- "foo".untrust.inspect.should.untrusted?
- "foo\n".untrust.inspect.should.untrusted?
- end
- end
-
it "does not return a subclass instance" do
StringSpecs::MyString.new.inspect.should be_an_instance_of(String)
end
@@ -31,6 +19,21 @@ describe "String#inspect" do
].should be_computed_by(:inspect)
end
+ it "returns a string with special characters replaced with \\<char> notation for UTF-16" do
+ pairs = [
+ ["\a", '"\\a"'],
+ ["\b", '"\\b"'],
+ ["\t", '"\\t"'],
+ ["\n", '"\\n"'],
+ ["\v", '"\\v"'],
+ ["\f", '"\\f"'],
+ ["\r", '"\\r"'],
+ ["\e", '"\\e"']
+ ].map { |str, result| [str.encode('UTF-16LE'), result] }
+
+ pairs.should be_computed_by(:inspect)
+ end
+
it "returns a string with \" and \\ escaped with a backslash" do
[ ["\"", '"\\""'],
["\\", '"\\\\"']
@@ -323,6 +326,11 @@ describe "String#inspect" do
"\xF0\x9F".inspect.should == '"\\xF0\\x9F"'
end
+ it "works for broken US-ASCII strings" do
+ s = "©".dup.force_encoding("US-ASCII")
+ s.inspect.should == '"\xC2\xA9"'
+ end
+
describe "when default external is UTF-8" do
before :each do
@extenc, Encoding.default_external = Encoding.default_external, Encoding::UTF_8
diff --git a/spec/ruby/core/string/lines_spec.rb b/spec/ruby/core/string/lines_spec.rb
index ad4b119074..40ab5f71d8 100644
--- a/spec/ruby/core/string/lines_spec.rb
+++ b/spec/ruby/core/string/lines_spec.rb
@@ -1,7 +1,6 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
require_relative 'shared/each_line'
-require_relative 'shared/each_line_without_block'
describe "String#lines" do
it_behaves_like :string_each_line, :lines
diff --git a/spec/ruby/core/string/ljust_spec.rb b/spec/ruby/core/string/ljust_spec.rb
index 0c3b2a2f44..47324c59d2 100644
--- a/spec/ruby/core/string/ljust_spec.rb
+++ b/spec/ruby/core/string/ljust_spec.rb
@@ -31,16 +31,6 @@ describe "String#ljust with length, padding" do
"radiology".ljust(8, '-').should == "radiology"
end
- ruby_version_is ''...'2.7' do
- it "taints result when self or padstr is tainted" do
- "x".taint.ljust(4).should.tainted?
- "x".taint.ljust(0).should.tainted?
- "".taint.ljust(0).should.tainted?
- "x".taint.ljust(4, "*").should.tainted?
- "x".ljust(4, "*".taint).should.tainted?
- end
- end
-
it "tries to convert length to an integer using to_int" do
"^".ljust(3.8, "_^").should == "^_^"
@@ -74,39 +64,18 @@ describe "String#ljust with length, padding" do
-> { "hello".ljust(10, '') }.should raise_error(ArgumentError)
end
- ruby_version_is ''...'3.0' do
- it "returns subclass instances when called on subclasses" do
- StringSpecs::MyString.new("").ljust(10).should be_an_instance_of(StringSpecs::MyString)
- StringSpecs::MyString.new("foo").ljust(10).should be_an_instance_of(StringSpecs::MyString)
- StringSpecs::MyString.new("foo").ljust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(StringSpecs::MyString)
-
- "".ljust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
- "foo".ljust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
- end
- end
+ it "returns String instances when called on subclasses" do
+ StringSpecs::MyString.new("").ljust(10).should be_an_instance_of(String)
+ StringSpecs::MyString.new("foo").ljust(10).should be_an_instance_of(String)
+ StringSpecs::MyString.new("foo").ljust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
- ruby_version_is '3.0' do
- it "returns String instances when called on subclasses" do
- StringSpecs::MyString.new("").ljust(10).should be_an_instance_of(String)
- StringSpecs::MyString.new("foo").ljust(10).should be_an_instance_of(String)
- StringSpecs::MyString.new("foo").ljust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
-
- "".ljust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
- "foo".ljust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
- end
- end
-
- ruby_version_is ''...'2.7' do
- it "when padding is tainted and self is untainted returns a tainted string if and only if length is longer than self" do
- "hello".ljust(4, 'X'.taint).tainted?.should be_false
- "hello".ljust(5, 'X'.taint).tainted?.should be_false
- "hello".ljust(6, 'X'.taint).tainted?.should be_true
- end
+ "".ljust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
+ "foo".ljust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
end
describe "with width" do
it "returns a String in the same encoding as the original" do
- str = "abc".force_encoding Encoding::IBM437
+ str = "abc".dup.force_encoding Encoding::IBM437
result = str.ljust 5
result.should == "abc "
result.encoding.should equal(Encoding::IBM437)
@@ -115,7 +84,7 @@ describe "String#ljust with length, padding" do
describe "with width, pattern" do
it "returns a String in the compatible encoding" do
- str = "abc".force_encoding Encoding::IBM437
+ str = "abc".dup.force_encoding Encoding::IBM437
result = str.ljust 5, "あ"
result.should == "abcああ"
result.encoding.should equal(Encoding::UTF_8)
diff --git a/spec/ruby/core/string/lstrip_spec.rb b/spec/ruby/core/string/lstrip_spec.rb
index 20e4cdeabd..99bab6f349 100644
--- a/spec/ruby/core/string/lstrip_spec.rb
+++ b/spec/ruby/core/string/lstrip_spec.rb
@@ -1,3 +1,4 @@
+# frozen_string_literal: false
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
require_relative 'shared/strip'
@@ -10,21 +11,19 @@ describe "String#lstrip" do
" hello world ".lstrip.should == "hello world "
"\n\r\t\n\v\r hello world ".lstrip.should == "hello world "
"hello".lstrip.should == "hello"
+ " こにちわ".lstrip.should == "こにちわ"
end
- ruby_version_is '3.1' do
- it "strips leading \\0" do
- "\x00hello".lstrip.should == "hello"
- "\000 \000hello\000 \000".lstrip.should == "hello\000 \000"
- end
+ it "works with lazy substrings" do
+ " hello "[1...-1].lstrip.should == "hello "
+ " hello world "[1...-1].lstrip.should == "hello world "
+ "\n\r\t\n\v\r hello world "[1...-1].lstrip.should == "hello world "
+ " こにちわ "[1...-1].lstrip.should == "こにちわ"
end
- ruby_version_is ''...'2.7' do
- it "taints the result when self is tainted" do
- "".taint.lstrip.should.tainted?
- "ok".taint.lstrip.should.tainted?
- " ok".taint.lstrip.should.tainted?
- end
+ it "strips leading \\0" do
+ "\x00hello".lstrip.should == "hello"
+ "\000 \000hello\000 \000".lstrip.should == "hello\000 \000"
end
end
@@ -35,20 +34,24 @@ describe "String#lstrip!" do
a.should == "hello "
end
- ruby_version_is '3.1' do
- it "strips leading \\0" do
- a = "\000 \000hello\000 \000"
- a.lstrip!
- a.should == "hello\000 \000"
- end
- end
-
it "returns nil if no modifications were made" do
a = "hello"
a.lstrip!.should == nil
a.should == "hello"
end
+ it "makes a string empty if it is only whitespace" do
+ "".lstrip!.should == nil
+ " ".lstrip.should == ""
+ " ".lstrip.should == ""
+ end
+
+ it "removes leading NULL bytes and whitespace" do
+ a = "\000 \000hello\000 \000"
+ a.lstrip!
+ a.should == "hello\000 \000"
+ end
+
it "raises a FrozenError on a frozen instance that is modified" do
-> { " hello ".freeze.lstrip! }.should raise_error(FrozenError)
end
@@ -58,4 +61,14 @@ describe "String#lstrip!" do
-> { "hello".freeze.lstrip! }.should raise_error(FrozenError)
-> { "".freeze.lstrip! }.should raise_error(FrozenError)
end
+
+ it "raises an ArgumentError if the first non-space codepoint is invalid" do
+ s = "\xDFabc".force_encoding(Encoding::UTF_8)
+ s.valid_encoding?.should be_false
+ -> { s.lstrip! }.should raise_error(ArgumentError)
+
+ s = " \xDFabc".force_encoding(Encoding::UTF_8)
+ s.valid_encoding?.should be_false
+ -> { s.lstrip! }.should raise_error(ArgumentError)
+ end
end
diff --git a/spec/ruby/core/string/modulo_spec.rb b/spec/ruby/core/string/modulo_spec.rb
index dc11ced4e2..bf96a82874 100644
--- a/spec/ruby/core/string/modulo_spec.rb
+++ b/spec/ruby/core/string/modulo_spec.rb
@@ -302,29 +302,6 @@ describe "String#%" do
end
end
- ruby_version_is ''...'2.7' do
- it "always taints the result when the format string is tainted" do
- universal = mock('0')
- def universal.to_int() 0 end
- def universal.to_str() "0" end
- def universal.to_f() 0.0 end
-
- [
- "", "foo",
- "%b", "%B", "%c", "%d", "%e", "%E",
- "%f", "%g", "%G", "%i", "%o", "%p",
- "%s", "%u", "%x", "%X"
- ].each do |format|
- subcls_format = StringSpecs::MyString.new(format)
- subcls_format.taint
- format.taint
-
- (format % universal).should.tainted?
- (subcls_format % universal).should.tainted?
- end
- end
- end
-
it "supports binary formats using %b for positive numbers" do
("%b" % 10).should == "1010"
("% b" % 10).should == " 1010"
@@ -391,8 +368,16 @@ describe "String#%" do
("%c" % 'A').should == "A"
end
- it "raises an exception for multiple character strings as argument for %c" do
- -> { "%c" % 'AA' }.should raise_error(ArgumentError)
+ 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
end
it "calls to_str on argument for %c formats" do
@@ -578,20 +563,6 @@ describe "String#%" do
# ("%p" % obj).should == "obj"
end
- ruby_version_is ''...'2.7' do
- it "taints result for %p when argument.inspect is tainted" do
- obj = mock('x')
- def obj.inspect() "x".taint end
-
- ("%p" % obj).should.tainted?
-
- obj = mock('x'); obj.taint
- def obj.inspect() "x" end
-
- ("%p" % obj).should_not.tainted?
- end
- end
-
it "supports string formats using %s" do
("%s" % "hello").should == "hello"
("%s" % "").should == ""
@@ -620,13 +591,6 @@ describe "String#%" do
# ("%s" % obj).should == "obj"
end
- ruby_version_is ''...'2.7' do
- it "taints result for %s when argument is tainted" do
- ("%s" % "x".taint).should.tainted?
- ("%s" % mock('x').taint).should.tainted?
- end
- end
-
# MRI crashes on this one.
# See http://groups.google.com/group/ruby-core-google/t/c285c18cd94c216d
it "raises an ArgumentError for huge precisions for %s" do
@@ -786,12 +750,6 @@ describe "String#%" do
it "behaves as if calling Kernel#Float for #{format} arguments, when the passed argument is hexadecimal string" do
(format % "0xA").should == (format % 0xA)
end
-
- ruby_version_is ''...'2.7' do
- it "doesn't taint the result for #{format} when argument is tainted" do
- (format % "5".taint).should_not.tainted?
- end
- end
end
describe "when format string contains %{} sections" do
diff --git a/spec/ruby/core/string/ord_spec.rb b/spec/ruby/core/string/ord_spec.rb
index cfc630a124..35af3b5458 100644
--- a/spec/ruby/core/string/ord_spec.rb
+++ b/spec/ruby/core/string/ord_spec.rb
@@ -25,4 +25,9 @@ describe "String#ord" do
it "raises an ArgumentError if called on an empty String" do
-> { ''.ord }.should raise_error(ArgumentError)
end
+
+ it "raises ArgumentError if the character is broken" do
+ s = "©".dup.force_encoding("US-ASCII")
+ -> { s.ord }.should raise_error(ArgumentError, "invalid byte sequence in US-ASCII")
+ end
end
diff --git a/spec/ruby/core/string/partition_spec.rb b/spec/ruby/core/string/partition_spec.rb
index 98311f2be4..d5370dcc73 100644
--- a/spec/ruby/core/string/partition_spec.rb
+++ b/spec/ruby/core/string/partition_spec.rb
@@ -38,4 +38,26 @@ describe "String#partition with String" do
it "takes precedence over a given block" do
"hello world".partition("o") { true }.should == ["hell", "o", " world"]
end
+
+ it "handles a pattern in a superset encoding" do
+ string = "hello".dup.force_encoding(Encoding::US_ASCII)
+
+ result = string.partition("é")
+
+ result.should == ["hello", "", ""]
+ result[0].encoding.should == Encoding::US_ASCII
+ result[1].encoding.should == Encoding::US_ASCII
+ result[2].encoding.should == Encoding::US_ASCII
+ end
+
+ it "handles a pattern in a subset encoding" do
+ pattern = "o".dup.force_encoding(Encoding::US_ASCII)
+
+ result = "héllo world".partition(pattern)
+
+ result.should == ["héll", "o", " world"]
+ result[0].encoding.should == Encoding::UTF_8
+ result[1].encoding.should == Encoding::US_ASCII
+ result[2].encoding.should == Encoding::UTF_8
+ end
end
diff --git a/spec/ruby/core/string/plus_spec.rb b/spec/ruby/core/string/plus_spec.rb
index 9f0db6427c..9da17451c6 100644
--- a/spec/ruby/core/string/plus_spec.rb
+++ b/spec/ruby/core/string/plus_spec.rb
@@ -3,6 +3,9 @@ require_relative 'fixtures/classes'
require_relative 'shared/concat'
describe "String#+" do
+ it_behaves_like :string_concat_encoding, :+
+ it_behaves_like :string_concat_type_coercion, :+
+
it "returns a new string containing the given string concatenated to self" do
("" + "").should == ""
("" + "Hello").should == "Hello"
@@ -31,19 +34,4 @@ describe "String#+" do
("hello" + StringSpecs::MyString.new("foo")).should be_an_instance_of(String)
("hello" + StringSpecs::MyString.new("")).should be_an_instance_of(String)
end
-
- ruby_version_is ''...'2.7' do
- it "taints the result when self or other is tainted" do
- strs = ["", "OK", StringSpecs::MyString.new(""), StringSpecs::MyString.new("OK")]
- strs += strs.map { |s| s.dup.taint }
-
- strs.each do |str|
- strs.each do |other|
- (str + other).tainted?.should == (str.tainted? | other.tainted?)
- end
- end
- end
- end
-
- it_behaves_like :string_concat_encoding, :+
end
diff --git a/spec/ruby/core/string/prepend_spec.rb b/spec/ruby/core/string/prepend_spec.rb
index a6074be3c6..5248ea8056 100644
--- a/spec/ruby/core/string/prepend_spec.rb
+++ b/spec/ruby/core/string/prepend_spec.rb
@@ -1,3 +1,4 @@
+# frozen_string_literal: false
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
@@ -34,16 +35,6 @@ describe "String#prepend" do
a.should == "hello world"
end
- ruby_version_is ''...'2.7' do
- it "taints self if other is tainted" do
- x = "x"
- x.prepend("".taint).tainted?.should be_true
-
- x = "x"
- x.prepend("y".taint).tainted?.should be_true
- end
- end
-
it "takes multiple arguments" do
str = " world"
str.prepend "he", "", "llo"
diff --git a/spec/ruby/core/string/reverse_spec.rb b/spec/ruby/core/string/reverse_spec.rb
index b45ff2cf6f..aa6abe6036 100644
--- a/spec/ruby/core/string/reverse_spec.rb
+++ b/spec/ruby/core/string/reverse_spec.rb
@@ -1,4 +1,5 @@
# encoding: utf-8
+# frozen_string_literal: false
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
@@ -10,31 +11,26 @@ describe "String#reverse" do
"".reverse.should == ""
end
- ruby_version_is '3.0' do
- it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new("stressed").reverse.should be_an_instance_of(String)
- StringSpecs::MyString.new("m").reverse.should be_an_instance_of(String)
- StringSpecs::MyString.new("").reverse.should be_an_instance_of(String)
- end
+ it "returns String instances when called on a subclass" do
+ StringSpecs::MyString.new("stressed").reverse.should be_an_instance_of(String)
+ StringSpecs::MyString.new("m").reverse.should be_an_instance_of(String)
+ StringSpecs::MyString.new("").reverse.should be_an_instance_of(String)
end
- ruby_version_is ''...'3.0' do
- it "returns subclass instances when called on a subclass" do
- StringSpecs::MyString.new("stressed").reverse.should be_an_instance_of(StringSpecs::MyString)
- StringSpecs::MyString.new("m").reverse.should be_an_instance_of(StringSpecs::MyString)
- StringSpecs::MyString.new("").reverse.should be_an_instance_of(StringSpecs::MyString)
- end
+ it "reverses a string with multi byte characters" do
+ "微軟正黑體".reverse.should == "體黑正軟微"
end
- ruby_version_is ''...'2.7' do
- it "taints the result if self is tainted" do
- "".taint.reverse.should.tainted?
- "m".taint.reverse.should.tainted?
- end
+ it "works with a broken string" do
+ str = "微軟\xDF\xDE正黑體".force_encoding(Encoding::UTF_8)
+
+ str.valid_encoding?.should be_false
+
+ str.reverse.should == "體黑正\xDE\xDF軟微"
end
- it "reverses a string with multi byte characters" do
- "微軟正黑體".reverse.should == "體黑正軟微"
+ it "returns a String in the same encoding as self" do
+ "stressed".encode("US-ASCII").reverse.encoding.should == Encoding::US_ASCII
end
end
@@ -62,4 +58,13 @@ describe "String#reverse!" do
str.reverse!
str.should == "體黑正軟微"
end
+
+ it "works with a broken string" do
+ str = "微軟\xDF\xDE正黑體".force_encoding(Encoding::UTF_8)
+
+ str.valid_encoding?.should be_false
+ str.reverse!
+
+ str.should == "體黑正\xDE\xDF軟微"
+ end
end
diff --git a/spec/ruby/core/string/rindex_spec.rb b/spec/ruby/core/string/rindex_spec.rb
index 7a6af0c9d0..88ce733583 100644
--- a/spec/ruby/core/string/rindex_spec.rb
+++ b/spec/ruby/core/string/rindex_spec.rb
@@ -1,16 +1,19 @@
# -*- encoding: utf-8 -*-
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'fixtures/utf-8-encoding'
describe "String#rindex with object" do
- it "raises a TypeError if obj isn't a String, Integer or Regexp" do
+ it "raises a TypeError if obj isn't a String or Regexp" do
not_supported_on :opal do
-> { "hello".rindex(:sym) }.should raise_error(TypeError)
end
-> { "hello".rindex(mock('x')) }.should raise_error(TypeError)
end
+ it "raises a TypeError if obj is an Integer" do
+ -> { "hello".rindex(42) }.should raise_error(TypeError)
+ end
+
it "doesn't try to convert obj to an integer via to_int" do
obj = mock('x')
obj.should_not_receive(:to_int)
@@ -192,6 +195,21 @@ describe "String#rindex with String" do
it "raises a TypeError when given offset is nil" do
-> { "str".rindex("st", nil) }.should raise_error(TypeError)
end
+
+ it "handles a substring in a superset encoding" do
+ 'abc'.dup.force_encoding(Encoding::US_ASCII).rindex('é').should == nil
+ end
+
+ it "handles a substring in a subset encoding" do
+ 'été'.rindex('t'.dup.force_encoding(Encoding::US_ASCII)).should == 1
+ end
+
+ it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
+ str = 'abc'.dup.force_encoding("ISO-2022-JP")
+ pattern = 'b'.dup.force_encoding("EUC-JP")
+
+ -> { str.rindex(pattern) }.should raise_error(Encoding::CompatibilityError, "incompatible character encodings: ISO-2022-JP and EUC-JP")
+ end
end
describe "String#rindex with Regexp" do
@@ -361,6 +379,6 @@ describe "String#rindex with Regexp" do
re = Regexp.new "れ".encode(Encoding::EUC_JP)
-> do
"あれ".rindex re
- end.should raise_error(Encoding::CompatibilityError)
+ end.should raise_error(Encoding::CompatibilityError, "incompatible encoding regexp match (EUC-JP regexp with UTF-8 string)")
end
end
diff --git a/spec/ruby/core/string/rjust_spec.rb b/spec/ruby/core/string/rjust_spec.rb
index f51aacff44..4ad3e54aea 100644
--- a/spec/ruby/core/string/rjust_spec.rb
+++ b/spec/ruby/core/string/rjust_spec.rb
@@ -31,16 +31,6 @@ describe "String#rjust with length, padding" do
"radiology".rjust(8, '-').should == "radiology"
end
- ruby_version_is ''...'2.7' do
- it "taints result when self or padstr is tainted" do
- "x".taint.rjust(4).should.tainted?
- "x".taint.rjust(0).should.tainted?
- "".taint.rjust(0).should.tainted?
- "x".taint.rjust(4, "*").should.tainted?
- "x".rjust(4, "*".taint).should.tainted?
- end
- end
-
it "tries to convert length to an integer using to_int" do
"^".rjust(3.8, "^_").should == "^_^"
@@ -74,39 +64,18 @@ describe "String#rjust with length, padding" do
-> { "hello".rjust(10, '') }.should raise_error(ArgumentError)
end
- ruby_version_is ''...'3.0' do
- it "returns subclass instances when called on subclasses" do
- StringSpecs::MyString.new("").rjust(10).should be_an_instance_of(StringSpecs::MyString)
- StringSpecs::MyString.new("foo").rjust(10).should be_an_instance_of(StringSpecs::MyString)
- StringSpecs::MyString.new("foo").rjust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(StringSpecs::MyString)
-
- "".rjust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
- "foo".rjust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
- end
- end
+ it "returns String instances when called on subclasses" do
+ StringSpecs::MyString.new("").rjust(10).should be_an_instance_of(String)
+ StringSpecs::MyString.new("foo").rjust(10).should be_an_instance_of(String)
+ StringSpecs::MyString.new("foo").rjust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
- ruby_version_is '3.0' do
- it "returns String instances when called on subclasses" do
- StringSpecs::MyString.new("").rjust(10).should be_an_instance_of(String)
- StringSpecs::MyString.new("foo").rjust(10).should be_an_instance_of(String)
- StringSpecs::MyString.new("foo").rjust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
-
- "".rjust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
- "foo".rjust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
- end
- end
-
- ruby_version_is ''...'2.7' do
- it "when padding is tainted and self is untainted returns a tainted string if and only if length is longer than self" do
- "hello".rjust(4, 'X'.taint).tainted?.should be_false
- "hello".rjust(5, 'X'.taint).tainted?.should be_false
- "hello".rjust(6, 'X'.taint).tainted?.should be_true
- end
+ "".rjust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
+ "foo".rjust(10, StringSpecs::MyString.new("x")).should be_an_instance_of(String)
end
describe "with width" do
it "returns a String in the same encoding as the original" do
- str = "abc".force_encoding Encoding::IBM437
+ str = "abc".dup.force_encoding Encoding::IBM437
result = str.rjust 5
result.should == " abc"
result.encoding.should equal(Encoding::IBM437)
@@ -115,7 +84,7 @@ describe "String#rjust with length, padding" do
describe "with width, pattern" do
it "returns a String in the compatible encoding" do
- str = "abc".force_encoding Encoding::IBM437
+ str = "abc".dup.force_encoding Encoding::IBM437
result = str.rjust 5, "あ"
result.should == "ああabc"
result.encoding.should equal(Encoding::UTF_8)
diff --git a/spec/ruby/core/string/rpartition_spec.rb b/spec/ruby/core/string/rpartition_spec.rb
index c8f9afaee9..cef0384c73 100644
--- a/spec/ruby/core/string/rpartition_spec.rb
+++ b/spec/ruby/core/string/rpartition_spec.rb
@@ -46,4 +46,26 @@ describe "String#rpartition with String" do
->{ "hello".rpartition(5) }.should raise_error(TypeError)
->{ "hello".rpartition(nil) }.should raise_error(TypeError)
end
+
+ it "handles a pattern in a superset encoding" do
+ string = "hello".dup.force_encoding(Encoding::US_ASCII)
+
+ result = string.rpartition("é")
+
+ result.should == ["", "", "hello"]
+ result[0].encoding.should == Encoding::US_ASCII
+ result[1].encoding.should == Encoding::US_ASCII
+ result[2].encoding.should == Encoding::US_ASCII
+ end
+
+ it "handles a pattern in a subset encoding" do
+ pattern = "o".dup.force_encoding(Encoding::US_ASCII)
+
+ result = "héllo world".rpartition(pattern)
+
+ result.should == ["héllo w", "o", "rld"]
+ result[0].encoding.should == Encoding::UTF_8
+ result[1].encoding.should == Encoding::US_ASCII
+ result[2].encoding.should == Encoding::UTF_8
+ end
end
diff --git a/spec/ruby/core/string/rstrip_spec.rb b/spec/ruby/core/string/rstrip_spec.rb
index a1453f91fe..6d46eb590e 100644
--- a/spec/ruby/core/string/rstrip_spec.rb
+++ b/spec/ruby/core/string/rstrip_spec.rb
@@ -1,3 +1,4 @@
+# frozen_string_literal: false
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
require_relative 'shared/strip'
@@ -11,18 +12,18 @@ describe "String#rstrip" do
" hello world \n\r\t\n\v\r".rstrip.should == " hello world"
"hello".rstrip.should == "hello"
"hello\x00".rstrip.should == "hello"
+ "こにちわ ".rstrip.should == "こにちわ"
end
- it "returns a copy of self with all trailing whitespace and NULL bytes removed" do
- "\x00 \x00hello\x00 \x00".rstrip.should == "\x00 \x00hello"
+ it "works with lazy substrings" do
+ " hello "[1...-1].rstrip.should == " hello"
+ " hello world "[1...-1].rstrip.should == " hello world"
+ " hello world \n\r\t\n\v\r"[1...-1].rstrip.should == " hello world"
+ " こにちわ "[1...-1].rstrip.should == "こにちわ"
end
- ruby_version_is ''...'2.7' do
- it "taints the result when self is tainted" do
- "".taint.rstrip.should.tainted?
- "ok".taint.rstrip.should.tainted?
- "ok ".taint.rstrip.should.tainted?
- end
+ it "returns a copy of self with all trailing whitespace and NULL bytes removed" do
+ "\x00 \x00hello\x00 \x00".rstrip.should == "\x00 \x00hello"
end
end
@@ -45,6 +46,18 @@ describe "String#rstrip!" do
a.should == "hello"
end
+ it "makes a string empty if it is only whitespace" do
+ "".rstrip!.should == nil
+ " ".rstrip.should == ""
+ " ".rstrip.should == ""
+ end
+
+ it "removes trailing NULL bytes and whitespace" do
+ a = "\000 goodbye \000"
+ a.rstrip!
+ a.should == "\000 goodbye"
+ end
+
it "raises a FrozenError on a frozen instance that is modified" do
-> { " hello ".freeze.rstrip! }.should raise_error(FrozenError)
end
@@ -54,4 +67,28 @@ describe "String#rstrip!" do
-> { "hello".freeze.rstrip! }.should raise_error(FrozenError)
-> { "".freeze.rstrip! }.should raise_error(FrozenError)
end
+
+ ruby_version_is "3.2" do
+ it "raises an Encoding::CompatibilityError if the last non-space codepoint is invalid" do
+ s = "abc\xDF".force_encoding(Encoding::UTF_8)
+ s.valid_encoding?.should be_false
+ -> { s.rstrip! }.should raise_error(Encoding::CompatibilityError)
+
+ s = "abc\xDF ".force_encoding(Encoding::UTF_8)
+ s.valid_encoding?.should be_false
+ -> { s.rstrip! }.should raise_error(Encoding::CompatibilityError)
+ end
+ end
+
+ ruby_version_is ""..."3.2" do
+ it "raises an ArgumentError if the last non-space codepoint is invalid" do
+ s = "abc\xDF".force_encoding(Encoding::UTF_8)
+ s.valid_encoding?.should be_false
+ -> { s.rstrip! }.should raise_error(ArgumentError)
+
+ s = "abc\xDF ".force_encoding(Encoding::UTF_8)
+ s.valid_encoding?.should be_false
+ -> { s.rstrip! }.should raise_error(ArgumentError)
+ end
+ end
end
diff --git a/spec/ruby/core/string/scan_spec.rb b/spec/ruby/core/string/scan_spec.rb
index 5f86dbbecc..70c3b7fb7b 100644
--- a/spec/ruby/core/string/scan_spec.rb
+++ b/spec/ruby/core/string/scan_spec.rb
@@ -65,32 +65,16 @@ describe "String#scan" do
-> { "cruel world".scan(mock('x')) }.should raise_error(TypeError)
end
- ruby_version_is ''...'2.7' do
- it "taints the results if the String argument is tainted" do
- a = "hello hello hello".scan("hello".taint)
- a.each { |m| m.tainted?.should be_true }
- end
-
- it "taints the results when passed a String argument if self is tainted" do
- a = "hello hello hello".taint.scan("hello")
- a.each { |m| m.tainted?.should be_true }
- end
-
- it "taints the results if the Regexp argument is tainted" do
- a = "hello".scan(/./.taint)
- a.each { |m| m.tainted?.should be_true }
- end
-
- it "taints the results when passed a Regexp argument if self is tainted" do
- a = "hello".taint.scan(/./)
- a.each { |m| m.tainted?.should be_true }
- end
- end
-
# jruby/jruby#5513
it "does not raise any errors when passed a multi-byte string" do
"あああaaaあああ".scan("あああ").should == ["あああ", "あああ"]
end
+
+ it "returns Strings in the same encoding as self" do
+ "cruel world".encode("US-ASCII").scan(/\w+/).each do |s|
+ s.encoding.should == Encoding::US_ASCII
+ end
+ end
end
describe "String#scan with pattern and block" do
@@ -173,24 +157,6 @@ describe "String#scan with pattern and block" do
$~.should == nil
end
- ruby_version_is ''...'2.7' do
- it "taints the results if the String argument is tainted" do
- "hello hello hello".scan("hello".taint).each { |m| m.tainted?.should be_true }
- end
-
- it "taints the results when passed a String argument if self is tainted" do
- "hello hello hello".taint.scan("hello").each { |m| m.tainted?.should be_true }
- end
-
- it "taints the results if the Regexp argument is tainted" do
- "hello".scan(/./.taint).each { |m| m.tainted?.should be_true }
- end
-
- it "taints the results when passed a Regexp argument if self is tainted" do
- "hello".taint.scan(/./).each { |m| m.tainted?.should be_true }
- end
- end
-
it "passes block arguments as individual arguments when blocks are provided" do
"a b c\na b c\na b c".scan(/(\w*) (\w*) (\w*)/) do |first,second,third|
first.should == 'a';
@@ -199,11 +165,9 @@ describe "String#scan with pattern and block" do
end
end
- ruby_version_is '3.0' do
- it "yields String instances for subclasses" do
- a = []
- StringSpecs::MyString.new("abc").scan(/./) { |s| a << s.class }
- a.should == [String, String, String]
- end
+ it "yields String instances for subclasses" do
+ a = []
+ StringSpecs::MyString.new("abc").scan(/./) { |s| a << s.class }
+ a.should == [String, String, String]
end
end
diff --git a/spec/ruby/core/string/scrub_spec.rb b/spec/ruby/core/string/scrub_spec.rb
index 3137399291..b9ef0f1a16 100644
--- a/spec/ruby/core/string/scrub_spec.rb
+++ b/spec/ruby/core/string/scrub_spec.rb
@@ -1,4 +1,5 @@
# -*- encoding: utf-8 -*-
+# frozen_string_literal: false
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
@@ -14,6 +15,11 @@ describe "String#scrub with a default replacement" do
"abc\u3042#{x81}".scrub.should == "abc\u3042\uFFFD"
end
+ it "replaces invalid byte sequences in lazy substrings" do
+ x81 = [0x81].pack('C').force_encoding('utf-8')
+ "abc\u3042#{x81}def"[1...-1].scrub.should == "bc\u3042\uFFFDde"
+ end
+
it "returns a copy of self when the input encoding is BINARY" do
input = "foo".encode('BINARY')
@@ -26,18 +32,15 @@ describe "String#scrub with a default replacement" do
input.scrub.should == "abc?????"
end
- ruby_version_is '3.0' do
- it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new("foo").scrub.should be_an_instance_of(String)
- input = [0x81].pack('C').force_encoding('utf-8')
- StringSpecs::MyString.new(input).scrub.should be_an_instance_of(String)
- end
+ it "returns a String in the same encoding as self" do
+ x81 = [0x81].pack('C').force_encoding('utf-8')
+ "abc\u3042#{x81}".scrub.encoding.should == Encoding::UTF_8
end
- ruby_version_is ''...'3.0' do
- it "returns subclass instances when called on a subclass" do
- StringSpecs::MyString.new("foo").scrub.should be_an_instance_of(StringSpecs::MyString)
- end
+ it "returns String instances when called on a subclass" do
+ StringSpecs::MyString.new("foo").scrub.should be_an_instance_of(String)
+ input = [0x81].pack('C').force_encoding('utf-8')
+ StringSpecs::MyString.new(input).scrub.should be_an_instance_of(String)
end
end
@@ -75,6 +78,11 @@ describe "String#scrub with a custom replacement" do
block.should raise_error(ArgumentError)
end
+ it "returns a String in the same encoding as self" do
+ x81 = [0x81].pack('C').force_encoding('utf-8')
+ "abc\u3042#{x81}".scrub("*").encoding.should == Encoding::UTF_8
+ end
+
it "raises TypeError when a non String replacement is given" do
x81 = [0x81].pack('C').force_encoding('utf-8')
block = -> { "foo#{x81}".scrub(1) }
@@ -82,12 +90,10 @@ describe "String#scrub with a custom replacement" do
block.should raise_error(TypeError)
end
- ruby_version_is '3.0' do
- it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new("foo").scrub("*").should be_an_instance_of(String)
- input = [0x81].pack('C').force_encoding('utf-8')
- StringSpecs::MyString.new(input).scrub("*").should be_an_instance_of(String)
- end
+ it "returns String instances when called on a subclass" do
+ StringSpecs::MyString.new("foo").scrub("*").should be_an_instance_of(String)
+ input = [0x81].pack('C').force_encoding('utf-8')
+ StringSpecs::MyString.new(input).scrub("*").should be_an_instance_of(String)
end
end
@@ -114,12 +120,10 @@ describe "String#scrub with a block" do
replaced.should == "€€"
end
- ruby_version_is '3.0' do
- it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new("foo").scrub { |b| "*" }.should be_an_instance_of(String)
- input = [0x81].pack('C').force_encoding('utf-8')
- StringSpecs::MyString.new(input).scrub { |b| "<#{b.unpack("H*")[0]}>" }.should be_an_instance_of(String)
- end
+ it "returns String instances when called on a subclass" do
+ StringSpecs::MyString.new("foo").scrub { |b| "*" }.should be_an_instance_of(String)
+ input = [0x81].pack('C').force_encoding('utf-8')
+ StringSpecs::MyString.new(input).scrub { |b| "<#{b.unpack("H*")[0]}>" }.should be_an_instance_of(String)
end
end
diff --git a/spec/ruby/core/string/setbyte_spec.rb b/spec/ruby/core/string/setbyte_spec.rb
index 03e5bad88b..85403ca62c 100644
--- a/spec/ruby/core/string/setbyte_spec.rb
+++ b/spec/ruby/core/string/setbyte_spec.rb
@@ -1,4 +1,5 @@
# -*- encoding: utf-8 -*-
+# frozen_string_literal: false
require_relative '../../spec_helper'
describe "String#setbyte" do
@@ -36,6 +37,12 @@ describe "String#setbyte" do
str.valid_encoding?.should be_true
str.setbyte(2,253)
str.valid_encoding?.should be_false
+
+ str = "ABC"
+ str.setbyte(0, 0x20) # ' '
+ str.should.valid_encoding?
+ str.setbyte(0, 0xE3)
+ str.should_not.valid_encoding?
end
it "regards a negative index as counting from the end of the String" do
diff --git a/spec/ruby/core/string/shared/byte_index_common.rb b/spec/ruby/core/string/shared/byte_index_common.rb
new file mode 100644
index 0000000000..3de1453f4f
--- /dev/null
+++ b/spec/ruby/core/string/shared/byte_index_common.rb
@@ -0,0 +1,63 @@
+# -*- encoding: utf-8 -*-
+require_relative '../../../spec_helper'
+
+describe :byte_index_common, shared: true do
+ describe "raises on type errors" do
+ it "raises a TypeError if passed nil" do
+ -> { "abc".send(@method, nil) }.should raise_error(TypeError, "no implicit conversion of nil into String")
+ end
+
+ it "raises a TypeError if passed a boolean" do
+ -> { "abc".send(@method, true) }.should raise_error(TypeError, "no implicit conversion of true into String")
+ end
+
+ it "raises a TypeError if passed a Symbol" do
+ not_supported_on :opal do
+ -> { "abc".send(@method, :a) }.should raise_error(TypeError, "no implicit conversion of Symbol into String")
+ end
+ end
+
+ it "raises a TypeError if passed a Symbol" do
+ obj = mock('x')
+ obj.should_not_receive(:to_int)
+ -> { "hello".send(@method, obj) }.should raise_error(TypeError, "no implicit conversion of MockObject into String")
+ end
+
+ it "raises a TypeError if passed an Integer" do
+ -> { "abc".send(@method, 97) }.should raise_error(TypeError, "no implicit conversion of Integer into String")
+ end
+ end
+
+ describe "with multibyte codepoints" do
+ it "raises an IndexError when byte offset lands in the middle of a multibyte character" do
+ -> { "わ".send(@method, "", 1) }.should raise_error(IndexError, "offset 1 does not land on character boundary")
+ -> { "わ".send(@method, "", 2) }.should raise_error(IndexError, "offset 2 does not land on character boundary")
+ -> { "わ".send(@method, "", -1) }.should raise_error(IndexError, "offset 2 does not land on character boundary")
+ -> { "わ".send(@method, "", -2) }.should raise_error(IndexError, "offset 1 does not land on character boundary")
+ end
+
+ it "raises an Encoding::CompatibilityError if the encodings are incompatible" do
+ re = Regexp.new "れ".encode(Encoding::EUC_JP)
+ -> do
+ "あれ".send(@method, re)
+ end.should raise_error(Encoding::CompatibilityError, "incompatible encoding regexp match (EUC-JP regexp with UTF-8 string)")
+ end
+ end
+
+ describe "with global variables" do
+ it "doesn't set $~ for non regex search" do
+ $~ = nil
+
+ 'hello.'.send(@method, 'll')
+ $~.should == nil
+ end
+
+ it "sets $~ to MatchData of match and nil when there's none" do
+ 'hello.'.send(@method, /.e./)
+ $~[0].should == 'hel'
+
+ 'hello.'.send(@method, /not/)
+ $~.should == nil
+ end
+ end
+end
diff --git a/spec/ruby/core/string/shared/chars.rb b/spec/ruby/core/string/shared/chars.rb
index 1f045e4530..c730643cf4 100644
--- a/spec/ruby/core/string/shared/chars.rb
+++ b/spec/ruby/core/string/shared/chars.rb
@@ -21,12 +21,12 @@ describe :string_chars, shared: true do
end
it "returns characters in the same encoding as self" do
- "&%".force_encoding('Shift_JIS').send(@method).to_a.all? {|c| c.encoding.name.should == 'Shift_JIS'}
+ "&%".dup.force_encoding('Shift_JIS').send(@method).to_a.all? {|c| c.encoding.name.should == 'Shift_JIS'}
"&%".encode('BINARY').send(@method).to_a.all? {|c| c.encoding.should == Encoding::BINARY }
end
it "works with multibyte characters" do
- s = "\u{8987}".force_encoding("UTF-8")
+ s = "\u{8987}".dup.force_encoding("UTF-8")
s.bytesize.should == 3
s.send(@method).to_a.should == [s]
end
@@ -39,14 +39,14 @@ describe :string_chars, shared: true do
end
it "returns a different character if the String is transcoded" do
- s = "\u{20AC}".force_encoding('UTF-8')
- s.encode('UTF-8').send(@method).to_a.should == ["\u{20AC}".force_encoding('UTF-8')]
+ s = "\u{20AC}".dup.force_encoding('UTF-8')
+ s.encode('UTF-8').send(@method).to_a.should == ["\u{20AC}".dup.force_encoding('UTF-8')]
s.encode('iso-8859-15').send(@method).to_a.should == [[0xA4].pack('C').force_encoding('iso-8859-15')]
- s.encode('iso-8859-15').encode('UTF-8').send(@method).to_a.should == ["\u{20AC}".force_encoding('UTF-8')]
+ s.encode('iso-8859-15').encode('UTF-8').send(@method).to_a.should == ["\u{20AC}".dup.force_encoding('UTF-8')]
end
it "uses the String's encoding to determine what characters it contains" do
- s = "\u{24B62}"
+ s = +"\u{24B62}"
s.force_encoding('UTF-8').send(@method).to_a.should == [
s.force_encoding('UTF-8')
@@ -63,18 +63,4 @@ describe :string_chars, shared: true do
[0xA2].pack('C').force_encoding('SJIS')
]
end
-
- ruby_version_is ''...'2.7' do
- it "taints resulting strings when self is tainted" do
- str = "hello"
-
- str.send(@method) do |x|
- x.should_not.tainted?
- end
-
- str.dup.taint.send(@method) do |x|
- x.should.tainted?
- end
- end
- end
end
diff --git a/spec/ruby/core/string/shared/codepoints.rb b/spec/ruby/core/string/shared/codepoints.rb
index 0b2e078e0a..f71263054a 100644
--- a/spec/ruby/core/string/shared/codepoints.rb
+++ b/spec/ruby/core/string/shared/codepoints.rb
@@ -7,7 +7,7 @@ describe :string_codepoints, shared: true do
end
it "raises an ArgumentError when self has an invalid encoding and a method is called on the returned Enumerator" do
- s = "\xDF".force_encoding(Encoding::UTF_8)
+ s = "\xDF".dup.force_encoding(Encoding::UTF_8)
s.valid_encoding?.should be_false
-> { s.send(@method).to_a }.should raise_error(ArgumentError)
end
@@ -21,7 +21,7 @@ describe :string_codepoints, shared: true do
end
it "raises an ArgumentError if self's encoding is invalid and a block is given" do
- s = "\xDF".force_encoding(Encoding::UTF_8)
+ s = "\xDF".dup.force_encoding(Encoding::UTF_8)
s.valid_encoding?.should be_false
-> { s.send(@method) { } }.should raise_error(ArgumentError)
end
@@ -49,7 +49,7 @@ describe :string_codepoints, shared: true do
it "round-trips to the original String using Integer#chr" do
s = "\u{13}\u{7711}\u{1010}"
- s2 = ""
+ s2 = +""
s.send(@method) {|n| s2 << n.chr(Encoding::UTF_8)}
s.should == s2
end
diff --git a/spec/ruby/core/string/shared/concat.rb b/spec/ruby/core/string/shared/concat.rb
index d6ffad7d4d..dded9a69e7 100644
--- a/spec/ruby/core/string/shared/concat.rb
+++ b/spec/ruby/core/string/shared/concat.rb
@@ -1,3 +1,4 @@
+# frozen_string_literal: false
describe :string_concat, shared: true do
it "concatenates the given argument to self and returns self" do
str = 'hello '
@@ -5,18 +6,6 @@ describe :string_concat, shared: true do
str.should == "hello world"
end
- it "converts the given argument to a String using to_str" do
- obj = mock('world!')
- obj.should_receive(:to_str).and_return("world!")
- a = 'hello '.send(@method, obj)
- a.should == 'hello world!'
- end
-
- it "raises a TypeError if the given argument can't be converted to a String" do
- -> { 'hello '.send(@method, []) }.should raise_error(TypeError)
- -> { 'hello '.send(@method, mock('x')) }.should raise_error(TypeError)
- end
-
it "raises a FrozenError when self is frozen" do
a = "hello"
a.freeze
@@ -39,18 +28,6 @@ describe :string_concat, shared: true do
str.should be_an_instance_of(StringSpecs::MyString)
end
- ruby_version_is ''...'2.7' do
- it "taints self if other is tainted" do
- "x".send(@method, "".taint).should.tainted?
- "x".send(@method, "y".taint).should.tainted?
- end
-
- it "untrusts self if other is untrusted" do
- "x".send(@method, "".untrust).should.untrusted?
- "x".send(@method, "y".untrust).should.untrusted?
- end
- end
-
describe "with Integer" do
it "concatenates the argument interpreted as a codepoint" do
b = "".send(@method, 33)
@@ -160,3 +137,23 @@ describe :string_concat_encoding, shared: true do
end
end
end
+
+describe :string_concat_type_coercion, shared: true do
+ it "converts the given argument to a String using to_str" do
+ obj = mock('world!')
+ obj.should_receive(:to_str).and_return("world!")
+ a = 'hello '.send(@method, obj)
+ a.should == 'hello world!'
+ end
+
+ it "raises a TypeError if the given argument can't be converted to a String" do
+ -> { 'hello '.send(@method, []) }.should raise_error(TypeError)
+ -> { 'hello '.send(@method, mock('x')) }.should raise_error(TypeError)
+ end
+
+ it "raises a NoMethodError if the given argument raises a NoMethodError during type coercion to a String" do
+ obj = mock('world!')
+ obj.should_receive(:to_str).and_raise(NoMethodError)
+ -> { 'hello '.send(@method, obj) }.should raise_error(NoMethodError)
+ end
+end
diff --git a/spec/ruby/core/string/shared/dedup.rb b/spec/ruby/core/string/shared/dedup.rb
new file mode 100644
index 0000000000..97b5df6ed1
--- /dev/null
+++ b/spec/ruby/core/string/shared/dedup.rb
@@ -0,0 +1,56 @@
+# frozen_string_literal: false
+describe :string_dedup, shared: true do
+ it 'returns self if the String is frozen' do
+ input = 'foo'.freeze
+ output = input.send(@method)
+
+ output.should equal(input)
+ output.should.frozen?
+ end
+
+ it 'returns a frozen copy if the String is not frozen' do
+ input = 'foo'
+ output = input.send(@method)
+
+ output.should.frozen?
+ output.should_not equal(input)
+ output.should == 'foo'
+ end
+
+ it "returns the same object for equal unfrozen strings" do
+ origin = "this is a string"
+ dynamic = %w(this is a string).join(' ')
+
+ origin.should_not equal(dynamic)
+ origin.send(@method).should equal(dynamic.send(@method))
+ end
+
+ it "returns the same object when it's called on the same String literal" do
+ "unfrozen string".send(@method).should equal("unfrozen string".send(@method))
+ "unfrozen string".send(@method).should_not equal("another unfrozen string".send(@method))
+ end
+
+ it "deduplicates frozen strings" do
+ dynamic = %w(this string is frozen).join(' ').freeze
+
+ dynamic.should_not equal("this string is frozen".freeze)
+
+ dynamic.send(@method).should equal("this string is frozen".freeze)
+ dynamic.send(@method).should equal("this string is frozen".send(@method).freeze)
+ end
+
+ it "does not deduplicate a frozen string when it has instance variables" do
+ dynamic = %w(this string is frozen).join(' ')
+ dynamic.instance_variable_set(:@a, 1)
+ dynamic.freeze
+
+ dynamic.send(@method).should_not equal("this string is frozen".freeze)
+ dynamic.send(@method).should_not equal("this string is frozen".send(@method).freeze)
+ dynamic.send(@method).should equal(dynamic)
+ end
+
+ it "interns the provided string if it is frozen" do
+ dynamic = "this string is unique and frozen #{rand}".freeze
+ dynamic.send(@method).should equal(dynamic)
+ end
+end
diff --git a/spec/ruby/core/string/shared/each_codepoint_without_block.rb b/spec/ruby/core/string/shared/each_codepoint_without_block.rb
index 92b7f76032..31b4c02c9c 100644
--- a/spec/ruby/core/string/shared/each_codepoint_without_block.rb
+++ b/spec/ruby/core/string/shared/each_codepoint_without_block.rb
@@ -6,7 +6,7 @@ describe :string_each_codepoint_without_block, shared: true do
end
it "returns an Enumerator even when self has an invalid encoding" do
- s = "\xDF".force_encoding(Encoding::UTF_8)
+ s = "\xDF".dup.force_encoding(Encoding::UTF_8)
s.valid_encoding?.should be_false
s.send(@method).should be_an_instance_of(Enumerator)
end
@@ -23,7 +23,7 @@ describe :string_each_codepoint_without_block, shared: true do
end
it "should return the size of the string even when the string has an invalid encoding" do
- s = "\xDF".force_encoding(Encoding::UTF_8)
+ s = "\xDF".dup.force_encoding(Encoding::UTF_8)
s.valid_encoding?.should be_false
s.send(@method).size.should == 1
end
diff --git a/spec/ruby/core/string/shared/each_line.rb b/spec/ruby/core/string/shared/each_line.rb
index f9c910596a..231a6d9d4f 100644
--- a/spec/ruby/core/string/shared/each_line.rb
+++ b/spec/ruby/core/string/shared/each_line.rb
@@ -40,14 +40,6 @@ describe :string_each_line, shared: true do
b.should == ["foo\n", "🤡🤡🤡🤡🤡🤡🤡\n", "bar\n", "baz\n"]
end
- ruby_version_is ''...'2.7' do
- it "taints substrings that are passed to the block if self is tainted" do
- "one\ntwo\r\nthree".taint.send(@method) { |s| s.should.tainted? }
-
- "x.y.".send(@method, ".".taint) { |s| s.should_not.tainted? }
- end
- end
-
it "passes self as a whole to the block if the separator is nil" do
a = []
"one\ntwo\r\nthree".send(@method, nil) { |s| a << s }
@@ -93,20 +85,10 @@ describe :string_each_line, shared: true do
end
end
- ruby_version_is ''...'3.0' do
- it "yields subclass instances for subclasses" do
- a = []
- StringSpecs::MyString.new("hello\nworld").send(@method) { |s| a << s.class }
- a.should == [StringSpecs::MyString, StringSpecs::MyString]
- end
- end
-
- ruby_version_is '3.0' do
- it "yields String instances for subclasses" do
- a = []
- StringSpecs::MyString.new("hello\nworld").send(@method) { |s| a << s.class }
- a.should == [String, String]
- end
+ it "yields String instances for subclasses" do
+ a = []
+ StringSpecs::MyString.new("hello\nworld").send(@method) { |s| a << s.class }
+ a.should == [String, String]
end
it "returns self" do
@@ -124,12 +106,18 @@ describe :string_each_line, shared: true do
end
it "does not care if the string is modified while substituting" do
- str = "hello\nworld."
+ str = +"hello\nworld."
out = []
str.send(@method){|x| out << x; str[-1] = '!' }.should == "hello\nworld!"
out.should == ["hello\n", "world."]
end
+ it "returns Strings in the same encoding as self" do
+ "one\ntwo\r\nthree".encode("US-ASCII").send(@method) do |s|
+ s.encoding.should == Encoding::US_ASCII
+ end
+ end
+
it "raises a TypeError when the separator can't be converted to a string" do
-> { "hello world".send(@method, false) {} }.should raise_error(TypeError)
-> { "hello world".send(@method, mock('x')) {} }.should raise_error(TypeError)
diff --git a/spec/ruby/core/string/shared/encode.rb b/spec/ruby/core/string/shared/encode.rb
index a73de5b943..3776e0d709 100644
--- a/spec/ruby/core/string/shared/encode.rb
+++ b/spec/ruby/core/string/shared/encode.rb
@@ -1,4 +1,5 @@
# -*- encoding: utf-8 -*-
+# frozen_string_literal: false
describe :string_encode, shared: true do
describe "when passed no options" do
it "transcodes to Encoding.default_internal when set" do
diff --git a/spec/ruby/core/string/shared/eql.rb b/spec/ruby/core/string/shared/eql.rb
index b57d6895ff..845b0a3e15 100644
--- a/spec/ruby/core/string/shared/eql.rb
+++ b/spec/ruby/core/string/shared/eql.rb
@@ -13,15 +13,15 @@ describe :string_eql_value, shared: true do
end
it "ignores encoding difference of compatible string" do
- "hello".force_encoding("utf-8").send(@method, "hello".force_encoding("iso-8859-1")).should be_true
+ "hello".dup.force_encoding("utf-8").send(@method, "hello".dup.force_encoding("iso-8859-1")).should be_true
end
it "considers encoding difference of incompatible string" do
- "\xff".force_encoding("utf-8").send(@method, "\xff".force_encoding("iso-8859-1")).should be_false
+ "\xff".dup.force_encoding("utf-8").send(@method, "\xff".dup.force_encoding("iso-8859-1")).should be_false
end
it "considers encoding compatibility" do
- "abcd".force_encoding("utf-8").send(@method, "abcd".force_encoding("utf-32le")).should be_false
+ "abcd".dup.force_encoding("utf-8").send(@method, "abcd".dup.force_encoding("utf-32le")).should be_false
end
it "ignores subclass differences" do
@@ -31,4 +31,8 @@ describe :string_eql_value, shared: true do
a.send(@method, b).should be_true
b.send(@method, a).should be_true
end
+
+ it "returns true when comparing 2 empty strings but one is not ASCII-compatible" do
+ "".send(@method, "".dup.force_encoding('iso-2022-jp')).should == true
+ end
end
diff --git a/spec/ruby/core/string/shared/length.rb b/spec/ruby/core/string/shared/length.rb
index 94e5ec135b..ae572ba755 100644
--- a/spec/ruby/core/string/shared/length.rb
+++ b/spec/ruby/core/string/shared/length.rb
@@ -18,7 +18,7 @@ describe :string_length, shared: true do
end
it "returns the length of the new self after encoding is changed" do
- str = 'こにちわ'
+ str = +'こにちわ'
str.send(@method)
str.force_encoding('BINARY').send(@method).should == 12
@@ -44,12 +44,12 @@ describe :string_length, shared: true do
end
it "adds 1 (and not 2) for a incomplete surrogate in UTF-16" do
- "\x00\xd8".force_encoding("UTF-16LE").send(@method).should == 1
- "\xd8\x00".force_encoding("UTF-16BE").send(@method).should == 1
+ "\x00\xd8".dup.force_encoding("UTF-16LE").send(@method).should == 1
+ "\xd8\x00".dup.force_encoding("UTF-16BE").send(@method).should == 1
end
it "adds 1 for a broken sequence in UTF-32" do
- "\x04\x03\x02\x01".force_encoding("UTF-32LE").send(@method).should == 1
- "\x01\x02\x03\x04".force_encoding("UTF-32BE").send(@method).should == 1
+ "\x04\x03\x02\x01".dup.force_encoding("UTF-32LE").send(@method).should == 1
+ "\x01\x02\x03\x04".dup.force_encoding("UTF-32BE").send(@method).should == 1
end
end
diff --git a/spec/ruby/core/string/shared/partition.rb b/spec/ruby/core/string/shared/partition.rb
index 7dc3d9cc0b..4cac149ce5 100644
--- a/spec/ruby/core/string/shared/partition.rb
+++ b/spec/ruby/core/string/shared/partition.rb
@@ -2,35 +2,32 @@ require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
describe :string_partition, shared: true do
- ruby_version_is '3.0' do
- it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new("hello").send(@method, "l").each do |item|
- item.should be_an_instance_of(String)
- end
+ it "returns String instances when called on a subclass" do
+ StringSpecs::MyString.new("hello").send(@method, "l").each do |item|
+ item.should be_an_instance_of(String)
+ end
- StringSpecs::MyString.new("hello").send(@method, "x").each do |item|
- item.should be_an_instance_of(String)
- end
+ StringSpecs::MyString.new("hello").send(@method, "x").each do |item|
+ item.should be_an_instance_of(String)
+ end
- StringSpecs::MyString.new("hello").send(@method, /l./).each do |item|
- item.should be_an_instance_of(String)
- end
+ StringSpecs::MyString.new("hello").send(@method, /l./).each do |item|
+ item.should be_an_instance_of(String)
end
end
- ruby_version_is ''...'3.0' do
- it "returns subclass instances when called on a subclass" do
- StringSpecs::MyString.new("hello").send(@method, StringSpecs::MyString.new("l")).each do |item|
- item.should be_an_instance_of(StringSpecs::MyString)
- end
+ it "returns before- and after- parts in the same encoding as self" do
+ strings = "hello".encode("US-ASCII").send(@method, "ello")
+ strings[0].encoding.should == Encoding::US_ASCII
+ strings[2].encoding.should == Encoding::US_ASCII
- StringSpecs::MyString.new("hello").send(@method, "x").each do |item|
- item.should be_an_instance_of(StringSpecs::MyString)
- end
+ strings = "hello".encode("US-ASCII").send(@method, /ello/)
+ strings[0].encoding.should == Encoding::US_ASCII
+ strings[2].encoding.should == Encoding::US_ASCII
+ end
- StringSpecs::MyString.new("hello").send(@method, /l./).each do |item|
- item.should be_an_instance_of(StringSpecs::MyString)
- end
- end
+ it "returns the matching part in the separator's encoding" do
+ strings = "hello".encode("US-ASCII").send(@method, "ello")
+ strings[1].encoding.should == Encoding::UTF_8
end
end
diff --git a/spec/ruby/core/string/shared/replace.rb b/spec/ruby/core/string/shared/replace.rb
index 8dfac49f02..24dac0eb27 100644
--- a/spec/ruby/core/string/shared/replace.rb
+++ b/spec/ruby/core/string/shared/replace.rb
@@ -1,3 +1,4 @@
+# frozen_string_literal: false
describe :string_replace, shared: true do
it "returns self" do
a = "a"
@@ -10,36 +11,6 @@ describe :string_replace, shared: true do
a.should == "another string"
end
- ruby_version_is ''...'2.7' do
- it "taints self if other is tainted" do
- a = ""
- b = "".taint
- a.send(@method, b)
- a.should.tainted?
- end
-
- it "does not untaint self if other is untainted" do
- a = "".taint
- b = ""
- a.send(@method, b)
- a.should.tainted?
- end
-
- it "untrusts self if other is untrusted" do
- a = ""
- b = "".untrust
- a.send(@method, b)
- a.should.untrusted?
- end
-
- it "does not trust self if other is trusted" do
- a = "".untrust
- b = ""
- a.send(@method, b)
- a.should.untrusted?
- end
- end
-
it "replaces the encoding of self with that of other" do
a = "".encode("UTF-16LE")
b = "".encode("UTF-8")
diff --git a/spec/ruby/core/string/shared/slice.rb b/spec/ruby/core/string/shared/slice.rb
index 1db8fd6730..2f69b9ddce 100644
--- a/spec/ruby/core/string/shared/slice.rb
+++ b/spec/ruby/core/string/shared/slice.rb
@@ -80,23 +80,12 @@ describe :string_slice_index_length, shared: true do
"hello there".send(@method, -3,2).should == "er"
end
- ruby_version_is ''...'2.7' do
- it "always taints resulting strings when self is tainted" do
- str = "hello world"
- str.taint
-
- str.send(@method, 0,0).should.tainted?
- str.send(@method, 0,1).should.tainted?
- str.send(@method, 2,1).should.tainted?
- end
- end
-
- it "returns a string with the same encoding" do
+ it "returns a string with the same encoding as self" do
s = "hello there"
s.send(@method, 1, 9).encoding.should == s.encoding
- a = "hello".force_encoding("binary")
- b = " there".force_encoding("ISO-8859-1")
+ a = "hello".dup.force_encoding("binary")
+ b = " there".dup.force_encoding("ISO-8859-1")
c = (a + b).force_encoding(Encoding::US_ASCII)
c.send(@method, 0, 5).encoding.should == Encoding::US_ASCII
@@ -163,22 +152,11 @@ describe :string_slice_index_length, shared: true do
-> { "hello".send(@method, 0, bignum_value) }.should raise_error(RangeError)
end
- ruby_version_is ''...'3.0' do
- it "returns subclass instances" do
- s = StringSpecs::MyString.new("hello")
- s.send(@method, 0,0).should be_an_instance_of(StringSpecs::MyString)
- s.send(@method, 0,4).should be_an_instance_of(StringSpecs::MyString)
- s.send(@method, 1,4).should be_an_instance_of(StringSpecs::MyString)
- end
- end
-
- ruby_version_is '3.0' do
- it "returns String instances" do
- s = StringSpecs::MyString.new("hello")
- s.send(@method, 0,0).should be_an_instance_of(String)
- s.send(@method, 0,4).should be_an_instance_of(String)
- s.send(@method, 1,4).should be_an_instance_of(String)
- end
+ it "returns String instances" do
+ s = StringSpecs::MyString.new("hello")
+ s.send(@method, 0,0).should be_an_instance_of(String)
+ s.send(@method, 0,4).should be_an_instance_of(String)
+ s.send(@method, 1,4).should be_an_instance_of(String)
end
it "handles repeated application" do
@@ -217,6 +195,10 @@ describe :string_slice_range, shared: true do
"x".send(@method, 1..-1).should == ""
end
+ it "returns a String in the same encoding as self" do
+ "hello there".encode("US-ASCII").send(@method, 1..1).encoding.should == Encoding::US_ASCII
+ end
+
it "returns nil if the beginning of the range falls outside of self" do
"hello there".send(@method, 12..-1).should == nil
"hello there".send(@method, 20..25).should == nil
@@ -249,36 +231,11 @@ describe :string_slice_range, shared: true do
"x".send(@method, 1...-1).should == ""
end
- ruby_version_is ''...'2.7' do
- it "always taints resulting strings when self is tainted" do
- str = "hello world"
- str.taint
-
- str.send(@method, 0..0).should.tainted?
- str.send(@method, 0...0).should.tainted?
- str.send(@method, 0..1).should.tainted?
- str.send(@method, 0...1).should.tainted?
- str.send(@method, 2..3).should.tainted?
- str.send(@method, 2..0).should.tainted?
- end
- end
-
- ruby_version_is ''...'3.0' do
- it "returns subclass instances" do
- s = StringSpecs::MyString.new("hello")
- s.send(@method, 0...0).should be_an_instance_of(StringSpecs::MyString)
- s.send(@method, 0..4).should be_an_instance_of(StringSpecs::MyString)
- s.send(@method, 1..4).should be_an_instance_of(StringSpecs::MyString)
- end
- end
-
- ruby_version_is '3.0' do
- it "returns String instances" do
- s = StringSpecs::MyString.new("hello")
- s.send(@method, 0...0).should be_an_instance_of(String)
- s.send(@method, 0..4).should be_an_instance_of(String)
- s.send(@method, 1..4).should be_an_instance_of(String)
- end
+ it "returns String instances" do
+ s = StringSpecs::MyString.new("hello")
+ s.send(@method, 0...0).should be_an_instance_of(String)
+ s.send(@method, 0..4).should be_an_instance_of(String)
+ s.send(@method, 1..4).should be_an_instance_of(String)
end
it "calls to_int on range arguments" do
@@ -334,14 +291,12 @@ describe :string_slice_range, shared: true do
"hello there".send(@method, eval("(-4...)")).should == "here"
end
- ruby_version_is "2.7" do
- it "works with beginless ranges" do
- "hello there".send(@method, eval("(..5)")).should == "hello "
- "hello there".send(@method, eval("(...5)")).should == "hello"
- "hello there".send(@method, eval("(..-4)")).should == "hello th"
- "hello there".send(@method, eval("(...-4)")).should == "hello t"
- "hello there".send(@method, eval("(...nil)")).should == "hello there"
- end
+ it "works with beginless ranges" do
+ "hello there".send(@method, (..5)).should == "hello "
+ "hello there".send(@method, (...5)).should == "hello"
+ "hello there".send(@method, (..-4)).should == "hello th"
+ "hello there".send(@method, (...-4)).should == "hello t"
+ "hello there".send(@method, (...nil)).should == "hello there"
end
end
@@ -355,43 +310,14 @@ describe :string_slice_regexp, shared: true do
"hello there".send(@method, /xyz/).should == nil
end
- not_supported_on :opal do
- ruby_version_is ''...'2.7' do
- it "always taints resulting strings when self or regexp is tainted" do
- strs = ["hello world"]
- strs += strs.map { |s| s.dup.taint }
-
- strs.each do |str|
- str.send(@method, //).tainted?.should == str.tainted?
- str.send(@method, /hello/).tainted?.should == str.tainted?
-
- tainted_re = /./
- tainted_re.taint
-
- str.send(@method, tainted_re).should.tainted?
- end
- end
-
- it "returns an untrusted string if the regexp is untrusted" do
- "hello".send(@method, /./.untrust).untrusted?.should be_true
- end
- end
- end
-
- ruby_version_is ''...'3.0' do
- it "returns subclass instances" do
- s = StringSpecs::MyString.new("hello")
- s.send(@method, //).should be_an_instance_of(StringSpecs::MyString)
- s.send(@method, /../).should be_an_instance_of(StringSpecs::MyString)
- end
+ it "returns a String in the same encoding as self" do
+ "hello there".encode("US-ASCII").send(@method, /[aeiou](.)\1/).encoding.should == Encoding::US_ASCII
end
- ruby_version_is '3.0' do
- it "returns String instances" do
- s = StringSpecs::MyString.new("hello")
- s.send(@method, //).should be_an_instance_of(String)
- s.send(@method, /../).should be_an_instance_of(String)
- end
+ it "returns String instances" do
+ s = StringSpecs::MyString.new("hello")
+ s.send(@method, //).should be_an_instance_of(String)
+ s.send(@method, /../).should be_an_instance_of(String)
end
it "sets $~ to MatchData when there is a match and nil when there's none" do
@@ -418,44 +344,28 @@ describe :string_slice_regexp_index, shared: true do
"har".send(@method, /(.)(.)(.)/, -3).should == "h"
end
- ruby_version_is ''...'2.7' do
- it "always taints resulting strings when self or regexp is tainted" do
- strs = ["hello world"]
- strs += strs.map { |s| s.dup.taint }
-
- strs.each do |str|
- str.send(@method, //, 0).tainted?.should == str.tainted?
- str.send(@method, /hello/, 0).tainted?.should == str.tainted?
-
- str.send(@method, /(.)(.)(.)/, 0).tainted?.should == str.tainted?
- str.send(@method, /(.)(.)(.)/, 1).tainted?.should == str.tainted?
- str.send(@method, /(.)(.)(.)/, -1).tainted?.should == str.tainted?
- str.send(@method, /(.)(.)(.)/, -2).tainted?.should == str.tainted?
-
- tainted_re = /(.)(.)(.)/
- tainted_re.taint
-
- str.send(@method, tainted_re, 0).should.tainted?
- str.send(@method, tainted_re, 1).should.tainted?
- str.send(@method, tainted_re, -1).should.tainted?
- end
- end
-
- not_supported_on :opal do
- it "returns an untrusted string if the regexp is untrusted" do
- "hello".send(@method, /(.)/.untrust, 1).untrusted?.should be_true
- end
- end
- end
-
it "returns nil if there is no match" do
"hello there".send(@method, /(what?)/, 1).should == nil
end
+ it "returns nil if the index is larger than the number of captures" do
+ "hello there".send(@method, /hello (.)/, 2).should == nil
+ # You can't refer to 0 using negative indices
+ "hello there".send(@method, /hello (.)/, -2).should == nil
+ end
+
it "returns nil if there is no capture for the given index" do
"hello there".send(@method, /[aeiou](.)\1/, 2).should == nil
- # You can't refer to 0 using negative indices
- "hello there".send(@method, /[aeiou](.)\1/, -2).should == nil
+ end
+
+ it "returns nil if the given capture group was not matched but still sets $~" do
+ "test".send(@method, /te(z)?/, 1).should == nil
+ $~[0].should == "te"
+ $~[1].should == nil
+ end
+
+ it "returns a String in the same encoding as self" do
+ "hello there".encode("US-ASCII").send(@method, /[aeiou](.)\1/, 0).encoding.should == Encoding::US_ASCII
end
it "calls to_int on the given index" do
@@ -476,20 +386,10 @@ describe :string_slice_regexp_index, shared: true do
-> { "hello".send(@method, /(.)(.)(.)/, nil) }.should raise_error(TypeError)
end
- ruby_version_is ''...'3.0' do
- it "returns subclass instances" do
- s = StringSpecs::MyString.new("hello")
- s.send(@method, /(.)(.)/, 0).should be_an_instance_of(StringSpecs::MyString)
- s.send(@method, /(.)(.)/, 1).should be_an_instance_of(StringSpecs::MyString)
- end
- end
-
- ruby_version_is '3.0' do
- it "returns String instances" do
- s = StringSpecs::MyString.new("hello")
- s.send(@method, /(.)(.)/, 0).should be_an_instance_of(String)
- s.send(@method, /(.)(.)/, 1).should be_an_instance_of(String)
- end
+ it "returns String instances" do
+ s = StringSpecs::MyString.new("hello")
+ s.send(@method, /(.)(.)/, 0).should be_an_instance_of(String)
+ s.send(@method, /(.)(.)/, 1).should be_an_instance_of(String)
end
it "sets $~ to MatchData when there is a match and nil when there's none" do
@@ -510,21 +410,6 @@ describe :string_slice_string, shared: true do
"hello there".send(@method, s).should == s
end
- ruby_version_is ''...'2.7' do
- it "taints resulting strings when other is tainted" do
- strs = ["", "hello world", "hello"]
- strs += strs.map { |s| s.dup.taint }
-
- strs.each do |str|
- strs.each do |other|
- r = str.send(@method, other)
-
- r.tainted?.should == !r.nil? & other.tainted?
- end
- end
- end
- end
-
it "doesn't set $~" do
$~ = nil
@@ -543,22 +428,11 @@ describe :string_slice_string, shared: true do
-> { "hello".send(@method, o) }.should raise_error(TypeError)
end
- ruby_version_is ''...'3.0' do
- it "returns a subclass instance when given a subclass instance" do
- s = StringSpecs::MyString.new("el")
- r = "hello".send(@method, s)
- r.should == "el"
- r.should be_an_instance_of(StringSpecs::MyString)
- end
- end
-
- ruby_version_is '3.0' do
- it "returns a String instance when given a subclass instance" do
- s = StringSpecs::MyString.new("el")
- r = "hello".send(@method, s)
- r.should == "el"
- r.should be_an_instance_of(String)
- end
+ it "returns a String instance when given a subclass instance" do
+ s = StringSpecs::MyString.new("el")
+ r = "hello".send(@method, s)
+ r.should == "el"
+ r.should be_an_instance_of(String)
end
end
@@ -584,30 +458,6 @@ describe :string_slice_regexp_group, shared: true do
"hello there".send(@method, /(?<g>h(?<g>.))/, 'g').should == "e"
end
- ruby_version_is ''...'2.7' do
- it "always taints resulting strings when self or regexp is tainted" do
- strs = ["hello world"]
- strs += strs.map { |s| s.dup.taint }
-
- strs.each do |str|
- str.send(@method, /(?<hi>hello)/, 'hi').tainted?.should == str.tainted?
-
- str.send(@method, /(?<g>(.)(.)(.))/, 'g').tainted?.should == str.tainted?
- str.send(@method, /(?<h>.)(.)(.)/, 'h').tainted?.should == str.tainted?
- str.send(@method, /(.)(?<a>.)(.)/, 'a').tainted?.should == str.tainted?
- str.send(@method, /(.)(.)(?<r>.)/, 'r').tainted?.should == str.tainted?
- str.send(@method, /(?<h>.)(?<a>.)(?<r>.)/, 'r').tainted?.should == str.tainted?
-
- tainted_re = /(?<a>.)(?<b>.)(?<c>.)/
- tainted_re.taint
-
- str.send(@method, tainted_re, 'a').tainted?.should be_true
- str.send(@method, tainted_re, 'b').tainted?.should be_true
- str.send(@method, tainted_re, 'c').tainted?.should be_true
- end
- end
- end
-
it "returns nil if there is no match" do
"hello there".send(@method, /(?<whut>what?)/, 'whut').should be_nil
end
@@ -628,18 +478,9 @@ describe :string_slice_regexp_group, shared: true do
-> { "hello".send(@method, /(?<q>)/, '') }.should raise_error(IndexError)
end
- ruby_version_is ''...'3.0' do
- it "returns subclass instances" do
- s = StringSpecs::MyString.new("hello")
- s.send(@method, /(?<q>.)/, 'q').should be_an_instance_of(StringSpecs::MyString)
- end
- end
-
- ruby_version_is '3.0' do
- it "returns String instances" do
- s = StringSpecs::MyString.new("hello")
- s.send(@method, /(?<q>.)/, 'q').should be_an_instance_of(String)
- end
+ it "returns String instances" do
+ s = StringSpecs::MyString.new("hello")
+ s.send(@method, /(?<q>.)/, 'q').should be_an_instance_of(String)
end
it "sets $~ to MatchData when there is a match and nil when there's none" do
diff --git a/spec/ruby/core/string/shared/strip.rb b/spec/ruby/core/string/shared/strip.rb
index 9c232b4694..3af77b50fe 100644
--- a/spec/ruby/core/string/shared/strip.rb
+++ b/spec/ruby/core/string/shared/strip.rb
@@ -2,19 +2,13 @@ require_relative '../../../spec_helper'
require_relative '../fixtures/classes'
describe :string_strip, shared: true do
- ruby_version_is '3.0' do
- it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new(" hello ").send(@method).should be_an_instance_of(String)
- StringSpecs::MyString.new(" ").send(@method).should be_an_instance_of(String)
- StringSpecs::MyString.new("").send(@method).should be_an_instance_of(String)
- end
+ it "returns a String in the same encoding as self" do
+ " hello ".encode("US-ASCII").send(@method).encoding.should == Encoding::US_ASCII
end
- ruby_version_is ''...'3.0' do
- it "returns subclass instances when called on a subclass" do
- StringSpecs::MyString.new(" hello ").send(@method).should be_an_instance_of(StringSpecs::MyString)
- StringSpecs::MyString.new(" ").send(@method).should be_an_instance_of(StringSpecs::MyString)
- StringSpecs::MyString.new("").send(@method).should be_an_instance_of(StringSpecs::MyString)
- end
+ it "returns String instances when called on a subclass" do
+ StringSpecs::MyString.new(" hello ").send(@method).should be_an_instance_of(String)
+ StringSpecs::MyString.new(" ").send(@method).should be_an_instance_of(String)
+ StringSpecs::MyString.new("").send(@method).should be_an_instance_of(String)
end
end
diff --git a/spec/ruby/core/string/shared/succ.rb b/spec/ruby/core/string/shared/succ.rb
index 25602103b6..b69a394875 100644
--- a/spec/ruby/core/string/shared/succ.rb
+++ b/spec/ruby/core/string/shared/succ.rb
@@ -59,34 +59,21 @@ describe :string_succ, shared: true do
"\xFF\xFF".send(@method).should == "\x01\x00\x00"
end
- ruby_version_is ''...'3.0' do
- it "returns subclass instances when called on a subclass" do
- StringSpecs::MyString.new("").send(@method).should be_an_instance_of(StringSpecs::MyString)
- StringSpecs::MyString.new("a").send(@method).should be_an_instance_of(StringSpecs::MyString)
- StringSpecs::MyString.new("z").send(@method).should be_an_instance_of(StringSpecs::MyString)
- end
+ it "returns String instances when called on a subclass" do
+ StringSpecs::MyString.new("").send(@method).should be_an_instance_of(String)
+ StringSpecs::MyString.new("a").send(@method).should be_an_instance_of(String)
+ StringSpecs::MyString.new("z").send(@method).should be_an_instance_of(String)
end
- ruby_version_is '3.0' do
- it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new("").send(@method).should be_an_instance_of(String)
- StringSpecs::MyString.new("a").send(@method).should be_an_instance_of(String)
- StringSpecs::MyString.new("z").send(@method).should be_an_instance_of(String)
- end
- end
-
- ruby_version_is ''...'2.7' do
- it "taints the result if self is tainted" do
- ["", "a", "z", "Z", "9", "\xFF", "\xFF\xFF"].each do |s|
- s.taint.send(@method).should.tainted?
- end
- end
+ it "returns a String in the same encoding as self" do
+ "z".encode("US-ASCII").send(@method).encoding.should == Encoding::US_ASCII
end
end
describe :string_succ_bang, shared: true do
it "is equivalent to succ, but modifies self in place (still returns self)" do
["", "abcd", "THX1138"].each do |s|
+ s = +s
r = s.dup.send(@method)
s.send(@method).should equal(s)
s.should == r
diff --git a/spec/ruby/core/string/shared/to_a.rb b/spec/ruby/core/string/shared/to_a.rb
deleted file mode 100644
index bad3ea6584..0000000000
--- a/spec/ruby/core/string/shared/to_a.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-describe :string_to_a, shared: true do
- it "returns an empty array for empty strings" do
- "".send(@method).should == []
- end
-
- it "returns an array containing the string for non-empty strings" do
- "hello".send(@method).should == ["hello"]
- end
-end
diff --git a/spec/ruby/core/string/shared/to_s.rb b/spec/ruby/core/string/shared/to_s.rb
index b8c9b8ab44..4b87a6cbe1 100644
--- a/spec/ruby/core/string/shared/to_s.rb
+++ b/spec/ruby/core/string/shared/to_s.rb
@@ -10,11 +10,4 @@ describe :string_to_s, shared: true do
s.should == "a string"
s.should be_an_instance_of(String)
end
-
- ruby_version_is ''...'2.7' do
- it "taints the result when self is tainted" do
- "x".taint.send(@method).should.tainted?
- StringSpecs::MyString.new("x").taint.send(@method).should.tainted?
- end
- end
end
diff --git a/spec/ruby/core/string/shared/to_sym.rb b/spec/ruby/core/string/shared/to_sym.rb
index 416f302aef..833eae100e 100644
--- a/spec/ruby/core/string/shared/to_sym.rb
+++ b/spec/ruby/core/string/shared/to_sym.rb
@@ -53,11 +53,20 @@ describe :string_to_sym, shared: true do
sym.to_s.should == binary_string
end
+ it "ignores existing symbols with different encoding" do
+ source = "fée"
+
+ iso_symbol = source.dup.force_encoding(Encoding::ISO_8859_1).send(@method)
+ iso_symbol.encoding.should == Encoding::ISO_8859_1
+ binary_symbol = source.dup.force_encoding(Encoding::BINARY).send(@method)
+ binary_symbol.encoding.should == Encoding::BINARY
+ end
+
it "raises an EncodingError for UTF-8 String containing invalid bytes" do
invalid_utf8 = "\xC3"
invalid_utf8.should_not.valid_encoding?
-> {
invalid_utf8.send(@method)
- }.should raise_error(EncodingError, /invalid/)
+ }.should raise_error(EncodingError, 'invalid symbol in encoding UTF-8 :"\xC3"')
end
end
diff --git a/spec/ruby/core/string/slice_spec.rb b/spec/ruby/core/string/slice_spec.rb
index 83b475c8b5..5aba2d3be0 100644
--- a/spec/ruby/core/string/slice_spec.rb
+++ b/spec/ruby/core/string/slice_spec.rb
@@ -1,5 +1,5 @@
# -*- encoding: utf-8 -*-
-
+# frozen_string_literal: false
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
require_relative 'shared/slice'
@@ -94,16 +94,6 @@ describe "String#slice! with index, length" do
a.should == "h"
end
- ruby_version_is ''...'2.7' do
- it "always taints resulting strings when self is tainted" do
- str = "hello world"
- str.taint
-
- str.slice!(0, 0).should.tainted?
- str.slice!(2, 1).should.tainted?
- end
- end
-
it "returns nil if the given position is out of self" do
a = "hello"
a.slice(10, 3).should == nil
@@ -142,20 +132,10 @@ describe "String#slice! with index, length" do
"hello".slice!(obj, obj).should == "ll"
end
- ruby_version_is ''...'3.0' do
- it "returns subclass instances" do
- s = StringSpecs::MyString.new("hello")
- s.slice!(0, 0).should be_an_instance_of(StringSpecs::MyString)
- s.slice!(0, 4).should be_an_instance_of(StringSpecs::MyString)
- end
- end
-
- ruby_version_is '3.0' do
- it "returns String instances" do
- s = StringSpecs::MyString.new("hello")
- s.slice!(0, 0).should be_an_instance_of(String)
- s.slice!(0, 4).should be_an_instance_of(String)
- end
+ it "returns String instances" do
+ s = StringSpecs::MyString.new("hello")
+ s.slice!(0, 0).should be_an_instance_of(String)
+ s.slice!(0, 4).should be_an_instance_of(String)
end
it "returns the substring given by the character offsets" do
@@ -195,30 +175,10 @@ describe "String#slice! Range" do
b.should == "hello"
end
- ruby_version_is ''...'2.7' do
- it "always taints resulting strings when self is tainted" do
- str = "hello world"
- str.taint
-
- str.slice!(0..0).should.tainted?
- str.slice!(2..3).should.tainted?
- end
- end
-
- ruby_version_is ''...'3.0' do
- it "returns subclass instances" do
- s = StringSpecs::MyString.new("hello")
- s.slice!(0...0).should be_an_instance_of(StringSpecs::MyString)
- s.slice!(0..4).should be_an_instance_of(StringSpecs::MyString)
- end
- end
-
- ruby_version_is '3.0' do
- it "returns String instances" do
- s = StringSpecs::MyString.new("hello")
- s.slice!(0...0).should be_an_instance_of(String)
- s.slice!(0..4).should be_an_instance_of(String)
- end
+ it "returns String instances" do
+ s = StringSpecs::MyString.new("hello")
+ s.slice!(0...0).should be_an_instance_of(String)
+ s.slice!(0..4).should be_an_instance_of(String)
end
it "calls to_int on range arguments" do
@@ -294,44 +254,10 @@ describe "String#slice! with Regexp" do
s.should == "this is a string"
end
- ruby_version_is ''...'2.7' do
- it "always taints resulting strings when self or regexp is tainted" do
- strs = ["hello world"]
- strs += strs.map { |s| s.dup.taint }
-
- strs.each do |str|
- str = str.dup
- str.slice!(//).tainted?.should == str.tainted?
- str.slice!(/hello/).tainted?.should == str.tainted?
-
- tainted_re = /./
- tainted_re.taint
-
- str.slice!(tainted_re).should.tainted?
- end
- end
-
- it "doesn't taint self when regexp is tainted" do
- s = "hello"
- s.slice!(/./.taint)
- s.should_not.tainted?
- end
- end
-
- ruby_version_is ''...'3.0' do
- it "returns subclass instances" do
- s = StringSpecs::MyString.new("hello")
- s.slice!(//).should be_an_instance_of(StringSpecs::MyString)
- s.slice!(/../).should be_an_instance_of(StringSpecs::MyString)
- end
- end
-
- ruby_version_is '3.0' do
- it "returns String instances" do
- s = StringSpecs::MyString.new("hello")
- s.slice!(//).should be_an_instance_of(String)
- s.slice!(/../).should be_an_instance_of(String)
- end
+ it "returns String instances" do
+ s = StringSpecs::MyString.new("hello")
+ s.slice!(//).should be_an_instance_of(String)
+ s.slice!(/../).should be_an_instance_of(String)
end
it "returns the matching portion of self with a multi byte character" do
@@ -365,30 +291,6 @@ describe "String#slice! with Regexp, index" do
str.should == "ho here"
end
- ruby_version_is ''...'2.7' do
- it "always taints resulting strings when self or regexp is tainted" do
- strs = ["hello world"]
- strs += strs.map { |s| s.dup.taint }
-
- strs.each do |str|
- str = str.dup
- str.slice!(//, 0).tainted?.should == str.tainted?
- str.slice!(/hello/, 0).tainted?.should == str.tainted?
-
- tainted_re = /(.)(.)(.)/
- tainted_re.taint
-
- str.slice!(tainted_re, 1).should.tainted?
- end
- end
-
- it "doesn't taint self when regexp is tainted" do
- s = "hello"
- s.slice!(/(.)(.)/.taint, 1)
- s.should_not.tainted?
- end
- end
-
it "returns nil if there was no match" do
s = "this is a string"
s.slice!(/x(zzz)/, 1).should == nil
@@ -412,20 +314,10 @@ describe "String#slice! with Regexp, index" do
"har".slice!(/(.)(.)(.)/, obj).should == "a"
end
- ruby_version_is ''...'3.0' do
- it "returns subclass instances" do
- s = StringSpecs::MyString.new("hello")
- s.slice!(/(.)(.)/, 0).should be_an_instance_of(StringSpecs::MyString)
- s.slice!(/(.)(.)/, 1).should be_an_instance_of(StringSpecs::MyString)
- end
- end
-
- ruby_version_is '3.0' do
- it "returns String instances" do
- s = StringSpecs::MyString.new("hello")
- s.slice!(/(.)(.)/, 0).should be_an_instance_of(String)
- s.slice!(/(.)(.)/, 1).should be_an_instance_of(String)
- end
+ it "returns String instances" do
+ s = StringSpecs::MyString.new("hello")
+ s.slice!(/(.)(.)/, 0).should be_an_instance_of(String)
+ s.slice!(/(.)(.)/, 1).should be_an_instance_of(String)
end
it "returns the encoding aware capture for the given index" do
@@ -463,23 +355,6 @@ describe "String#slice! with String" do
c.should == "he hello"
end
- ruby_version_is ''...'2.7' do
- it "taints resulting strings when other is tainted" do
- strs = ["", "hello world", "hello"]
- strs += strs.map { |s| s.dup.taint }
-
- strs.each do |str|
- str = str.dup
- strs.each do |other|
- other = other.dup
- r = str.slice!(other)
-
- r.tainted?.should == !r.nil? & other.tainted?
- end
- end
- end
- end
-
it "doesn't set $~" do
$~ = nil
@@ -500,22 +375,11 @@ describe "String#slice! with String" do
-> { "hello".slice!(o) }.should raise_error(TypeError)
end
- ruby_version_is ''...'3.0' do
- it "returns a subclass instance when given a subclass instance" do
- s = StringSpecs::MyString.new("el")
- r = "hello".slice!(s)
- r.should == "el"
- r.should be_an_instance_of(StringSpecs::MyString)
- end
- end
-
- ruby_version_is '3.0' do
- it "returns a subclass instance when given a subclass instance" do
- s = StringSpecs::MyString.new("el")
- r = "hello".slice!(s)
- r.should == "el"
- r.should be_an_instance_of(String)
- end
+ it "returns a subclass instance when given a subclass instance" do
+ s = StringSpecs::MyString.new("el")
+ r = "hello".slice!(s)
+ r.should == "el"
+ r.should be_an_instance_of(String)
end
it "raises a FrozenError if self is frozen" do
diff --git a/spec/ruby/core/string/split_spec.rb b/spec/ruby/core/string/split_spec.rb
index 94f6c9aaee..3c6d1864d1 100644
--- a/spec/ruby/core/string/split_spec.rb
+++ b/spec/ruby/core/string/split_spec.rb
@@ -3,12 +3,17 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "String#split with String" do
+ it "throws an ArgumentError if the string is not a valid" do
+ s = "\xDF".dup.force_encoding(Encoding::UTF_8)
+
+ -> { s.split }.should raise_error(ArgumentError)
+ -> { s.split(':') }.should raise_error(ArgumentError)
+ end
+
it "throws an ArgumentError if the pattern is not a valid string" do
str = 'проверка'
- broken_str = 'проверка'
- broken_str.force_encoding('binary')
- broken_str.chop!
- broken_str.force_encoding('utf-8')
+ broken_str = "\xDF".dup.force_encoding(Encoding::UTF_8)
+
-> { str.split(broken_str) }.should raise_error(ArgumentError)
end
@@ -24,9 +29,35 @@ describe "String#split with String" do
"1,2,,3,4,,".split(',').should == ["1", "2", "", "3", "4"]
"1,2,,3,4,,".split(',', 0).should == ["1", "2", "", "3", "4"]
" a b c\nd ".split(" ").should == ["", "a", "b", "c\nd"]
+ " a あ c\nd ".split(" ").should == ["", "a", "あ", "c\nd"]
"hai".split("hai").should == []
",".split(",").should == []
",".split(",", 0).should == []
+ "あ".split("あ").should == []
+ "あ".split("あ", 0).should == []
+ end
+
+ it "does not suppress trailing empty fields when a positive limit is given" do
+ " 1 2 ".split(" ", 2).should == ["1", "2 "]
+ " 1 2 ".split(" ", 3).should == ["1", "2", ""]
+ " 1 2 ".split(" ", 4).should == ["1", "2", ""]
+ " 1 あ ".split(" ", 2).should == ["1", "あ "]
+ " 1 あ ".split(" ", 3).should == ["1", "あ", ""]
+ " 1 あ ".split(" ", 4).should == ["1", "あ", ""]
+
+ "1,2,".split(',', 2).should == ["1", "2,"]
+ "1,2,".split(',', 3).should == ["1", "2", ""]
+ "1,2,".split(',', 4).should == ["1", "2", ""]
+ "1,あ,".split(',', 2).should == ["1", "あ,"]
+ "1,あ,".split(',', 3).should == ["1", "あ", ""]
+ "1,あ,".split(',', 4).should == ["1", "あ", ""]
+
+ "1 2 ".split(/ /, 2).should == ["1", "2 "]
+ "1 2 ".split(/ /, 3).should == ["1", "2", ""]
+ "1 2 ".split(/ /, 4).should == ["1", "2", ""]
+ "1 あ ".split(/ /, 2).should == ["1", "あ "]
+ "1 あ ".split(/ /, 3).should == ["1", "あ", ""]
+ "1 あ ".split(/ /, 4).should == ["1", "あ", ""]
end
it "returns an array with one entry if limit is 1: the original string" do
@@ -89,21 +120,19 @@ describe "String#split with String" do
end
end
- ruby_version_is "2.7" do
- context "when $; is not nil" do
- before do
- suppress_warning do
- @old_value, $; = $;, 'foobar'
- end
+ context "when $; is not nil" do
+ before do
+ suppress_warning do
+ @old_value, $; = $;, 'foobar'
end
+ end
- after do
- $; = @old_value
- end
+ after do
+ $; = @old_value
+ end
- it "warns" do
- -> { "".split }.should complain(/warning: \$; is set to non-nil value/)
- end
+ it "warns" do
+ -> { "".split }.should complain(/warning: \$; is set to non-nil value/)
end
end
end
@@ -163,70 +192,48 @@ describe "String#split with String" do
"foo".split("bar", 3).should == ["foo"]
end
- ruby_version_is ''...'3.0' do
- it "returns subclass instances based on self" do
- ["", "x.y.z.", " x y "].each do |str|
- ["", ".", " "].each do |pat|
- [-1, 0, 1, 2].each do |limit|
- StringSpecs::MyString.new(str).split(pat, limit).each do |x|
- x.should be_an_instance_of(StringSpecs::MyString)
- end
+ it "returns String instances based on self" do
+ ["", "x.y.z.", " x y "].each do |str|
+ ["", ".", " "].each do |pat|
+ [-1, 0, 1, 2].each do |limit|
+ StringSpecs::MyString.new(str).split(pat, limit).each do |x|
+ x.should be_an_instance_of(String)
+ end
- str.split(StringSpecs::MyString.new(pat), limit).each do |x|
- x.should be_an_instance_of(String)
- end
+ str.split(StringSpecs::MyString.new(pat), limit).each do |x|
+ x.should be_an_instance_of(String)
end
end
end
end
-
- it "does not call constructor on created subclass instances" do
- # can't call should_not_receive on an object that doesn't yet exist
- # so failure here is signalled by exception, not expectation failure
-
- s = StringSpecs::StringWithRaisingConstructor.new('silly:string')
- s.split(':').first.should == 'silly'
- end
end
- ruby_version_is '3.0' do
- it "returns String instances based on self" do
- ["", "x.y.z.", " x y "].each do |str|
- ["", ".", " "].each do |pat|
- [-1, 0, 1, 2].each do |limit|
- StringSpecs::MyString.new(str).split(pat, limit).each do |x|
- x.should be_an_instance_of(String)
- end
+ it "returns an empty array when whitespace is split on whitespace" do
+ " ".split(" ").should == []
+ " \n ".split(" ").should == []
+ " ".split(" ").should == []
+ " \t ".split(" ").should == []
+ end
- str.split(StringSpecs::MyString.new(pat), limit).each do |x|
- x.should be_an_instance_of(String)
- end
- end
- end
- end
- end
+ it "doesn't split on non-ascii whitespace" do
+ "a\u{2008}b".split(" ").should == ["a\u{2008}b"]
end
- ruby_version_is ''...'2.7' do
- it "taints the resulting strings if self is tainted" do
- ["", "x.y.z.", " x y "].each do |str|
- ["", ".", " "].each do |pat|
- [-1, 0, 1, 2].each do |limit|
- str.dup.taint.split(pat).each do |x|
- x.should.tainted?
- end
+ it "returns Strings in the same encoding as self" do
+ strings = "hello world".encode("US-ASCII").split(" ")
- str.split(pat.dup.taint).each do |x|
- x.should_not.tainted?
- end
- end
- end
- end
- end
+ strings[0].encoding.should == Encoding::US_ASCII
+ strings[1].encoding.should == Encoding::US_ASCII
end
end
describe "String#split with Regexp" do
+ it "throws an ArgumentError if the string is not a valid" do
+ s = "\xDF".dup.force_encoding(Encoding::UTF_8)
+
+ -> { s.split(/./) }.should raise_error(ArgumentError)
+ end
+
it "divides self on regexp matches" do
" now's the time".split(/ /).should == ["", "now's", "", "the", "time"]
" x\ny ".split(/ /).should == ["", "x\ny"]
@@ -379,86 +386,30 @@ describe "String#split with Regexp" do
"foo".split(/bar/, 3).should == ["foo"]
end
- ruby_version_is ''...'3.0' do
- it "returns subclass instances based on self" do
- ["", "x:y:z:", " x y "].each do |str|
- [//, /:/, /\s+/].each do |pat|
- [-1, 0, 1, 2].each do |limit|
- StringSpecs::MyString.new(str).split(pat, limit).each do |x|
- x.should be_an_instance_of(StringSpecs::MyString)
- end
+ it "returns String instances based on self" do
+ ["", "x:y:z:", " x y "].each do |str|
+ [//, /:/, /\s+/].each do |pat|
+ [-1, 0, 1, 2].each do |limit|
+ StringSpecs::MyString.new(str).split(pat, limit).each do |x|
+ x.should be_an_instance_of(String)
end
end
end
end
-
- it "does not call constructor on created subclass instances" do
- # can't call should_not_receive on an object that doesn't yet exist
- # so failure here is signalled by exception, not expectation failure
-
- s = StringSpecs::StringWithRaisingConstructor.new('silly:string')
- s.split(/:/).first.should == 'silly'
- end
end
- ruby_version_is '3.0' do
- it "returns String instances based on self" do
- ["", "x:y:z:", " x y "].each do |str|
- [//, /:/, /\s+/].each do |pat|
- [-1, 0, 1, 2].each do |limit|
- StringSpecs::MyString.new(str).split(pat, limit).each do |x|
- x.should be_an_instance_of(String)
- end
- end
- end
- end
- end
- end
-
- ruby_version_is ''...'2.7' do
- it "taints the resulting strings if self is tainted" do
- ["", "x:y:z:", " x y "].each do |str|
- [//, /:/, /\s+/].each do |pat|
- [-1, 0, 1, 2].each do |limit|
- str.dup.taint.split(pat, limit).each do |x|
- # See the spec below for why the conditional is here
- x.tainted?.should be_true unless x.empty?
- end
- end
- end
- end
- end
-
- it "taints an empty string if self is tainted" do
- ":".taint.split(//, -1).last.tainted?.should be_true
- end
-
- it "doesn't taints the resulting strings if the Regexp is tainted" do
- ["", "x:y:z:", " x y "].each do |str|
- [//, /:/, /\s+/].each do |pat|
- [-1, 0, 1, 2].each do |limit|
- str.split(pat.dup.taint, limit).each do |x|
- x.tainted?.should be_false
- end
- end
- end
- end
- end
- end
-
- it "retains the encoding of the source string" do
+ it "returns Strings in the same encoding as self" do
ary = "а б в".split
encodings = ary.map { |s| s.encoding }
encodings.should == [Encoding::UTF_8, Encoding::UTF_8, Encoding::UTF_8]
end
-
it "splits a string on each character for a multibyte encoding and empty split" do
"That's why efficiency could not be helped".split("").size.should == 39
end
it "returns an ArgumentError if an invalid UTF-8 string is supplied" do
- broken_str = 'проверка' # in russian, means "test"
+ broken_str = +'проверка' # in russian, means "test"
broken_str.force_encoding('binary')
broken_str.chop!
broken_str.force_encoding('utf-8')
@@ -484,6 +435,14 @@ describe "String#split with Regexp" do
a.should == ["Chunky", "Bacon"]
end
+ it "yields each split substring with default pattern for a lazy substring" do
+ a = []
+ returned_object = "chunky bacon"[1...-1].split { |str| a << str.capitalize }
+
+ returned_object.should == "hunky baco"
+ a.should == ["Hunky", "Baco"]
+ end
+
it "yields each split substring with default pattern for a non-ASCII string" do
a = []
returned_object = "l'été arrive bientôt".split { |str| a << str }
@@ -492,6 +451,14 @@ describe "String#split with Regexp" do
a.should == ["l'été", "arrive", "bientôt"]
end
+ it "yields each split substring with default pattern for a non-ASCII lazy substring" do
+ a = []
+ returned_object = "l'été arrive bientôt"[1...-1].split { |str| a << str }
+
+ returned_object.should == "'été arrive bientô"
+ a.should == ["'été", "arrive", "bientô"]
+ end
+
it "yields the string when limit is 1" do
a = []
returned_object = "chunky bacon".split("", 1) { |str| a << str.capitalize }
@@ -550,32 +517,30 @@ describe "String#split with Regexp" do
end
describe "for a String subclass" do
- ruby_version_is ''...'3.0' do
- it "yields instances of the same subclass" do
- a = []
- StringSpecs::MyString.new("a|b").split("|") { |str| a << str }
- first, last = a
+ it "yields instances of String" do
+ a = []
+ StringSpecs::MyString.new("a|b").split("|") { |str| a << str }
+ first, last = a
- first.should be_an_instance_of(StringSpecs::MyString)
- first.should == "a"
+ first.should be_an_instance_of(String)
+ first.should == "a"
- last.should be_an_instance_of(StringSpecs::MyString)
- last.should == "b"
- end
+ last.should be_an_instance_of(String)
+ last.should == "b"
end
+ end
- ruby_version_is '3.0' do
- it "yields instances of String" do
- a = []
- StringSpecs::MyString.new("a|b").split("|") { |str| a << str }
- first, last = a
+ it "raises a TypeError when not called with nil, String, or Regexp" do
+ -> { "hello".split(42) }.should raise_error(TypeError)
+ -> { "hello".split(:ll) }.should raise_error(TypeError)
+ -> { "hello".split(false) }.should raise_error(TypeError)
+ -> { "hello".split(Object.new) }.should raise_error(TypeError)
+ end
- first.should be_an_instance_of(String)
- first.should == "a"
+ it "returns Strings in the same encoding as self" do
+ strings = "hello world".encode("US-ASCII").split(/ /)
- last.should be_an_instance_of(String)
- last.should == "b"
- end
- end
+ strings[0].encoding.should == Encoding::US_ASCII
+ strings[1].encoding.should == Encoding::US_ASCII
end
end
diff --git a/spec/ruby/core/string/squeeze_spec.rb b/spec/ruby/core/string/squeeze_spec.rb
index 6f75402c9c..4ea238e6b5 100644
--- a/spec/ruby/core/string/squeeze_spec.rb
+++ b/spec/ruby/core/string/squeeze_spec.rb
@@ -1,4 +1,5 @@
# -*- encoding: binary -*-
+# frozen_string_literal: false
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
@@ -54,16 +55,6 @@ describe "String#squeeze" do
-> { s.squeeze("^e-b") }.should raise_error(ArgumentError)
end
- ruby_version_is ''...'2.7' do
- it "taints the result when self is tainted" do
- "hello".taint.squeeze("e").should.tainted?
- "hello".taint.squeeze("a-z").should.tainted?
-
- "hello".squeeze("e".taint).should_not.tainted?
- "hello".squeeze("l".taint).should_not.tainted?
- end
- end
-
it "tries to convert each set arg to a string using to_str" do
other_string = mock('lo')
other_string.should_receive(:to_str).and_return("lo")
@@ -74,22 +65,19 @@ describe "String#squeeze" do
"hello room".squeeze(other_string, other_string2).should == "hello rom"
end
+ it "returns a String in the same encoding as self" do
+ "yellow moon".encode("US-ASCII").squeeze.encoding.should == Encoding::US_ASCII
+ "yellow moon".encode("US-ASCII").squeeze("a").encoding.should == Encoding::US_ASCII
+ end
+
it "raises a TypeError when one set arg can't be converted to a string" do
-> { "hello world".squeeze([]) }.should raise_error(TypeError)
-> { "hello world".squeeze(Object.new)}.should raise_error(TypeError)
-> { "hello world".squeeze(mock('x')) }.should raise_error(TypeError)
end
- ruby_version_is ''...'3.0' do
- it "returns subclass instances when called on a subclass" do
- StringSpecs::MyString.new("oh no!!!").squeeze("!").should be_an_instance_of(StringSpecs::MyString)
- end
- end
-
- ruby_version_is '3.0' do
- it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new("oh no!!!").squeeze("!").should be_an_instance_of(String)
- end
+ it "returns String instances when called on a subclass" do
+ StringSpecs::MyString.new("oh no!!!").squeeze("!").should be_an_instance_of(String)
end
end
diff --git a/spec/ruby/core/string/start_with_spec.rb b/spec/ruby/core/string/start_with_spec.rb
index aaed197ff3..35e33b46a6 100644
--- a/spec/ruby/core/string/start_with_spec.rb
+++ b/spec/ruby/core/string/start_with_spec.rb
@@ -5,4 +5,23 @@ require_relative '../../shared/string/start_with'
describe "String#start_with?" do
it_behaves_like :start_with, :to_s
+
+ # Here and not in the shared examples because this is invalid as a Symbol
+ it "matches part of a character with the same part" do
+ "\xA9".should.start_with?("\xA9") # A9 is not a character head for UTF-8
+ end
+
+ ruby_version_is ""..."3.3" do
+ it "does not check we are matching only part of a character" do
+ "\xe3\x81\x82".size.should == 1
+ "\xe3\x81\x82".should.start_with?("\xe3")
+ end
+ end
+
+ ruby_version_is "3.3" do # #19784
+ it "checks we are matching only part of a character" do
+ "\xe3\x81\x82".size.should == 1
+ "\xe3\x81\x82".should_not.start_with?("\xe3")
+ end
+ end
end
diff --git a/spec/ruby/core/string/strip_spec.rb b/spec/ruby/core/string/strip_spec.rb
index 8517bf2d2a..edb6ea3b44 100644
--- a/spec/ruby/core/string/strip_spec.rb
+++ b/spec/ruby/core/string/strip_spec.rb
@@ -1,3 +1,4 @@
+# frozen_string_literal: false
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
require_relative 'shared/strip'
@@ -11,18 +12,8 @@ describe "String#strip" do
"\tgoodbye\r\v\n".strip.should == "goodbye"
end
- ruby_version_is '3.1' do
- it "returns a copy of self without leading and trailing NULL bytes and whitespace" do
- " \x00 goodbye \x00 ".strip.should == "goodbye"
- end
- end
-
- ruby_version_is ''...'2.7' do
- it "taints the result when self is tainted" do
- "".taint.strip.should.tainted?
- "ok".taint.strip.should.tainted?
- " ok ".taint.strip.should.tainted?
- end
+ it "returns a copy of self without leading and trailing NULL bytes and whitespace" do
+ " \x00 goodbye \x00 ".strip.should == "goodbye"
end
end
@@ -43,12 +34,16 @@ describe "String#strip!" do
a.should == "hello"
end
- ruby_version_is '3.1' do
- it "removes leading and trailing NULL bytes and whitespace" do
- a = "\000 goodbye \000"
- a.strip!
- a.should == "goodbye"
- end
+ it "makes a string empty if it is only whitespace" do
+ "".strip!.should == nil
+ " ".strip.should == ""
+ " ".strip.should == ""
+ end
+
+ it "removes leading and trailing NULL bytes and whitespace" do
+ a = "\000 goodbye \000"
+ a.strip!
+ a.should == "goodbye"
end
it "raises a FrozenError on a frozen instance that is modified" do
diff --git a/spec/ruby/core/string/sub_spec.rb b/spec/ruby/core/string/sub_spec.rb
index 5ae9a4bbf3..4f9f87a433 100644
--- a/spec/ruby/core/string/sub_spec.rb
+++ b/spec/ruby/core/string/sub_spec.rb
@@ -1,3 +1,4 @@
+# frozen_string_literal: false
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
@@ -137,28 +138,6 @@ describe "String#sub with pattern, replacement" do
"hello".sub(/./, 'hah\\').should == 'hah\\ello'
end
- ruby_version_is ''...'2.7' do
- it "taints the result if the original string or replacement is tainted" do
- hello = "hello"
- hello_t = "hello"
- a = "a"
- a_t = "a"
- empty = ""
- empty_t = ""
-
- hello_t.taint; a_t.taint; empty_t.taint
-
- hello_t.sub(/./, a).should.tainted?
- hello_t.sub(/./, empty).should.tainted?
-
- hello.sub(/./, a_t).should.tainted?
- hello.sub(/./, empty_t).should.tainted?
- hello.sub(//, empty_t).should.tainted?
-
- hello.sub(//.taint, "foo").should_not.tainted?
- end
- end
-
it "tries to convert pattern to a string using to_str" do
pattern = mock('.')
pattern.should_receive(:to_str).and_return(".")
@@ -192,22 +171,11 @@ describe "String#sub with pattern, replacement" do
-> { "hello".sub(/[aeiou]/, 99) }.should raise_error(TypeError)
end
- ruby_version_is ''...'3.0' do
- it "returns subclass instances when called on a subclass" do
- StringSpecs::MyString.new("").sub(//, "").should be_an_instance_of(StringSpecs::MyString)
- StringSpecs::MyString.new("").sub(/foo/, "").should be_an_instance_of(StringSpecs::MyString)
- StringSpecs::MyString.new("foo").sub(/foo/, "").should be_an_instance_of(StringSpecs::MyString)
- StringSpecs::MyString.new("foo").sub("foo", "").should be_an_instance_of(StringSpecs::MyString)
- end
- end
-
- ruby_version_is '3.0' do
- it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new("").sub(//, "").should be_an_instance_of(String)
- StringSpecs::MyString.new("").sub(/foo/, "").should be_an_instance_of(String)
- StringSpecs::MyString.new("foo").sub(/foo/, "").should be_an_instance_of(String)
- StringSpecs::MyString.new("foo").sub("foo", "").should be_an_instance_of(String)
- end
+ it "returns String instances when called on a subclass" do
+ StringSpecs::MyString.new("").sub(//, "").should be_an_instance_of(String)
+ StringSpecs::MyString.new("").sub(/foo/, "").should be_an_instance_of(String)
+ StringSpecs::MyString.new("foo").sub(/foo/, "").should be_an_instance_of(String)
+ StringSpecs::MyString.new("foo").sub("foo", "").should be_an_instance_of(String)
end
it "sets $~ to MatchData of match and nil when there's none" do
@@ -236,6 +204,17 @@ describe "String#sub with pattern, replacement" do
"ababa".sub(/(b)/, '\\\\\1').should == "a\\baba"
end
+ it "handles a pattern in a superset encoding" do
+ result = 'abc'.force_encoding(Encoding::US_ASCII).sub('é', 'è')
+ result.should == 'abc'
+ result.encoding.should == Encoding::US_ASCII
+ end
+
+ it "handles a pattern in a subset encoding" do
+ result = 'été'.sub('t'.force_encoding(Encoding::US_ASCII), 'u')
+ result.should == 'éué'
+ result.encoding.should == Encoding::UTF_8
+ end
end
describe "String#sub with pattern and block" do
@@ -297,28 +276,6 @@ describe "String#sub with pattern and block" do
obj.should_receive(:to_s).and_return("ok")
"hello".sub(/.+/) { obj }.should == "ok"
end
-
- ruby_version_is ''...'2.7' do
- it "taints the result if the original string or replacement is tainted" do
- hello = "hello"
- hello_t = "hello"
- a = "a"
- a_t = "a"
- empty = ""
- empty_t = ""
-
- hello_t.taint; a_t.taint; empty_t.taint
-
- hello_t.sub(/./) { a }.should.tainted?
- hello_t.sub(/./) { empty }.should.tainted?
-
- hello.sub(/./) { a_t }.should.tainted?
- hello.sub(/./) { empty_t }.should.tainted?
- hello.sub(//) { empty_t }.should.tainted?
-
- hello.sub(//.taint) { "foo" }.should_not.tainted?
- end
- end
end
describe "String#sub! with pattern, replacement" do
@@ -328,14 +285,6 @@ describe "String#sub! with pattern, replacement" do
a.should == "h*llo"
end
- ruby_version_is ''...'2.7' do
- it "taints self if replacement is tainted" do
- a = "hello"
- a.sub!(/./.taint, "foo").should_not.tainted?
- a.sub!(/./, "foo".taint).should.tainted?
- end
- end
-
it "returns nil if no modifications were made" do
a = "hello"
a.sub!(/z/, '*').should == nil
@@ -351,6 +300,27 @@ describe "String#sub! with pattern, replacement" do
-> { s.sub!(/e/, "e") }.should raise_error(FrozenError)
-> { s.sub!(/[aeiou]/, '*') }.should raise_error(FrozenError)
end
+
+ it "handles a pattern in a superset encoding" do
+ string = 'abc'.force_encoding(Encoding::US_ASCII)
+
+ result = string.sub!('é', 'è')
+
+ result.should == nil
+ string.should == 'abc'
+ string.encoding.should == Encoding::US_ASCII
+ end
+
+ it "handles a pattern in a subset encoding" do
+ string = 'été'
+ pattern = 't'.force_encoding(Encoding::US_ASCII)
+
+ result = string.sub!(pattern, 'u')
+
+ result.should == string
+ string.should == 'éué'
+ string.encoding.should == Encoding::UTF_8
+ end
end
describe "String#sub! with pattern and block" do
@@ -378,14 +348,6 @@ describe "String#sub! with pattern and block" do
offsets.should == [[1, 2]]
end
- ruby_version_is ''...'2.7' do
- it "taints self if block's result is tainted" do
- a = "hello"
- a.sub!(/./.taint) { "foo" }.should_not.tainted?
- a.sub!(/./) { "foo".taint }.should.tainted?
- end
- end
-
it "returns nil if no modifications were made" do
a = "hello"
a.sub!(/z/) { '*' }.should == nil
@@ -471,28 +433,6 @@ describe "String#sub with pattern and Hash" do
"hello".sub(/(.+)/, 'hello' => repl ).should == repl
end
- ruby_version_is ''...'2.7' do
- it "untrusts the result if the original string is untrusted" do
- str = "Ghana".untrust
- str.sub(/[Aa]na/, 'ana' => '').untrusted?.should be_true
- end
-
- it "untrusts the result if a hash value is untrusted" do
- str = "Ghana"
- str.sub(/a$/, 'a' => 'di'.untrust).untrusted?.should be_true
- end
-
- it "taints the result if the original string is tainted" do
- str = "Ghana".taint
- str.sub(/[Aa]na/, 'ana' => '').tainted?.should be_true
- end
-
- it "taints the result if a hash value is tainted" do
- str = "Ghana"
- str.sub(/a$/, 'a' => 'di'.taint).tainted?.should be_true
- end
- end
-
end
describe "String#sub! with pattern and Hash" do
@@ -557,28 +497,6 @@ describe "String#sub! with pattern and Hash" do
repl = '\& \0 \1 \` \\\' \+ \\\\ foo'
"hello".sub!(/(.+)/, 'hello' => repl ).should == repl
end
-
- ruby_version_is ''...'2.7' do
- it "keeps untrusted state" do
- str = "Ghana".untrust
- str.sub!(/[Aa]na/, 'ana' => '').untrusted?.should be_true
- end
-
- it "untrusts self if a hash value is untrusted" do
- str = "Ghana"
- str.sub!(/a$/, 'a' => 'di'.untrust).untrusted?.should be_true
- end
-
- it "keeps tainted state" do
- str = "Ghana".taint
- str.sub!(/[Aa]na/, 'ana' => '').tainted?.should be_true
- end
-
- it "taints self if a hash value is tainted" do
- str = "Ghana"
- str.sub!(/a$/, 'a' => 'di'.taint).tainted?.should be_true
- end
- end
end
describe "String#sub with pattern and without replacement and block" do
diff --git a/spec/ruby/core/string/swapcase_spec.rb b/spec/ruby/core/string/swapcase_spec.rb
index 32b358607e..7f4c68366d 100644
--- a/spec/ruby/core/string/swapcase_spec.rb
+++ b/spec/ruby/core/string/swapcase_spec.rb
@@ -1,4 +1,5 @@
# -*- encoding: utf-8 -*-
+# frozen_string_literal: false
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
@@ -9,11 +10,8 @@ describe "String#swapcase" do
"+++---111222???".swapcase.should == "+++---111222???"
end
- ruby_version_is ''...'2.7' do
- it "taints resulting string when self is tainted" do
- "".taint.swapcase.should.tainted?
- "hello".taint.swapcase.should.tainted?
- end
+ it "returns a String in the same encoding as self" do
+ "Hello".encode("US-ASCII").swapcase.encoding.should == Encoding::US_ASCII
end
describe "full Unicode case mapping" do
@@ -35,6 +33,10 @@ describe "String#swapcase" do
it "does not swapcase non-ASCII characters" do
"aßet".swapcase(:ascii).should == "AßET"
end
+
+ it "works with substrings" do
+ "prefix aTé"[-3..-1].swapcase(:ascii).should == "Até"
+ end
end
describe "full Unicode case mapping adapted for Turkic languages" do
@@ -73,18 +75,9 @@ describe "String#swapcase" do
-> { "abc".swapcase(:invalid_option) }.should raise_error(ArgumentError)
end
- ruby_version_is ''...'3.0' do
- it "returns subclass instances when called on a subclass" do
- StringSpecs::MyString.new("").swapcase.should be_an_instance_of(StringSpecs::MyString)
- StringSpecs::MyString.new("hello").swapcase.should be_an_instance_of(StringSpecs::MyString)
- end
- end
-
- ruby_version_is '3.0' do
- it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new("").swapcase.should be_an_instance_of(String)
- StringSpecs::MyString.new("hello").swapcase.should be_an_instance_of(String)
- end
+ it "returns String instances when called on a subclass" do
+ StringSpecs::MyString.new("").swapcase.should be_an_instance_of(String)
+ StringSpecs::MyString.new("hello").swapcase.should be_an_instance_of(String)
end
end
diff --git a/spec/ruby/core/string/to_c_spec.rb b/spec/ruby/core/string/to_c_spec.rb
index 9c84b14f4d..9d24f1f56c 100644
--- a/spec/ruby/core/string/to_c_spec.rb
+++ b/spec/ruby/core/string/to_c_spec.rb
@@ -1,99 +1,53 @@
require_relative '../../spec_helper'
+require_relative '../../shared/kernel/complex'
+require_relative 'fixtures/to_c'
describe "String#to_c" do
- it "returns a Complex object" do
- '9'.to_c.should be_an_instance_of(Complex)
- end
-
- it "understands integers" do
- '20'.to_c.should == Complex(20)
- end
-
- it "understands negative integers" do
- '-3'.to_c.should == Complex(-3)
- end
-
- it "understands fractions (numerator/denominator) for the real part" do
- '2/3'.to_c.should == Complex(Rational(2, 3))
- end
-
- it "understands fractions (numerator/denominator) for the imaginary part" do
- '4+2/3i'.to_c.should == Complex(4, Rational(2, 3))
- end
-
- it "understands negative fractions (-numerator/denominator) for the real part" do
- '-2/3'.to_c.should == Complex(Rational(-2, 3))
- end
-
- it "understands negative fractions (-numerator/denominator) for the imaginary part" do
- '7-2/3i'.to_c.should == Complex(7, Rational(-2, 3))
- end
-
- it "understands floats (a.b) for the real part" do
- '2.3'.to_c.should == Complex(2.3)
- end
-
- it "understands floats (a.b) for the imaginary part" do
- '4+2.3i'.to_c.should == Complex(4, 2.3)
- end
-
- it "understands negative floats (-a.b) for the real part" do
- '-2.33'.to_c.should == Complex(-2.33)
- end
-
- it "understands negative floats (-a.b) for the imaginary part" do
- '7-28.771i'.to_c.should == Complex(7, -28.771)
- end
-
- it "understands an integer followed by 'i' to mean that integer is the imaginary part" do
- '35i'.to_c.should == Complex(0,35)
- end
-
- it "understands a negative integer followed by 'i' to mean that negative integer is the imaginary part" do
- '-29i'.to_c.should == Complex(0,-29)
- end
-
- it "understands an 'i' by itself as denoting a complex number with an imaginary part of 1" do
- 'i'.to_c.should == Complex(0,1)
- end
-
- it "understands a '-i' by itself as denoting a complex number with an imaginary part of -1" do
- '-i'.to_c.should == Complex(0,-1)
- end
-
- it "understands 'a+bi' to mean a complex number with 'a' as the real part, 'b' as the imaginary" do
- '79+4i'.to_c.should == Complex(79,4)
- end
+ it_behaves_like :kernel_complex, :to_c_method, StringSpecs
+end
- it "understands 'a-bi' to mean a complex number with 'a' as the real part, '-b' as the imaginary" do
- '79-4i'.to_c.should == Complex(79,-4)
+describe "String#to_c" do
+ it "returns a complex number with 0 as the real part, 0 as the imaginary part for unrecognised Strings" do
+ 'ruby'.to_c.should == Complex(0, 0)
end
- it "understands scientific notation for the real part" do
- '2e3+4i'.to_c.should == Complex(2e3,4)
+ 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
end
- it "understands negative scientific notation for the real part" do
- '-2e3+4i'.to_c.should == Complex(-2e3,4)
+ it "understands Float::INFINITY" do
+ 'Infinity'.to_c.should == Complex(0, 1)
+ '-Infinity'.to_c.should == Complex(0, -1)
end
- it "understands scientific notation for the imaginary part" do
- '4+2e3i'.to_c.should == Complex(4, 2e3)
+ it "understands Float::NAN" do
+ 'NaN'.to_c.should == Complex(0, 0)
end
- it "understands negative scientific notation for the imaginary part" do
- '4-2e3i'.to_c.should == Complex(4, -2e3)
+ it "allows null-byte" do
+ "1-2i\0".to_c.should == Complex(1, -2)
+ "1\0-2i".to_c.should == Complex(1, 0)
+ "\01-2i".to_c.should == Complex(0, 0)
end
- it "understands scientific notation for the real and imaginary part in the same String" do
- '2e3+2e4i'.to_c.should == Complex(2e3,2e4)
+ it "raises Encoding::CompatibilityError if String is in not ASCII-compatible encoding" do
+ -> {
+ '79+4i'.encode("UTF-16").to_c
+ }.should raise_error(Encoding::CompatibilityError, "ASCII incompatible encoding: UTF-16")
end
- it "understands negative scientific notation for the real and imaginary part in the same String" do
- '-2e3-2e4i'.to_c.should == Complex(-2e3,-2e4)
- end
+ 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 "returns a complex number with 0 as the real part, 0 as the imaginary part for unrecognised Strings" do
- 'ruby'.to_c.should == Complex(0,0)
+ "12_3".to_c.should == Complex(123)
+ "12__3".to_c.should == Complex(12)
+ "12___3".to_c.should == Complex(12)
+ end
end
end
diff --git a/spec/ruby/core/string/to_i_spec.rb b/spec/ruby/core/string/to_i_spec.rb
index e4fa89aab3..9931502baa 100644
--- a/spec/ruby/core/string/to_i_spec.rb
+++ b/spec/ruby/core/string/to_i_spec.rb
@@ -10,6 +10,18 @@ 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
+ (2..16).each do |base|
+ "0_0_010".to_i(base).should == base;
+ end
+ end
+
+ it "bails out at the first double underscore if the first digit is 0" do
+ (2..16).each do |base|
+ "010__1".to_i(base).should == base;
+ end
+ end
+
it "ignores leading whitespaces" do
[ " 123", " 123", "\r\n\r\n123", "\t\t123",
"\r\n\t\n123", " \t\n\r\t 123"].each do |str|
diff --git a/spec/ruby/core/string/tr_s_spec.rb b/spec/ruby/core/string/tr_s_spec.rb
index c6ad12139e..dd72da440c 100644
--- a/spec/ruby/core/string/tr_s_spec.rb
+++ b/spec/ruby/core/string/tr_s_spec.rb
@@ -1,4 +1,5 @@
# -*- encoding: utf-8 -*-
+# frozen_string_literal: false
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
@@ -17,6 +18,15 @@ describe "String#tr_s" do
"hello ^--^".tr_s("---", "_").should == "hello ^_^"
end
+ ruby_bug "#19769", ""..."3.3" do
+ it "accepts c1-c1 notation to denote range of one character" do
+ "hello".tr_s('e-e', 'x').should == "hxllo"
+ "123456789".tr_s("2-23","xy").should == "1xy456789"
+ "hello ^-^".tr_s("e-", "a-a_").should == "hallo ^_^"
+ "hello ^-^".tr_s("---o", "_a").should == "hella ^_^"
+ end
+ end
+
it "pads to_str with its last char if it is shorter than from_string" do
"this".tr_s("this", "x").should == "x"
end
@@ -45,29 +55,8 @@ describe "String#tr_s" do
"bla".tr_s(from_str, to_str).should == "BlA"
end
- ruby_version_is ''...'3.0' do
- it "returns subclass instances when called on a subclass" do
- StringSpecs::MyString.new("hello").tr_s("e", "a").should be_an_instance_of(StringSpecs::MyString)
- end
- end
-
- ruby_version_is '3.0' do
- it "returns String instances when called on a subclass" do
- StringSpecs::MyString.new("hello").tr_s("e", "a").should be_an_instance_of(String)
- end
- end
-
- ruby_version_is ''...'2.7' do
- it "taints the result when self is tainted" do
- ["h", "hello"].each do |str|
- tainted_str = str.dup.taint
-
- tainted_str.tr_s("e", "a").should.tainted?
-
- str.tr_s("e".taint, "a").should_not.tainted?
- str.tr_s("e", "a".taint).should_not.tainted?
- end
- end
+ it "returns String instances when called on a subclass" do
+ StringSpecs::MyString.new("hello").tr_s("e", "a").should be_an_instance_of(String)
end
# http://redmine.ruby-lang.org/issues/show/1839
diff --git a/spec/ruby/core/string/tr_spec.rb b/spec/ruby/core/string/tr_spec.rb
index 06be1e6641..75841a974f 100644
--- a/spec/ruby/core/string/tr_spec.rb
+++ b/spec/ruby/core/string/tr_spec.rb
@@ -1,4 +1,5 @@
# -*- encoding: utf-8 -*-
+# frozen_string_literal: false
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
@@ -16,6 +17,15 @@ describe "String#tr" do
"hello ^-^".tr("---", "_").should == "hello ^_^"
end
+ ruby_bug "#19769", ""..."3.3" do
+ it "accepts c1-c1 notation to denote range of one character" do
+ "hello".tr('e-e', 'x').should == "hxllo"
+ "123456789".tr("2-23","xy").should == "1xy456789"
+ "hello ^-^".tr("e-", "a-a_").should == "hallo ^_^"
+ "hello ^-^".tr("---o", "_a").should == "hella ^_^"
+ end
+ end
+
it "pads to_str with its last char if it is shorter than from_string" do
"this".tr("this", "x").should == "xxxx"
"hello".tr("a-z", "A-H.").should == "HE..."
@@ -57,29 +67,8 @@ describe "String#tr" do
"bla".tr(from_str, to_str).should == "BlA"
end
- ruby_version_is ''...'3.0' do
- it "returns subclass instances when called on a subclass" do
- StringSpecs::MyString.new("hello").tr("e", "a").should be_an_instance_of(StringSpecs::MyString)
- end
- end
-
- ruby_version_is '3.0' do
- it "returns Stringinstances when called on a subclass" do
- StringSpecs::MyString.new("hello").tr("e", "a").should be_an_instance_of(String)
- end
- end
-
- ruby_version_is ''...'2.7' do
- it "taints the result when self is tainted" do
- ["h", "hello"].each do |str|
- tainted_str = str.dup.taint
-
- tainted_str.tr("e", "a").should.tainted?
-
- str.tr("e".taint, "a").should_not.tainted?
- str.tr("e", "a".taint).should_not.tainted?
- end
- end
+ it "returns Stringinstances when called on a subclass" do
+ StringSpecs::MyString.new("hello").tr("e", "a").should be_an_instance_of(String)
end
# http://redmine.ruby-lang.org/issues/show/1839
diff --git a/spec/ruby/core/string/try_convert_spec.rb b/spec/ruby/core/string/try_convert_spec.rb
index 84415c4a75..72ce5dd8b2 100644
--- a/spec/ruby/core/string/try_convert_spec.rb
+++ b/spec/ruby/core/string/try_convert_spec.rb
@@ -39,7 +39,7 @@ describe "String.try_convert" do
it "sends #to_str to the argument and raises TypeError if it's not a kind of String" do
obj = mock("to_str")
obj.should_receive(:to_str).and_return(Object.new)
- -> { String.try_convert obj }.should raise_error(TypeError)
+ -> { String.try_convert obj }.should raise_error(TypeError, "can't convert MockObject to String (MockObject#to_str gives Object)")
end
it "does not rescue exceptions raised by #to_str" do
diff --git a/spec/ruby/core/string/uminus_spec.rb b/spec/ruby/core/string/uminus_spec.rb
index 800dca5044..46d88f6704 100644
--- a/spec/ruby/core/string/uminus_spec.rb
+++ b/spec/ruby/core/string/uminus_spec.rb
@@ -1,49 +1,6 @@
require_relative '../../spec_helper'
+require_relative 'shared/dedup'
describe 'String#-@' do
- it 'returns self if the String is frozen' do
- input = 'foo'.freeze
- output = -input
-
- output.should equal(input)
- output.should.frozen?
- end
-
- it 'returns a frozen copy if the String is not frozen' do
- input = 'foo'
- output = -input
-
- output.should.frozen?
- output.should_not equal(input)
- output.should == 'foo'
- end
-
- it "returns the same object for equal unfrozen strings" do
- origin = "this is a string"
- dynamic = %w(this is a string).join(' ')
-
- origin.should_not equal(dynamic)
- (-origin).should equal(-dynamic)
- end
-
- it "returns the same object when it's called on the same String literal" do
- (-"unfrozen string").should equal(-"unfrozen string")
- (-"unfrozen string").should_not equal(-"another unfrozen string")
- end
-
- it "deduplicates frozen strings" do
- dynamic = %w(this string is frozen).join(' ').freeze
-
- dynamic.should_not equal("this string is frozen".freeze)
-
- (-dynamic).should equal("this string is frozen".freeze)
- (-dynamic).should equal(-"this string is frozen".freeze)
- end
-
- ruby_version_is "3.0" do
- it "interns the provided string if it is frozen" do
- dynamic = "this string is unique and frozen #{rand}".freeze
- (-dynamic).should equal(dynamic)
- end
- end
+ it_behaves_like :string_dedup, :-@
end
diff --git a/spec/ruby/core/string/undump_spec.rb b/spec/ruby/core/string/undump_spec.rb
index b990aa25ee..6ff220161c 100644
--- a/spec/ruby/core/string/undump_spec.rb
+++ b/spec/ruby/core/string/undump_spec.rb
@@ -3,16 +3,6 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "String#undump" do
- ruby_version_is ''...'2.7' do
- it "taints the result if self is tainted" do
- '"foo"'.taint.undump.should.tainted?
- end
-
- it "untrusts the result if self is untrusted" do
- '"foo"'.untrust.undump.should.untrusted?
- end
- end
-
it "does not take into account if a string is frozen" do
'"foo"'.freeze.undump.should_not.frozen?
end
@@ -399,7 +389,7 @@ describe "String#undump" do
'"\\bv".force_encoding("UTF-16BE")'.undump.should == "\u0876".encode('utf-16be')
end
- it "keeps origin encoding" do
+ it "returns a String in the same encoding as self" do
'"foo"'.encode("ISO-8859-1").undump.encoding.should == Encoding::ISO_8859_1
'"foo"'.encode('windows-1251').undump.encoding.should == Encoding::Windows_1251
end
diff --git a/spec/ruby/core/string/unicode_normalize_spec.rb b/spec/ruby/core/string/unicode_normalize_spec.rb
index 6de7533fc7..2e7d22394a 100644
--- a/spec/ruby/core/string/unicode_normalize_spec.rb
+++ b/spec/ruby/core/string/unicode_normalize_spec.rb
@@ -1,4 +1,5 @@
# -*- encoding: utf-8 -*-
+# frozen_string_literal: false
require_relative '../../spec_helper'
# Examples taken from http://www.unicode.org/reports/tr15/#Norm_Forms
diff --git a/spec/ruby/core/string/unicode_normalized_spec.rb b/spec/ruby/core/string/unicode_normalized_spec.rb
index 87f3740459..91cf2086b2 100644
--- a/spec/ruby/core/string/unicode_normalized_spec.rb
+++ b/spec/ruby/core/string/unicode_normalized_spec.rb
@@ -1,4 +1,5 @@
# -*- encoding: utf-8 -*-
+# frozen_string_literal: false
require_relative '../../spec_helper'
describe "String#unicode_normalized?" do
diff --git a/spec/ruby/core/string/unpack/a_spec.rb b/spec/ruby/core/string/unpack/a_spec.rb
index 2d83b4c824..4002ece697 100644
--- a/spec/ruby/core/string/unpack/a_spec.rb
+++ b/spec/ruby/core/string/unpack/a_spec.rb
@@ -31,7 +31,7 @@ describe "String#unpack with format 'A'" do
end
it "decodes into raw (ascii) string values" do
- str = "str".force_encoding('UTF-8').unpack("A*")[0]
+ str = "str".dup.force_encoding('UTF-8').unpack("A*")[0]
str.encoding.should == Encoding::BINARY
end
diff --git a/spec/ruby/core/string/unpack/b_spec.rb b/spec/ruby/core/string/unpack/b_spec.rb
index 1a838d6c7c..23d93a8aea 100644
--- a/spec/ruby/core/string/unpack/b_spec.rb
+++ b/spec/ruby/core/string/unpack/b_spec.rb
@@ -86,13 +86,30 @@ describe "String#unpack with format 'B'" do
].should be_computed_by(:unpack, "BBB")
end
- it "ignores NULL bytes between directives" do
- "\x80\x00".unpack("B\x00B").should == ["1", "0"]
+ ruby_version_is ""..."3.3" do
+ it "ignores NULL bytes between directives" do
+ suppress_warning do
+ "\x80\x00".unpack("B\x00B").should == ["1", "0"]
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "\x80\x00".unpack("B\x00B")
+ }.should raise_error(ArgumentError, /unknown unpack directive/)
+ end
end
it "ignores spaces between directives" do
"\x80\x00".unpack("B B").should == ["1", "0"]
end
+
+ it "decodes into US-ASCII string values" do
+ str = "s".dup.force_encoding('UTF-8').unpack("B*")[0]
+ str.encoding.name.should == 'US-ASCII'
+ end
end
describe "String#unpack with format 'b'" do
@@ -177,8 +194,20 @@ describe "String#unpack with format 'b'" do
].should be_computed_by(:unpack, "bbb")
end
- it "ignores NULL bytes between directives" do
- "\x01\x00".unpack("b\x00b").should == ["1", "0"]
+ ruby_version_is ""..."3.3" do
+ it "ignores NULL bytes between directives" do
+ suppress_warning do
+ "\x01\x00".unpack("b\x00b").should == ["1", "0"]
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "\x01\x00".unpack("b\x00b")
+ }.should raise_error(ArgumentError, /unknown unpack directive/)
+ end
end
it "ignores spaces between directives" do
@@ -186,8 +215,7 @@ describe "String#unpack with format 'b'" do
end
it "decodes into US-ASCII string values" do
- str = "s".force_encoding('UTF-8').unpack("b*")[0]
+ str = "s".dup.force_encoding('UTF-8').unpack("b*")[0]
str.encoding.name.should == 'US-ASCII'
end
-
end
diff --git a/spec/ruby/core/string/unpack/c_spec.rb b/spec/ruby/core/string/unpack/c_spec.rb
index ed8caa4895..c2bf813954 100644
--- a/spec/ruby/core/string/unpack/c_spec.rb
+++ b/spec/ruby/core/string/unpack/c_spec.rb
@@ -35,8 +35,20 @@ describe :string_unpack_8bit, shared: true do
].should be_computed_by(:unpack, unpack_format(3))
end
- it "ignores NULL bytes between directives" do
- "abc".unpack(unpack_format("\000", 2)).should == [97, 98]
+ ruby_version_is ""..."3.3" do
+ it "ignores NULL bytes between directives" do
+ suppress_warning do
+ "abc".unpack(unpack_format("\000", 2)).should == [97, 98]
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "abc".unpack(unpack_format("\000", 2))
+ }.should raise_error(ArgumentError, /unknown unpack directive/)
+ end
end
it "ignores spaces between directives" do
diff --git a/spec/ruby/core/string/unpack/h_spec.rb b/spec/ruby/core/string/unpack/h_spec.rb
index f2f5dcf396..19c4d63664 100644
--- a/spec/ruby/core/string/unpack/h_spec.rb
+++ b/spec/ruby/core/string/unpack/h_spec.rb
@@ -56,8 +56,20 @@ describe "String#unpack with format 'H'" do
].should be_computed_by(:unpack, "HHH")
end
- it "ignores NULL bytes between directives" do
- "\x01\x10".unpack("H\x00H").should == ["0", "1"]
+ ruby_version_is ""..."3.3" do
+ it "ignores NULL bytes between directives" do
+ suppress_warning do
+ "\x01\x10".unpack("H\x00H").should == ["0", "1"]
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "\x01\x10".unpack("H\x00H")
+ }.should raise_error(ArgumentError, /unknown unpack directive/)
+ end
end
it "ignores spaces between directives" do
@@ -121,8 +133,20 @@ describe "String#unpack with format 'h'" do
].should be_computed_by(:unpack, "hhh")
end
- it "ignores NULL bytes between directives" do
- "\x01\x10".unpack("h\x00h").should == ["1", "0"]
+ ruby_version_is ""..."3.3" do
+ it "ignores NULL bytes between directives" do
+ suppress_warning do
+ "\x01\x10".unpack("h\x00h").should == ["1", "0"]
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "\x01\x10".unpack("h\x00h")
+ }.should raise_error(ArgumentError, /unknown unpack directive/)
+ end
end
it "ignores spaces between directives" do
diff --git a/spec/ruby/core/string/unpack/m_spec.rb b/spec/ruby/core/string/unpack/m_spec.rb
index 21134514a1..c551c755d1 100644
--- a/spec/ruby/core/string/unpack/m_spec.rb
+++ b/spec/ruby/core/string/unpack/m_spec.rb
@@ -97,6 +97,11 @@ describe "String#unpack with format 'M'" do
["=FF=\n", ["\xff"]]
].should be_computed_by(:unpack, "M")
end
+
+ it "unpacks incomplete escape sequences as literal characters" do
+ "foo=".unpack("M").should == ["foo="]
+ "foo=4".unpack("M").should == ["foo=4"]
+ end
end
describe "String#unpack with format 'm'" do
diff --git a/spec/ruby/core/string/unpack/p_spec.rb b/spec/ruby/core/string/unpack/p_spec.rb
index 3e187d674f..cd48c0523d 100644
--- a/spec/ruby/core/string/unpack/p_spec.rb
+++ b/spec/ruby/core/string/unpack/p_spec.rb
@@ -18,12 +18,6 @@ describe "String#unpack with format 'P'" do
-> { packed.to_sym.to_s.unpack("P5") }.should raise_error(ArgumentError, /no associated pointer/)
end
- ruby_version_is ''...'2.7' do
- it "taints the unpacked string" do
- ["hello"].pack("P").unpack("P5").first.tainted?.should be_true
- end
- end
-
it "reads as many characters as specified" do
["hello"].pack("P").unpack("P1").should == ["h"]
end
@@ -47,10 +41,4 @@ describe "String#unpack with format 'p'" do
packed.dup.unpack("p").should == ["hello"]
-> { packed.to_sym.to_s.unpack("p") }.should raise_error(ArgumentError, /no associated pointer/)
end
-
- ruby_version_is ''...'2.7' do
- it "taints the unpacked string" do
- ["hello"].pack("p").unpack("p").first.tainted?.should be_true
- end
- end
end
diff --git a/spec/ruby/core/string/unpack/shared/basic.rb b/spec/ruby/core/string/unpack/shared/basic.rb
index f636f4689f..bb5302edc5 100644
--- a/spec/ruby/core/string/unpack/shared/basic.rb
+++ b/spec/ruby/core/string/unpack/shared/basic.rb
@@ -8,20 +8,6 @@ describe :string_unpack_basic, shared: true do
d.should_receive(:to_str).and_return("a"+unpack_format)
"abc".unpack(d).should be_an_instance_of(Array)
end
-
- it "raises a TypeError when passed nil" do
- -> { "abc".unpack(nil) }.should raise_error(TypeError)
- end
-
- it "raises a TypeError when passed an Integer" do
- -> { "abc".unpack(1) }.should raise_error(TypeError)
- end
-
- ruby_version_is "3.1" do
- it "starts unpacking from the given offset" do
- "abc".unpack("CC", offset: 1).should == [98, 99]
- end
- end
end
describe :string_unpack_no_platform, shared: true do
@@ -32,18 +18,4 @@ describe :string_unpack_no_platform, shared: true do
it "raises an ArgumentError when the format modifier is '!'" do
-> { "abcdefgh".unpack(unpack_format("!")) }.should raise_error(ArgumentError)
end
-
- ruby_version_is "3.1" do
- it "raises an ArgumentError when the offset is negative" do
- -> { "a".unpack("C", offset: -1) }.should raise_error(ArgumentError)
- end
-
- it "returns nil if the offset is at the end of the string" do
- "a".unpack("C", offset: 1).should == [nil]
- end
-
- it "raises an ArgumentError when the offset is larget than the string" do
- -> { "a".unpack("C", offset: 2) }.should raise_error(ArgumentError)
- end
- end
end
diff --git a/spec/ruby/core/string/unpack/shared/float.rb b/spec/ruby/core/string/unpack/shared/float.rb
index 99bd8a3401..93282bf4c9 100644
--- a/spec/ruby/core/string/unpack/shared/float.rb
+++ b/spec/ruby/core/string/unpack/shared/float.rb
@@ -56,9 +56,21 @@ describe :string_unpack_float_le, shared: true do
[nan_value].pack(unpack_format).unpack(unpack_format).first.nan?.should be_true
end
- it "ignores NULL bytes between directives" do
- array = "\x9a\x999@33\xb3?".unpack(unpack_format("\000", 2))
- array.should == [2.9000000953674316, 1.399999976158142]
+ ruby_version_is ""..."3.3" do
+ it "ignores NULL bytes between directives" do
+ suppress_warning do
+ array = "\x9a\x999@33\xb3?".unpack(unpack_format("\000", 2))
+ array.should == [2.9000000953674316, 1.399999976158142]
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "\x9a\x999@33\xb3?".unpack(unpack_format("\000", 2))
+ }.should raise_error(ArgumentError, /unknown unpack directive/)
+ end
end
it "ignores spaces between directives" do
@@ -123,9 +135,21 @@ describe :string_unpack_float_be, shared: true do
[nan_value].pack(unpack_format).unpack(unpack_format).first.nan?.should be_true
end
- it "ignores NULL bytes between directives" do
- array = "@9\x99\x9a?\xb333".unpack(unpack_format("\000", 2))
- array.should == [2.9000000953674316, 1.399999976158142]
+ ruby_version_is ""..."3.3" do
+ it "ignores NULL bytes between directives" do
+ suppress_warning do
+ array = "@9\x99\x9a?\xb333".unpack(unpack_format("\000", 2))
+ array.should == [2.9000000953674316, 1.399999976158142]
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "@9\x99\x9a?\xb333".unpack(unpack_format("\000", 2))
+ }.should raise_error(ArgumentError, /unknown unpack directive/)
+ end
end
it "ignores spaces between directives" do
@@ -193,8 +217,20 @@ describe :string_unpack_double_le, shared: true do
[nan_value].pack(unpack_format).unpack(unpack_format).first.nan?.should be_true
end
- it "ignores NULL bytes between directives" do
- "333333\x07@ffffff\xf6?".unpack(unpack_format("\000", 2)).should == [2.9, 1.4]
+ ruby_version_is ""..."3.3" do
+ it "ignores NULL bytes between directives" do
+ suppress_warning do
+ "333333\x07@ffffff\xf6?".unpack(unpack_format("\000", 2)).should == [2.9, 1.4]
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "333333\x07@ffffff\xf6?".unpack(unpack_format("\000", 2))
+ }.should raise_error(ArgumentError, /unknown unpack directive/)
+ end
end
it "ignores spaces between directives" do
@@ -261,8 +297,20 @@ describe :string_unpack_double_be, shared: true do
[nan_value].pack(unpack_format).unpack(unpack_format).first.nan?.should be_true
end
- it "ignores NULL bytes between directives" do
- "@\x07333333?\xf6ffffff".unpack(unpack_format("\000", 2)).should == [2.9, 1.4]
+ ruby_version_is ""..."3.3" do
+ it "ignores NULL bytes between directives" do
+ suppress_warning do
+ "@\x07333333?\xf6ffffff".unpack(unpack_format("\000", 2)).should == [2.9, 1.4]
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "@\x07333333?\xf6ffffff".unpack(unpack_format("\000", 2))
+ }.should raise_error(ArgumentError, /unknown unpack directive/)
+ end
end
it "ignores spaces between directives" do
diff --git a/spec/ruby/core/string/unpack/shared/integer.rb b/spec/ruby/core/string/unpack/shared/integer.rb
index cbaa743683..d71a2cf00d 100644
--- a/spec/ruby/core/string/unpack/shared/integer.rb
+++ b/spec/ruby/core/string/unpack/shared/integer.rb
@@ -32,8 +32,20 @@ describe :string_unpack_16bit_le, shared: true do
].should be_computed_by(:unpack, unpack_format(3))
end
- it "ignores NULL bytes between directives" do
- "abcd".unpack(unpack_format("\000", 2)).should == [25185, 25699]
+ ruby_version_is ""..."3.3" do
+ it "ignores NULL bytes between directives" do
+ suppress_warning do
+ "abcd".unpack(unpack_format("\000", 2)).should == [25185, 25699]
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "abcd".unpack(unpack_format("\000", 2))
+ }.should raise_error(ArgumentError, /unknown unpack directive/)
+ end
end
it "ignores spaces between directives" do
@@ -85,8 +97,20 @@ describe :string_unpack_16bit_be, shared: true do
].should be_computed_by(:unpack, unpack_format(3))
end
- it "ignores NULL bytes between directives" do
- "badc".unpack(unpack_format("\000", 2)).should == [25185, 25699]
+ ruby_version_is ""..."3.3" do
+ it "ignores NULL bytes between directives" do
+ suppress_warning do
+ "badc".unpack(unpack_format("\000", 2)).should == [25185, 25699]
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "badc".unpack(unpack_format("\000", 2))
+ }.should raise_error(ArgumentError, /unknown unpack directive/)
+ end
end
it "ignores spaces between directives" do
@@ -139,8 +163,20 @@ describe :string_unpack_32bit_le, shared: true do
].should be_computed_by(:unpack, unpack_format(3))
end
- it "ignores NULL bytes between directives" do
- "abcdefgh".unpack(unpack_format("\000", 2)).should == [1684234849, 1751606885]
+ ruby_version_is ""..."3.3" do
+ it "ignores NULL bytes between directives" do
+ suppress_warning do
+ "abcdefgh".unpack(unpack_format("\000", 2)).should == [1684234849, 1751606885]
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "abcdefgh".unpack(unpack_format("\000", 2))
+ }.should raise_error(ArgumentError, /unknown unpack directive/)
+ end
end
it "ignores spaces between directives" do
@@ -193,8 +229,20 @@ describe :string_unpack_32bit_be, shared: true do
].should be_computed_by(:unpack, unpack_format(3))
end
- it "ignores NULL bytes between directives" do
- "dcbahgfe".unpack(unpack_format("\000", 2)).should == [1684234849, 1751606885]
+ ruby_version_is ""..."3.3" do
+ it "ignores NULL bytes between directives" do
+ suppress_warning do
+ "dcbahgfe".unpack(unpack_format("\000", 2)).should == [1684234849, 1751606885]
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "dcbahgfe".unpack(unpack_format("\000", 2))
+ }.should raise_error(ArgumentError, /unknown unpack directive/)
+ end
end
it "ignores spaces between directives" do
@@ -243,9 +291,21 @@ describe :string_unpack_64bit_le, shared: true do
"abc".unpack(unpack_format('*')).should == []
end
- it "ignores NULL bytes between directives" do
- array = "abcdefghabghefcd".unpack(unpack_format("\000", 2))
- array.should == [7523094288207667809, 7233738012216484449]
+ ruby_version_is ""..."3.3" do
+ it "ignores NULL bytes between directives" do
+ suppress_warning do
+ array = "abcdefghabghefcd".unpack(unpack_format("\000", 2))
+ array.should == [7523094288207667809, 7233738012216484449]
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "badc".unpack(unpack_format("\000", 2))
+ }.should raise_error(ArgumentError, /unknown unpack directive/)
+ end
end
it "ignores spaces between directives" do
@@ -305,9 +365,21 @@ describe :string_unpack_64bit_be, shared: true do
"abc".unpack(unpack_format('*')).should == []
end
- it "ignores NULL bytes between directives" do
- array = "hgfedcbadcfehgba".unpack(unpack_format("\000", 2))
- array.should == [7523094288207667809, 7233738012216484449]
+ ruby_version_is ""..."3.3" do
+ it "ignores NULL bytes between directives" do
+ suppress_warning do
+ array = "hgfedcbadcfehgba".unpack(unpack_format("\000", 2))
+ array.should == [7523094288207667809, 7233738012216484449]
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "hgfedcbadcfehgba".unpack(unpack_format("\000", 2))
+ }.should raise_error(ArgumentError, /unknown unpack directive/)
+ end
end
it "ignores spaces between directives" do
diff --git a/spec/ruby/core/string/unpack/shared/taint.rb b/spec/ruby/core/string/unpack/shared/taint.rb
index 061a3e26ad..79c7251f01 100644
--- a/spec/ruby/core/string/unpack/shared/taint.rb
+++ b/spec/ruby/core/string/unpack/shared/taint.rb
@@ -1,83 +1,2 @@
describe :string_unpack_taint, shared: true do
- ruby_version_is ''...'2.7' do
- it "does not taint returned arrays if given an untainted format string" do
- "".unpack(unpack_format(2)).tainted?.should be_false
- end
-
- it "does not taint returned arrays if given a tainted format string" do
- format_string = unpack_format(2).dup
- format_string.taint
- "".unpack(format_string).tainted?.should be_false
- end
-
- it "does not taint returned strings if given an untainted format string" do
- "".unpack(unpack_format(2)).any?(&:tainted?).should be_false
- end
-
- it "does not taint returned strings if given a tainted format string" do
- format_string = unpack_format(2).dup
- format_string.taint
- "".unpack(format_string).any?(&:tainted?).should be_false
- end
-
- it "does not taint returned arrays if given an untainted packed string" do
- "".unpack(unpack_format(2)).tainted?.should be_false
- end
-
- it "does not taint returned arrays if given a tainted packed string" do
- packed_string = ""
- packed_string.taint
- packed_string.unpack(unpack_format(2)).tainted?.should be_false
- end
-
- it "does not taint returned strings if given an untainted packed string" do
- "".unpack(unpack_format(2)).any?(&:tainted?).should be_false
- end
-
- it "taints returned strings if given a tainted packed string" do
- packed_string = ""
- packed_string.taint
- packed_string.unpack(unpack_format(2)).all?(&:tainted?).should be_true
- end
-
- it "does not untrust returned arrays if given an untrusted format string" do
- "".unpack(unpack_format(2)).untrusted?.should be_false
- end
-
- it "does not untrust returned arrays if given a untrusted format string" do
- format_string = unpack_format(2).dup
- format_string.untrust
- "".unpack(format_string).untrusted?.should be_false
- end
-
- it "does not untrust returned strings if given an untainted format string" do
- "".unpack(unpack_format(2)).any?(&:untrusted?).should be_false
- end
-
- it "does not untrust returned strings if given a untrusted format string" do
- format_string = unpack_format(2).dup
- format_string.untrust
- "".unpack(format_string).any?(&:untrusted?).should be_false
- end
-
- it "does not untrust returned arrays if given an trusted packed string" do
- "".unpack(unpack_format(2)).untrusted?.should be_false
- end
-
- it "does not untrust returned arrays if given a untrusted packed string" do
- packed_string = ""
- packed_string.untrust
- packed_string.unpack(unpack_format(2)).untrusted?.should be_false
- end
-
- it "does not untrust returned strings if given an trusted packed string" do
- "".unpack(unpack_format(2)).any?(&:untrusted?).should be_false
- end
-
- it "untrusts returned strings if given a untrusted packed string" do
- packed_string = ""
- packed_string.untrust
- packed_string.unpack(unpack_format(2)).all?(&:untrusted?).should be_true
- end
- end
end
diff --git a/spec/ruby/core/string/unpack/shared/unicode.rb b/spec/ruby/core/string/unpack/shared/unicode.rb
index a2b4e142b2..9fe07f53ae 100644
--- a/spec/ruby/core/string/unpack/shared/unicode.rb
+++ b/spec/ruby/core/string/unpack/shared/unicode.rb
@@ -50,8 +50,20 @@ describe :string_unpack_unicode, shared: true do
"\xc2\x80".unpack("UUUU").should == [0x80]
end
- it "ignores NULL bytes between directives" do
- "\x01\x02".unpack("U\x00U").should == [1, 2]
+ ruby_version_is ""..."3.3" do
+ it "ignores NULL bytes between directives" do
+ suppress_warning do
+ "\x01\x02".unpack("U\x00U").should == [1, 2]
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "\x01\x02".unpack("U\x00U")
+ }.should raise_error(ArgumentError, /unknown unpack directive/)
+ end
end
it "ignores spaces between directives" do
diff --git a/spec/ruby/core/string/unpack/u_spec.rb b/spec/ruby/core/string/unpack/u_spec.rb
index 7845e6d5f2..456abee784 100644
--- a/spec/ruby/core/string/unpack/u_spec.rb
+++ b/spec/ruby/core/string/unpack/u_spec.rb
@@ -33,7 +33,7 @@ describe "String#unpack with format 'u'" do
str = "".unpack("u")[0]
str.encoding.should == Encoding::BINARY
- str = "1".force_encoding('UTF-8').unpack("u")[0]
+ str = "1".dup.force_encoding('UTF-8').unpack("u")[0]
str.encoding.should == Encoding::BINARY
end
diff --git a/spec/ruby/core/string/unpack/w_spec.rb b/spec/ruby/core/string/unpack/w_spec.rb
index 011c75f5c4..6a1cff1965 100644
--- a/spec/ruby/core/string/unpack/w_spec.rb
+++ b/spec/ruby/core/string/unpack/w_spec.rb
@@ -15,8 +15,20 @@ describe "String#unpack with directive 'w'" do
].should be_computed_by(:unpack, "w")
end
- it "ignores NULL bytes between directives" do
- "\x01\x02\x03".unpack("w\x00w").should == [1, 2]
+ ruby_version_is ""..."3.3" do
+ it "ignores NULL bytes between directives" do
+ suppress_warning do
+ "\x01\x02\x03".unpack("w\x00w").should == [1, 2]
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise ArgumentError for NULL bytes between directives" do
+ -> {
+ "\x01\x02\x03".unpack("w\x00w")
+ }.should raise_error(ArgumentError, /unknown unpack directive/)
+ end
end
it "ignores spaces between directives" do
diff --git a/spec/ruby/core/string/unpack/z_spec.rb b/spec/ruby/core/string/unpack/z_spec.rb
index 552851ce04..ce8da4b29e 100644
--- a/spec/ruby/core/string/unpack/z_spec.rb
+++ b/spec/ruby/core/string/unpack/z_spec.rb
@@ -20,4 +20,9 @@ describe "String#unpack with format 'Z'" do
["\x00a\x00 bc \x00", ["", "c"]]
].should be_computed_by(:unpack, "Z5Z")
end
+
+ it "does not advance past the null byte when given a 'Z' format specifier" do
+ "a\x00\x0f".unpack('Zxc').should == ['a', 15]
+ "a\x00\x0f".unpack('Zcc').should == ['a', 0, 15]
+ end
end
diff --git a/spec/ruby/core/string/unpack1_spec.rb b/spec/ruby/core/string/unpack1_spec.rb
index f59bd92d6a..df830916a3 100644
--- a/spec/ruby/core/string/unpack1_spec.rb
+++ b/spec/ruby/core/string/unpack1_spec.rb
@@ -15,16 +15,22 @@ describe "String#unpack1" do
"ZA".unpack1("B*", offset: 1).should == "01000001"
end
+ it "traits offset as a bytes offset" do
+ "؈".unpack("CC").should == [216, 136]
+ "؈".unpack1("C").should == 216
+ "؈".unpack1("C", offset: 1).should == 136
+ end
+
it "raises an ArgumentError when the offset is negative" do
- -> { "a".unpack1("C", offset: -1) }.should raise_error(ArgumentError)
+ -> { "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 larget than the string" do
- -> { "a".unpack1("C", offset: 2) }.should raise_error(ArgumentError)
+ 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
end
end
diff --git a/spec/ruby/core/string/unpack_spec.rb b/spec/ruby/core/string/unpack_spec.rb
new file mode 100644
index 0000000000..52b4af3a95
--- /dev/null
+++ b/spec/ruby/core/string/unpack_spec.rb
@@ -0,0 +1,34 @@
+require_relative '../../spec_helper'
+
+describe "String#unpack" do
+ it "raises a TypeError when passed nil" do
+ -> { "abc".unpack(nil) }.should raise_error(TypeError)
+ end
+
+ it "raises a TypeError when passed an Integer" do
+ -> { "abc".unpack(1) }.should raise_error(TypeError)
+ end
+
+ ruby_version_is "3.1" do
+ it "starts unpacking from the given offset" do
+ "abc".unpack("CC", offset: 1).should == [98, 99]
+ end
+
+ it "traits offset as a bytes offset" do
+ "؈".unpack("CC").should == [216, 136]
+ "؈".unpack("CC", offset: 1).should == [136, nil]
+ end
+
+ it "raises an ArgumentError when the offset is negative" do
+ -> { "a".unpack("C", offset: -1) }.should raise_error(ArgumentError, "offset can't be negative")
+ end
+
+ it "returns nil if the offset is at the end of the string" do
+ "a".unpack("C", offset: 1).should == [nil]
+ end
+
+ it "raises an ArgumentError when the offset is larget than the string" do
+ -> { "a".unpack("C", offset: 2) }.should raise_error(ArgumentError, "offset outside of string")
+ end
+ end
+end
diff --git a/spec/ruby/core/string/upcase_spec.rb b/spec/ruby/core/string/upcase_spec.rb
index 6cf44b4703..652de5c2ef 100644
--- a/spec/ruby/core/string/upcase_spec.rb
+++ b/spec/ruby/core/string/upcase_spec.rb
@@ -1,4 +1,5 @@
# -*- encoding: utf-8 -*-
+# frozen_string_literal: false
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
@@ -8,6 +9,10 @@ describe "String#upcase" do
"hello".upcase.should == "HELLO"
end
+ it "returns a String in the same encoding as self" do
+ "hello".encode("US-ASCII").upcase.encoding.should == Encoding::US_ASCII
+ end
+
describe "full Unicode case mapping" do
it "works for all of Unicode with no option" do
"äöü".upcase.should == "ÄÖÜ"
@@ -27,6 +32,10 @@ describe "String#upcase" do
it "does not upcase non-ASCII characters" do
"aßet".upcase(:ascii).should == "AßET"
end
+
+ it "works with substrings" do
+ "prefix té"[-2..-1].upcase(:ascii).should == "Té"
+ end
end
describe "full Unicode case mapping adapted for Turkic languages" do
@@ -65,24 +74,8 @@ describe "String#upcase" do
-> { "abc".upcase(:invalid_option) }.should raise_error(ArgumentError)
end
- ruby_version_is ''...'2.7' do
- it "taints result when self is tainted" do
- "".taint.upcase.should.tainted?
- "X".taint.upcase.should.tainted?
- "x".taint.upcase.should.tainted?
- end
- end
-
- ruby_version_is ''...'3.0' do
- it "returns a subclass instance for subclasses" do
- StringSpecs::MyString.new("fooBAR").upcase.should be_an_instance_of(StringSpecs::MyString)
- end
- end
-
- ruby_version_is '3.0' do
- it "returns a String instance for subclasses" do
- StringSpecs::MyString.new("fooBAR").upcase.should be_an_instance_of(String)
- end
+ it "returns a String instance for subclasses" do
+ StringSpecs::MyString.new("fooBAR").upcase.should be_an_instance_of(String)
end
end
diff --git a/spec/ruby/core/string/uplus_spec.rb b/spec/ruby/core/string/uplus_spec.rb
index 038b283c90..c0b0c49ede 100644
--- a/spec/ruby/core/string/uplus_spec.rb
+++ b/spec/ruby/core/string/uplus_spec.rb
@@ -1,3 +1,4 @@
+# frozen_string_literal: false
require_relative '../../spec_helper'
describe 'String#+@' do
@@ -7,6 +8,9 @@ describe 'String#+@' do
output.should_not.frozen?
output.should == 'foo'
+
+ output << 'bar'
+ output.should == 'foobar'
end
it 'returns self if the String is not frozen' do
diff --git a/spec/ruby/core/string/upto_spec.rb b/spec/ruby/core/string/upto_spec.rb
index f8529b1d2b..8bc847d5ac 100644
--- a/spec/ruby/core/string/upto_spec.rb
+++ b/spec/ruby/core/string/upto_spec.rb
@@ -80,6 +80,12 @@ describe "String#upto" do
a.should == ["Σ", "Τ", "Υ", "Φ", "Χ", "Ψ", "Ω"]
end
+ it "raises Encoding::CompatibilityError when incompatible characters are given" do
+ char1 = 'a'.dup.force_encoding("EUC-JP")
+ char2 = 'b'.dup.force_encoding("ISO-2022-JP")
+ -> { char1.upto(char2) {} }.should raise_error(Encoding::CompatibilityError, "incompatible character encodings: EUC-JP and ISO-2022-JP")
+ end
+
describe "on sequence of numbers" do
it "calls the block as Integer#upto" do
"8".upto("11").to_a.should == 8.upto(11).map(&:to_s)
diff --git a/spec/ruby/core/string/valid_encoding/utf_8_spec.rb b/spec/ruby/core/string/valid_encoding/utf_8_spec.rb
new file mode 100644
index 0000000000..a14c3af830
--- /dev/null
+++ b/spec/ruby/core/string/valid_encoding/utf_8_spec.rb
@@ -0,0 +1,214 @@
+# -*- encoding: utf-8 -*-
+require_relative '../../../spec_helper'
+
+describe "String#valid_encoding? and UTF-8" do
+ def utf8(bytes)
+ bytes.pack("C*").force_encoding("UTF-8")
+ end
+
+ describe "1-byte character" do
+ it "is valid if is in format 0xxxxxxx" do
+ utf8([0b00000000]).valid_encoding?.should == true
+ utf8([0b01111111]).valid_encoding?.should == true
+ end
+
+ it "is not valid if is not in format 0xxxxxxx" do
+ utf8([0b10000000]).valid_encoding?.should == false
+ utf8([0b11111111]).valid_encoding?.should == false
+ end
+ end
+
+ describe "2-bytes character" do
+ it "is valid if in format [110xxxxx 10xxxxx]" do
+ utf8([0b11000010, 0b10000000]).valid_encoding?.should == true
+ utf8([0b11000010, 0b10111111]).valid_encoding?.should == true
+
+ utf8([0b11011111, 0b10000000]).valid_encoding?.should == true
+ utf8([0b11011111, 0b10111111]).valid_encoding?.should == true
+ end
+
+ it "is not valid if the first byte is not in format 110xxxxx" do
+ utf8([0b00000010, 0b10000000]).valid_encoding?.should == false
+ utf8([0b00100010, 0b10000000]).valid_encoding?.should == false
+ utf8([0b01000010, 0b10000000]).valid_encoding?.should == false
+ utf8([0b01100010, 0b10000000]).valid_encoding?.should == false
+ utf8([0b10000010, 0b10000000]).valid_encoding?.should == false
+ utf8([0b10100010, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11000010, 0b10000000]).valid_encoding?.should == true # correct bytes
+ utf8([0b11100010, 0b10000000]).valid_encoding?.should == false
+ end
+
+ it "is not valid if the second byte is not in format 10xxxxxx" do
+ utf8([0b11000010, 0b00000000]).valid_encoding?.should == false
+ utf8([0b11000010, 0b01000000]).valid_encoding?.should == false
+ utf8([0b11000010, 0b11000000]).valid_encoding?.should == false
+ end
+
+ it "is not valid if is smaller than [xxxxxx10 xx000000] (codepoints < U+007F, that are encoded with the 1-byte format)" do
+ utf8([0b11000000, 0b10111111]).valid_encoding?.should == false
+ utf8([0b11000001, 0b10111111]).valid_encoding?.should == false
+ end
+
+ it "is not valid if the first byte is missing" do
+ bytes = [0b11000010, 0b10000000]
+ utf8(bytes[1..1]).valid_encoding?.should == false
+ end
+
+ it "is not valid if the second byte is missing" do
+ bytes = [0b11000010, 0b10000000]
+ utf8(bytes[0..0]).valid_encoding?.should == false
+ end
+ end
+
+ describe "3-bytes character" do
+ it "is valid if in format [1110xxxx 10xxxxxx 10xxxxxx]" do
+ utf8([0b11100000, 0b10100000, 0b10000000]).valid_encoding?.should == true
+ utf8([0b11100000, 0b10100000, 0b10111111]).valid_encoding?.should == true
+ utf8([0b11100000, 0b10111111, 0b10111111]).valid_encoding?.should == true
+ utf8([0b11101111, 0b10111111, 0b10111111]).valid_encoding?.should == true
+ end
+
+ it "is not valid if the first byte is not in format 1110xxxx" do
+ utf8([0b00000000, 0b10100000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b00010000, 0b10100000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b00100000, 0b10100000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b00110000, 0b10100000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b01000000, 0b10100000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b01010000, 0b10100000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b01100000, 0b10100000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b01110000, 0b10100000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b10000000, 0b10100000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b10010000, 0b10100000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b10100000, 0b10100000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b10110000, 0b10100000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11000000, 0b10100000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11010000, 0b10100000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11100000, 0b10100000, 0b10000000]).valid_encoding?.should == true # correct bytes
+ utf8([0b11110000, 0b10100000, 0b10000000]).valid_encoding?.should == false
+ end
+
+ it "is not valid if the second byte is not in format 10xxxxxx" do
+ utf8([0b11100000, 0b00100000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11100000, 0b01100000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11100000, 0b11100000, 0b10000000]).valid_encoding?.should == false
+ end
+
+ it "is not valid if the third byte is not in format 10xxxxxx" do
+ utf8([0b11100000, 0b10100000, 0b00000000]).valid_encoding?.should == false
+ utf8([0b11100000, 0b10100000, 0b01000000]).valid_encoding?.should == false
+ utf8([0b11100000, 0b10100000, 0b01000000]).valid_encoding?.should == false
+ end
+
+ it "is not valid if is smaller than [xxxx0000 xx100000 xx000000] (codepoints < U+07FF that are encoded with the 2-byte format)" do
+ utf8([0b11100000, 0b10010000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11100000, 0b10001000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11100000, 0b10000100, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11100000, 0b10000010, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11100000, 0b10000001, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11100000, 0b10000000, 0b10000000]).valid_encoding?.should == false
+ end
+
+ it "is not valid if in range [xxxx1101 xx100000 xx000000] - [xxxx1101 xx111111 xx111111] (codepoints U+D800 - U+DFFF)" do
+ utf8([0b11101101, 0b10100000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11101101, 0b10100000, 0b10000001]).valid_encoding?.should == false
+ utf8([0b11101101, 0b10111111, 0b10111111]).valid_encoding?.should == false
+
+ utf8([0b11101101, 0b10011111, 0b10111111]).valid_encoding?.should == true # lower boundary - 1
+ utf8([0b11101110, 0b10000000, 0b10000000]).valid_encoding?.should == true # upper boundary + 1
+ end
+
+ it "is not valid if the first byte is missing" do
+ bytes = [0b11100000, 0b10100000, 0b10000000]
+ utf8(bytes[2..3]).valid_encoding?.should == false
+ end
+
+ it "is not valid if the second byte is missing" do
+ bytes = [0b11100000, 0b10100000, 0b10000000]
+ utf8([bytes[0], bytes[2]]).valid_encoding?.should == false
+ end
+
+ it "is not valid if the second and the third bytes are missing" do
+ bytes = [0b11100000, 0b10100000, 0b10000000]
+ utf8(bytes[0..0]).valid_encoding?.should == false
+ end
+ end
+
+ describe "4-bytes character" do
+ it "is valid if in format [11110xxx 10xxxxxx 10xxxxxx 10xxxxxx]" do
+ utf8([0b11110000, 0b10010000, 0b10000000, 0b10000000]).valid_encoding?.should == true
+ utf8([0b11110000, 0b10010000, 0b10000000, 0b10111111]).valid_encoding?.should == true
+ utf8([0b11110000, 0b10010000, 0b10111111, 0b10111111]).valid_encoding?.should == true
+ utf8([0b11110000, 0b10111111, 0b10111111, 0b10111111]).valid_encoding?.should == true
+ utf8([0b11110100, 0b10001111, 0b10111111, 0b10111111]).valid_encoding?.should == true
+ end
+
+ it "is not valid if the first byte is not in format 11110xxx" do
+ utf8([0b11100000, 0b10010000, 0b10000000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11010000, 0b10010000, 0b10000000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b10110000, 0b10010000, 0b10000000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b01110000, 0b10010000, 0b10000000, 0b10000000]).valid_encoding?.should == false
+ end
+
+ it "is not valid if the second byte is not in format 10xxxxxx" do
+ utf8([0b11110000, 0b00010000, 0b10000000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11110000, 0b01010000, 0b10000000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11110000, 0b10010000, 0b10000000, 0b10000000]).valid_encoding?.should == true # correct bytes
+ utf8([0b11110000, 0b11010000, 0b10000000, 0b10000000]).valid_encoding?.should == false
+ end
+
+ it "is not valid if the third byte is not in format 10xxxxxx" do
+ utf8([0b11110000, 0b10010000, 0b00000000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11110000, 0b10010000, 0b01000000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11110000, 0b10010000, 0b10000000, 0b10000000]).valid_encoding?.should == true # correct bytes
+ utf8([0b11110000, 0b10010000, 0b11000000, 0b10000000]).valid_encoding?.should == false
+ end
+
+ it "is not valid if the forth byte is not in format 10xxxxxx" do
+ utf8([0b11110000, 0b10010000, 0b10000000, 0b00000000]).valid_encoding?.should == false
+ utf8([0b11110000, 0b10010000, 0b10000000, 0b01000000]).valid_encoding?.should == false
+ utf8([0b11110000, 0b10010000, 0b10000000, 0b10000000]).valid_encoding?.should == true # correct bytes
+ utf8([0b11110000, 0b10010000, 0b10000000, 0b11000000]).valid_encoding?.should == false
+ end
+
+ it "is not valid if is smaller than [xxxxx000 xx001000 xx000000 xx000000] (codepoint < U+10000)" do
+ utf8([0b11110000, 0b10000111, 0b10000000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11110000, 0b10000110, 0b10000000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11110000, 0b10000101, 0b10000000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11110000, 0b10000100, 0b10000000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11110000, 0b10000011, 0b10000000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11110000, 0b10000010, 0b10000000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11110000, 0b10000001, 0b10000000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11110000, 0b10000000, 0b10000000, 0b10000000]).valid_encoding?.should == false
+ end
+
+ it "is not valid if is greater than [xxxxx100 xx001111 xx111111 xx111111] (codepoint > U+10FFFF)" do
+ utf8([0b11110100, 0b10010000, 0b10000000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11110100, 0b10100000, 0b10000000, 0b10000000]).valid_encoding?.should == false
+ utf8([0b11110100, 0b10110000, 0b10000000, 0b10000000]).valid_encoding?.should == false
+
+ utf8([0b11110101, 0b10001111, 0b10111111, 0b10111111]).valid_encoding?.should == false
+ utf8([0b11110110, 0b10001111, 0b10111111, 0b10111111]).valid_encoding?.should == false
+ utf8([0b11110111, 0b10001111, 0b10111111, 0b10111111]).valid_encoding?.should == false
+ end
+
+ it "is not valid if the first byte is missing" do
+ bytes = [0b11110000, 0b10010000, 0b10000000, 0b10000000]
+ utf8(bytes[1..3]).valid_encoding?.should == false
+ end
+
+ it "is not valid if the second byte is missing" do
+ bytes = [0b11110000, 0b10010000, 0b10000000, 0b10000000]
+ utf8([bytes[0], bytes[2], bytes[3]]).valid_encoding?.should == false
+ end
+
+ it "is not valid if the second and the third bytes are missing" do
+ bytes = [0b11110000, 0b10010000, 0b10000000, 0b10000000]
+ utf8([bytes[0], bytes[3]]).valid_encoding?.should == false
+ end
+
+ it "is not valid if the second, the third and the fourth bytes are missing" do
+ bytes = [0b11110000, 0b10010000, 0b10000000, 0b10000000]
+ utf8(bytes[0..0]).valid_encoding?.should == false
+ end
+ end
+end
diff --git a/spec/ruby/core/string/valid_encoding_spec.rb b/spec/ruby/core/string/valid_encoding_spec.rb
index be7cef7a8e..375035cd94 100644
--- a/spec/ruby/core/string/valid_encoding_spec.rb
+++ b/spec/ruby/core/string/valid_encoding_spec.rb
@@ -7,13 +7,13 @@ describe "String#valid_encoding?" do
end
it "returns true if self is valid in the current encoding and other encodings" do
- str = "\x77"
+ str = +"\x77"
str.force_encoding('utf-8').valid_encoding?.should be_true
str.force_encoding('binary').valid_encoding?.should be_true
end
it "returns true for all encodings self is valid in" do
- str = "\xE6\x9D\x94"
+ str = +"\xE6\x9D\x94"
str.force_encoding('BINARY').valid_encoding?.should be_true
str.force_encoding('UTF-8').valid_encoding?.should be_true
str.force_encoding('US-ASCII').valid_encoding?.should be_false
@@ -43,10 +43,10 @@ describe "String#valid_encoding?" do
str.force_encoding('KOI8-R').valid_encoding?.should be_true
str.force_encoding('KOI8-U').valid_encoding?.should be_true
str.force_encoding('Shift_JIS').valid_encoding?.should be_false
- "\xD8\x00".force_encoding('UTF-16BE').valid_encoding?.should be_false
- "\x00\xD8".force_encoding('UTF-16LE').valid_encoding?.should be_false
- "\x04\x03\x02\x01".force_encoding('UTF-32BE').valid_encoding?.should be_false
- "\x01\x02\x03\x04".force_encoding('UTF-32LE').valid_encoding?.should be_false
+ "\xD8\x00".dup.force_encoding('UTF-16BE').valid_encoding?.should be_false
+ "\x00\xD8".dup.force_encoding('UTF-16LE').valid_encoding?.should be_false
+ "\x04\x03\x02\x01".dup.force_encoding('UTF-32BE').valid_encoding?.should be_false
+ "\x01\x02\x03\x04".dup.force_encoding('UTF-32LE').valid_encoding?.should be_false
str.force_encoding('Windows-1251').valid_encoding?.should be_true
str.force_encoding('IBM437').valid_encoding?.should be_true
str.force_encoding('IBM737').valid_encoding?.should be_true
@@ -100,27 +100,25 @@ describe "String#valid_encoding?" do
str.force_encoding('UTF8-MAC').valid_encoding?.should be_true
end
- ruby_version_is '3.0' do
- it "returns true for IBM720 encoding self is valid in" do
- str = "\xE6\x9D\x94"
- str.force_encoding('IBM720').valid_encoding?.should be_true
- str.force_encoding('CP720').valid_encoding?.should be_true
- end
+ it "returns true for IBM720 encoding self is valid in" do
+ str = +"\xE6\x9D\x94"
+ str.force_encoding('IBM720').valid_encoding?.should be_true
+ str.force_encoding('CP720').valid_encoding?.should be_true
end
it "returns false if self is valid in one encoding, but invalid in the one it's tagged with" do
- str = "\u{8765}"
+ str = +"\u{8765}"
str.valid_encoding?.should be_true
- str = str.force_encoding('ascii')
+ str.force_encoding('ascii')
str.valid_encoding?.should be_false
end
it "returns false if self contains a character invalid in the associated encoding" do
- "abc#{[0x80].pack('C')}".force_encoding('ascii').valid_encoding?.should be_false
+ "abc#{[0x80].pack('C')}".dup.force_encoding('ascii').valid_encoding?.should be_false
end
it "returns false if a valid String had an invalid character appended to it" do
- str = "a"
+ str = +"a"
str.valid_encoding?.should be_true
str << [0xDD].pack('C').force_encoding('utf-8')
str.valid_encoding?.should be_false
diff --git a/spec/ruby/core/struct/constants_spec.rb b/spec/ruby/core/struct/constants_spec.rb
new file mode 100644
index 0000000000..fa61a4b912
--- /dev/null
+++ b/spec/ruby/core/struct/constants_spec.rb
@@ -0,0 +1,15 @@
+require_relative '../../spec_helper'
+
+ruby_version_is "3.2" do
+ describe "Struct::Group" do
+ it "is no longer defined" do
+ Struct.should_not.const_defined?(:Group)
+ end
+ end
+
+ describe "Struct::Passwd" do
+ it "is no longer defined" do
+ Struct.should_not.const_defined?(:Passwd)
+ end
+ end
+end
diff --git a/spec/ruby/core/struct/deconstruct_keys_spec.rb b/spec/ruby/core/struct/deconstruct_keys_spec.rb
index f0a1f50ad3..b4c84c49df 100644
--- a/spec/ruby/core/struct/deconstruct_keys_spec.rb
+++ b/spec/ruby/core/struct/deconstruct_keys_spec.rb
@@ -1,78 +1,76 @@
require_relative '../../spec_helper'
-ruby_version_is "2.7" do
- describe "Struct#deconstruct_keys" do
- it "returns a hash of attributes" do
- struct = Struct.new(:x, :y)
- s = struct.new(1, 2)
-
- s.deconstruct_keys([:x, :y]).should == {x: 1, y: 2}
- end
-
- it "requires one argument" do
- struct = Struct.new(:x)
- obj = struct.new(1)
-
- -> {
- obj.deconstruct_keys
- }.should raise_error(ArgumentError, /wrong number of arguments \(given 0, expected 1\)/)
- end
-
- it "returns only specified keys" do
- struct = Struct.new(:x, :y, :z)
- s = struct.new(1, 2, 3)
-
- s.deconstruct_keys([:x, :y]).should == {x: 1, y: 2}
- s.deconstruct_keys([:x] ).should == {x: 1}
- s.deconstruct_keys([] ).should == {}
- end
-
- it "accepts string attribute names" do
- struct = Struct.new(:x, :y)
- s = struct.new(1, 2)
-
- s.deconstruct_keys(['x', 'y']).should == {'x' => 1, 'y' => 2}
- end
-
- it "accepts argument position number as well but returns them as keys" do
- struct = Struct.new(:x, :y, :z)
- s = struct.new(10, 20, 30)
-
- s.deconstruct_keys([0, 1, 2]).should == {0 => 10, 1 => 20, 2 => 30}
- s.deconstruct_keys([0, 1] ).should == {0 => 10, 1 => 20}
- s.deconstruct_keys([0] ).should == {0 => 10}
- end
-
- it "returns an empty hash when there are more keys than attributes" do
- struct = Struct.new(:x, :y)
- s = struct.new(1, 2)
-
- s.deconstruct_keys([:x, :y, :a]).should == {}
- end
-
- it "returns at first not existing attribute name" do
- struct = Struct.new(:x, :y)
- s = struct.new(1, 2)
-
- s.deconstruct_keys([:a, :x]).should == {}
- s.deconstruct_keys([:x, :a]).should == {x: 1}
- end
-
- it "accepts nil argument and return all the attributes" do
- struct = Struct.new(:x, :y)
- obj = struct.new(1, 2)
-
- obj.deconstruct_keys(nil).should == {x: 1, y: 2}
- end
-
- it "raise TypeError if passed anything accept nil or array" do
- struct = Struct.new(:x, :y)
- s = struct.new(1, 2)
-
- -> { s.deconstruct_keys('x') }.should raise_error(TypeError, /expected Array or nil/)
- -> { s.deconstruct_keys(1) }.should raise_error(TypeError, /expected Array or nil/)
- -> { s.deconstruct_keys(:x) }.should raise_error(TypeError, /expected Array or nil/)
- -> { s.deconstruct_keys({}) }.should raise_error(TypeError, /expected Array or nil/)
- end
+describe "Struct#deconstruct_keys" do
+ it "returns a hash of attributes" do
+ struct = Struct.new(:x, :y)
+ s = struct.new(1, 2)
+
+ s.deconstruct_keys([:x, :y]).should == {x: 1, y: 2}
+ end
+
+ it "requires one argument" do
+ struct = Struct.new(:x)
+ obj = struct.new(1)
+
+ -> {
+ obj.deconstruct_keys
+ }.should raise_error(ArgumentError, /wrong number of arguments \(given 0, expected 1\)/)
+ end
+
+ it "returns only specified keys" do
+ struct = Struct.new(:x, :y, :z)
+ s = struct.new(1, 2, 3)
+
+ s.deconstruct_keys([:x, :y]).should == {x: 1, y: 2}
+ s.deconstruct_keys([:x] ).should == {x: 1}
+ s.deconstruct_keys([] ).should == {}
+ end
+
+ it "accepts string attribute names" do
+ struct = Struct.new(:x, :y)
+ s = struct.new(1, 2)
+
+ s.deconstruct_keys(['x', 'y']).should == {'x' => 1, 'y' => 2}
+ end
+
+ it "accepts argument position number as well but returns them as keys" do
+ struct = Struct.new(:x, :y, :z)
+ s = struct.new(10, 20, 30)
+
+ s.deconstruct_keys([0, 1, 2]).should == {0 => 10, 1 => 20, 2 => 30}
+ s.deconstruct_keys([0, 1] ).should == {0 => 10, 1 => 20}
+ s.deconstruct_keys([0] ).should == {0 => 10}
+ end
+
+ it "returns an empty hash when there are more keys than attributes" do
+ struct = Struct.new(:x, :y)
+ s = struct.new(1, 2)
+
+ s.deconstruct_keys([:x, :y, :a]).should == {}
+ end
+
+ it "returns at first not existing attribute name" do
+ struct = Struct.new(:x, :y)
+ s = struct.new(1, 2)
+
+ s.deconstruct_keys([:a, :x]).should == {}
+ s.deconstruct_keys([:x, :a]).should == {x: 1}
+ end
+
+ it "accepts nil argument and return all the attributes" do
+ struct = Struct.new(:x, :y)
+ obj = struct.new(1, 2)
+
+ obj.deconstruct_keys(nil).should == {x: 1, y: 2}
+ end
+
+ it "raise TypeError if passed anything except nil or array" do
+ struct = Struct.new(:x, :y)
+ s = struct.new(1, 2)
+
+ -> { s.deconstruct_keys('x') }.should raise_error(TypeError, /expected Array or nil/)
+ -> { s.deconstruct_keys(1) }.should raise_error(TypeError, /expected Array or nil/)
+ -> { s.deconstruct_keys(:x) }.should raise_error(TypeError, /expected Array or nil/)
+ -> { s.deconstruct_keys({}) }.should raise_error(TypeError, /expected Array or nil/)
end
end
diff --git a/spec/ruby/core/struct/deconstruct_spec.rb b/spec/ruby/core/struct/deconstruct_spec.rb
index 7518a40987..32d4f6bac4 100644
--- a/spec/ruby/core/struct/deconstruct_spec.rb
+++ b/spec/ruby/core/struct/deconstruct_spec.rb
@@ -1,12 +1,10 @@
require_relative '../../spec_helper'
-ruby_version_is "2.7" do
- describe "Struct#deconstruct" do
- it "returns an array of attribute values" do
- struct = Struct.new(:x, :y)
- s = struct.new(1, 2)
+describe "Struct#deconstruct" do
+ it "returns an array of attribute values" do
+ struct = Struct.new(:x, :y)
+ s = struct.new(1, 2)
- s.deconstruct.should == [1, 2]
- end
+ s.deconstruct.should == [1, 2]
end
end
diff --git a/spec/ruby/core/struct/fixtures/classes.rb b/spec/ruby/core/struct/fixtures/classes.rb
index 6d620f9060..bf838d05df 100644
--- a/spec/ruby/core/struct/fixtures/classes.rb
+++ b/spec/ruby/core/struct/fixtures/classes.rb
@@ -13,6 +13,12 @@ module StructClasses
end
end
+ class StructWithOverriddenName < Struct.new(:a)
+ def self.name
+ "A"
+ end
+ end
+
class SubclassX < Struct
end
diff --git a/spec/ruby/core/struct/initialize_spec.rb b/spec/ruby/core/struct/initialize_spec.rb
index e82289071a..a5ebe9551c 100644
--- a/spec/ruby/core/struct/initialize_spec.rb
+++ b/spec/ruby/core/struct/initialize_spec.rb
@@ -40,4 +40,22 @@ describe "Struct#initialize" do
it "can be overridden" do
StructClasses::SubclassX.new(:y).new.key.should == :value
end
+
+ ruby_version_is "3.1"..."3.2" do
+ it "warns about passing only keyword arguments" do
+ -> {
+ StructClasses::Ruby.new(version: "3.1", platform: "OS")
+ }.should complain(/warning: Passing only keyword arguments/)
+ end
+ end
+
+ ruby_version_is "3.2" do
+ it "can be initialized with keyword arguments" do
+ positional_args = StructClasses::Ruby.new("3.2", "OS")
+ keyword_args = StructClasses::Ruby.new(version: "3.2", platform: "OS")
+
+ positional_args.version.should == keyword_args.version
+ positional_args.platform.should == keyword_args.platform
+ end
+ end
end
diff --git a/spec/ruby/core/struct/inspect_spec.rb b/spec/ruby/core/struct/inspect_spec.rb
index 83e13597ba..657b06abc1 100644
--- a/spec/ruby/core/struct/inspect_spec.rb
+++ b/spec/ruby/core/struct/inspect_spec.rb
@@ -3,10 +3,5 @@ require_relative 'fixtures/classes'
require_relative 'shared/inspect'
describe "Struct#inspect" do
- it "returns a string representation showing members and values" do
- car = StructClasses::Car.new('Ford', 'Ranger')
- car.inspect.should == '#<struct StructClasses::Car make="Ford", model="Ranger", year=nil>'
- end
-
it_behaves_like :struct_inspect, :inspect
end
diff --git a/spec/ruby/core/struct/keyword_init_spec.rb b/spec/ruby/core/struct/keyword_init_spec.rb
new file mode 100644
index 0000000000..8de4c14351
--- /dev/null
+++ b/spec/ruby/core/struct/keyword_init_spec.rb
@@ -0,0 +1,40 @@
+require_relative '../../spec_helper'
+
+ruby_version_is "3.1" do
+ # See https://bugs.ruby-lang.org/issues/18008
+ describe "StructClass#keyword_init?" do
+ it "returns true for a struct that accepts keyword arguments to initialize" do
+ struct = Struct.new(:arg, keyword_init: true)
+ struct.keyword_init?.should be_true
+ end
+
+ it "returns false for a struct that does not accept keyword arguments to initialize" do
+ struct = Struct.new(:arg, keyword_init: false)
+ struct.keyword_init?.should be_false
+ end
+
+ it "returns nil for a struct that did not explicitly specify keyword_init" do
+ struct = Struct.new(:arg)
+ struct.keyword_init?.should be_nil
+ end
+
+ it "returns nil for a struct that does specify keyword_init to be nil" do
+ struct = Struct.new(:arg, keyword_init: nil)
+ struct.keyword_init?.should be_nil
+ end
+
+ it "returns true for any truthy value, not just for true" do
+ struct = Struct.new(:arg, keyword_init: 1)
+ struct.keyword_init?.should be_true
+
+ struct = Struct.new(:arg, keyword_init: "")
+ struct.keyword_init?.should be_true
+
+ struct = Struct.new(:arg, keyword_init: [])
+ struct.keyword_init?.should be_true
+
+ struct = Struct.new(:arg, keyword_init: {})
+ struct.keyword_init?.should be_true
+ end
+ end
+end
diff --git a/spec/ruby/core/struct/new_spec.rb b/spec/ruby/core/struct/new_spec.rb
index cbbec829d7..a94eb852e1 100644
--- a/spec/ruby/core/struct/new_spec.rb
+++ b/spec/ruby/core/struct/new_spec.rb
@@ -47,6 +47,11 @@ describe "Struct.new" do
Struct.const_defined?("Animal2").should be_false
end
+ it "allows non-ASCII member name" do
+ name = "r\xe9sum\xe9".dup.force_encoding(Encoding::ISO_8859_1).to_sym
+ struct = Struct.new(name)
+ struct.new("foo").send(name).should == "foo"
+ end
it "fails with invalid constant name as first argument" do
-> { Struct.new('animal', :name, :legs, :eyeballs) }.should raise_error(NameError)
@@ -62,8 +67,34 @@ describe "Struct.new" do
-> { Struct.new(:animal, ['chris', 'evan']) }.should raise_error(TypeError)
end
- it "raises a ArgumentError if passed a Hash with an unknown key" do
- -> { Struct.new(:animal, { name: 'chris' }) }.should raise_error(ArgumentError)
+ ruby_version_is ""..."3.2" do
+ it "raises a TypeError or ArgumentError if passed a Hash with an unknown key" do
+ # CRuby < 3.2 raises ArgumentError: unknown keyword: :name, but that seems a bug:
+ # https://bugs.ruby-lang.org/issues/18632
+ -> { Struct.new(:animal, { name: 'chris' }) }.should raise_error(StandardError) { |e|
+ [ArgumentError, TypeError].should.include?(e.class)
+ }
+ end
+ end
+
+ ruby_version_is "3.2" do
+ it "raises a TypeError if passed a Hash with an unknown key" do
+ -> { Struct.new(:animal, { name: 'chris' }) }.should raise_error(TypeError)
+ end
+ end
+
+ ruby_version_is ""..."3.3" do
+ it "raises ArgumentError if not provided any arguments" do
+ -> { Struct.new }.should raise_error(ArgumentError)
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "works when not provided any arguments" do
+ c = Struct.new
+ c.should be_kind_of(Class)
+ c.superclass.should == Struct
+ end
end
it "raises ArgumentError when there is a duplicate member" do
diff --git a/spec/ruby/core/struct/shared/inspect.rb b/spec/ruby/core/struct/shared/inspect.rb
index 90594a5452..1a0fb6a6b2 100644
--- a/spec/ruby/core/struct/shared/inspect.rb
+++ b/spec/ruby/core/struct/shared/inspect.rb
@@ -1,5 +1,40 @@
describe :struct_inspect, shared: true do
+ it "returns a string representation showing members and values" do
+ car = StructClasses::Car.new('Ford', 'Ranger')
+ car.send(@method).should == '#<struct StructClasses::Car make="Ford", model="Ranger", year=nil>'
+ end
+
it "returns a string representation without the class name for anonymous structs" do
Struct.new(:a).new("").send(@method).should == '#<struct a="">'
end
+
+ it "returns a string representation without the class name for structs nested in anonymous classes" do
+ c = Class.new
+ c.class_eval <<~DOC
+ class Foo < Struct.new(:a); end
+ DOC
+
+ c::Foo.new("").send(@method).should == '#<struct a="">'
+ end
+
+ it "returns a string representation without the class name for structs nested in anonymous modules" do
+ m = Module.new
+ m.module_eval <<~DOC
+ class Foo < Struct.new(:a); end
+ DOC
+
+ m::Foo.new("").send(@method).should == '#<struct a="">'
+ end
+
+ it "does not call #name method" do
+ struct = StructClasses::StructWithOverriddenName.new("")
+ struct.send(@method).should == '#<struct StructClasses::StructWithOverriddenName a="">'
+ end
+
+ it "does not call #name method when struct is anonymous" do
+ struct = Struct.new(:a)
+ def struct.name; "A"; end
+
+ struct.new("").send(@method).should == '#<struct a="">'
+ end
end
diff --git a/spec/ruby/core/struct/values_at_spec.rb b/spec/ruby/core/struct/values_at_spec.rb
index e7d287cba2..5e5a496600 100644
--- a/spec/ruby/core/struct/values_at_spec.rb
+++ b/spec/ruby/core/struct/values_at_spec.rb
@@ -1,16 +1,59 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
+# Should be synchronized with core/array/values_at_spec.rb
describe "Struct#values_at" do
- it "returns an array of values" do
+ before do
clazz = Struct.new(:name, :director, :year)
- movie = clazz.new('Sympathy for Mr. Vengeance', 'Chan-wook Park', 2002)
- movie.values_at(0, 1).should == ['Sympathy for Mr. Vengeance', 'Chan-wook Park']
- movie.values_at(0..2).should == ['Sympathy for Mr. Vengeance', 'Chan-wook Park', 2002]
+ @movie = clazz.new('Sympathy for Mr. Vengeance', 'Chan-wook Park', 2002)
+ end
+
+ context "when passed a list of Integers" do
+ it "returns an array containing each value given by one of integers" do
+ @movie.values_at(0, 1).should == ['Sympathy for Mr. Vengeance', 'Chan-wook Park']
+ end
+
+ it "raises IndexError if any of integers is out of range" do
+ -> { @movie.values_at(3) }.should raise_error(IndexError, "offset 3 too large for struct(size:3)")
+ -> { @movie.values_at(-4) }.should raise_error(IndexError, "offset -4 too small for struct(size:3)")
+ end
+ end
+
+ context "when passed an integer Range" do
+ it "returns an array containing each value given by the elements of the range" do
+ @movie.values_at(0..2).should == ['Sympathy for Mr. Vengeance', 'Chan-wook Park', 2002]
+ end
+
+ it "fills with nil values for range elements larger than the structure" do
+ @movie.values_at(0..3).should == ['Sympathy for Mr. Vengeance', 'Chan-wook Park', 2002, nil]
+ end
+
+ it "raises RangeError if any element of the range is negative and out of range" do
+ -> { @movie.values_at(-4..3) }.should raise_error(RangeError, "-4..3 out of range")
+ end
+
+ it "supports endless Range" do
+ @movie.values_at(0..).should == ["Sympathy for Mr. Vengeance", "Chan-wook Park", 2002]
+ end
+
+ it "supports beginningless Range" do
+ @movie.values_at(..2).should == ["Sympathy for Mr. Vengeance", "Chan-wook Park", 2002]
+ end
+ end
+
+ it "supports multiple integer Ranges" do
+ @movie.values_at(0..2, 1..2).should == ['Sympathy for Mr. Vengeance', 'Chan-wook Park', 2002, 'Chan-wook Park', 2002]
+ end
+
+ it "supports mixing integer Ranges and Integers" do
+ @movie.values_at(0..2, 2).should == ['Sympathy for Mr. Vengeance', 'Chan-wook Park', 2002, 2002]
+ end
+
+ it "returns a new empty Array if no arguments given" do
+ @movie.values_at().should == []
end
it "fails when passed unsupported types" do
- car = StructClasses::Car.new('Ford', 'Ranger')
- -> { car.values_at('make') }.should raise_error(TypeError)
+ -> { @movie.values_at('make') }.should raise_error(TypeError, "no implicit conversion of String into Integer")
end
end
diff --git a/spec/ruby/core/symbol/casecmp_spec.rb b/spec/ruby/core/symbol/casecmp_spec.rb
index 80ea51e910..662a29a284 100644
--- a/spec/ruby/core/symbol/casecmp_spec.rb
+++ b/spec/ruby/core/symbol/casecmp_spec.rb
@@ -56,6 +56,10 @@ describe "Symbol#casecmp with Symbol" do
lower_a_tilde.casecmp(upper_a_tilde).should == 1
lower_a_umlaut.casecmp(upper_a_umlaut).should == 1
end
+
+ it "returns 0 for empty strings in different encodings" do
+ ''.to_sym.casecmp(''.encode("UTF-32LE").to_sym).should == 0
+ end
end
describe "Symbol#casecmp" do
@@ -141,4 +145,8 @@ describe 'Symbol#casecmp?' do
upper_a_tilde.casecmp?(lower_a_tilde).should == nil
lower_a_tilde.casecmp?(upper_a_tilde).should == nil
end
+
+ it "returns true for empty symbols in different encodings" do
+ ''.to_sym.should.casecmp?(''.encode("UTF-32LE").to_sym)
+ end
end
diff --git a/spec/ruby/core/symbol/end_with_spec.rb b/spec/ruby/core/symbol/end_with_spec.rb
index 77dc4caf71..4b9f5a4996 100644
--- a/spec/ruby/core/symbol/end_with_spec.rb
+++ b/spec/ruby/core/symbol/end_with_spec.rb
@@ -3,8 +3,6 @@
require_relative '../../spec_helper'
require_relative '../../shared/string/end_with'
-ruby_version_is "2.7" do
- describe "Symbol#end_with?" do
- it_behaves_like :end_with, :to_sym
- end
+describe "Symbol#end_with?" do
+ it_behaves_like :end_with, :to_sym
end
diff --git a/spec/ruby/core/symbol/inspect_spec.rb b/spec/ruby/core/symbol/inspect_spec.rb
index 58402ab261..6dbb36c2ad 100644
--- a/spec/ruby/core/symbol/inspect_spec.rb
+++ b/spec/ruby/core/symbol/inspect_spec.rb
@@ -5,6 +5,8 @@ describe "Symbol#inspect" do
fred: ":fred",
:fred? => ":fred?",
:fred! => ":fred!",
+ :BAD! => ":BAD!",
+ :_BAD! => ":_BAD!",
:$ruby => ":$ruby",
:@ruby => ":@ruby",
:@@ruby => ":@@ruby",
diff --git a/spec/ruby/core/symbol/name_spec.rb b/spec/ruby/core/symbol/name_spec.rb
index 15b9aa75e9..f9b631266c 100644
--- a/spec/ruby/core/symbol/name_spec.rb
+++ b/spec/ruby/core/symbol/name_spec.rb
@@ -1,19 +1,17 @@
require_relative '../../spec_helper'
-ruby_version_is "3.0" do
- describe "Symbol#name" do
- it "returns string" do
- :ruby.name.should == "ruby"
- :ルビー.name.should == "ルビー"
- end
+describe "Symbol#name" do
+ it "returns string" do
+ :ruby.name.should == "ruby"
+ :ルビー.name.should == "ルビー"
+ end
- it "returns same string instance" do
- :"ruby_3".name.should.equal?(:ruby_3.name)
- :"ruby_#{1+2}".name.should.equal?(:ruby_3.name)
- end
+ it "returns same string instance" do
+ :"ruby_3".name.should.equal?(:ruby_3.name)
+ :"ruby_#{1+2}".name.should.equal?(:ruby_3.name)
+ end
- it "returns frozen string" do
- :symbol.name.should.frozen?
- end
+ it "returns frozen string" do
+ :symbol.name.should.frozen?
end
end
diff --git a/spec/ruby/core/symbol/shared/id2name.rb b/spec/ruby/core/symbol/shared/id2name.rb
index 47f97bd332..d012b7634e 100644
--- a/spec/ruby/core/symbol/shared/id2name.rb
+++ b/spec/ruby/core/symbol/shared/id2name.rb
@@ -6,4 +6,11 @@ describe :symbol_id2name, shared: true do
:@ruby.send(@method).should == "@ruby"
:@@ruby.send(@method).should == "@@ruby"
end
+
+ it "returns a String in the same encoding as self" do
+ string = "ruby".encode("US-ASCII")
+ symbol = string.to_sym
+
+ symbol.send(@method).encoding.should == Encoding::US_ASCII
+ end
end
diff --git a/spec/ruby/core/symbol/shared/slice.rb b/spec/ruby/core/symbol/shared/slice.rb
index 3f07f6aedb..0df87e183d 100644
--- a/spec/ruby/core/symbol/shared/slice.rb
+++ b/spec/ruby/core/symbol/shared/slice.rb
@@ -190,16 +190,6 @@ describe :symbol_slice, shared: true do
:symbol.send(@method, /[0-9]+/)
$~.should be_nil
end
-
- ruby_version_is ''...'2.7' do
- it "returns a tainted string if the regexp is tainted" do
- :symbol.send(@method, /./.taint).tainted?.should be_true
- end
-
- it "returns an untrusted string if the regexp is untrusted" do
- :symbol.send(@method, /./.untrust).untrusted?.should be_true
- end
- end
end
describe "with a capture index" do
@@ -221,16 +211,6 @@ describe :symbol_slice, shared: true do
:symbol.send(@method, /(sy)(mb)(ol)/, 1.5).should == "sy"
end
- ruby_version_is ''...'2.7' do
- it "returns a tainted string if the regexp is tainted" do
- :symbol.send(@method, /(.)/.taint, 1).tainted?.should be_true
- end
-
- it "returns an untrusted string if the regexp is untrusted" do
- :symbol.send(@method, /(.)/.untrust, 1).untrusted?.should be_true
- end
- end
-
describe "and an index that cannot be converted to an Integer" do
it "raises a TypeError when given an Hash" do
-> { :symbol.send(@method, /(sy)(mb)(ol)/, Hash.new) }.should raise_error(TypeError)
diff --git a/spec/ruby/core/symbol/start_with_spec.rb b/spec/ruby/core/symbol/start_with_spec.rb
index f54b3e499e..cd43279003 100644
--- a/spec/ruby/core/symbol/start_with_spec.rb
+++ b/spec/ruby/core/symbol/start_with_spec.rb
@@ -3,8 +3,6 @@ require_relative '../../spec_helper'
require_relative 'fixtures/classes'
require_relative '../../shared/string/start_with'
-ruby_version_is "2.7" do
- describe "Symbol#start_with?" do
- it_behaves_like :start_with, :to_sym
- end
+describe "Symbol#start_with?" do
+ it_behaves_like :start_with, :to_sym
end
diff --git a/spec/ruby/core/symbol/to_proc_spec.rb b/spec/ruby/core/symbol/to_proc_spec.rb
index 47f2a939ab..54eccdba11 100644
--- a/spec/ruby/core/symbol/to_proc_spec.rb
+++ b/spec/ruby/core/symbol/to_proc_spec.rb
@@ -12,37 +12,45 @@ describe "Symbol#to_proc" do
:to_s.to_proc.call(obj).should == "Received #to_s"
end
- ruby_version_is ""..."3.0" do
- it "returns a Proc with #lambda? false" do
- pr = :to_s.to_proc
- pr.should_not.lambda?
- end
+ it "returns a Proc with #lambda? true" do
+ pr = :to_s.to_proc
+ pr.should.lambda?
+ end
- it "produces a Proc with arity -1" do
- pr = :to_s.to_proc
- pr.arity.should == -1
- end
+ it "produces a Proc with arity -2" do
+ pr = :to_s.to_proc
+ pr.arity.should == -2
+ end
- it "produces a Proc that always returns [[:rest]] for #parameters" do
- pr = :to_s.to_proc
- pr.parameters.should == [[:rest]]
- end
+ it "produces a Proc that always returns [[:req], [:rest]] for #parameters" do
+ pr = :to_s.to_proc
+ pr.parameters.should == [[:req], [:rest]]
end
- ruby_version_is "3.0" do
- it "returns a Proc with #lambda? true" do
- pr = :to_s.to_proc
- pr.should.lambda?
- 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 "produces a Proc with arity -2" do
- pr = :to_s.to_proc
- pr.arity.should == -2
- end
+ @a = []
+ singleton_class.class_eval(&body)
+ tap(&:pub)
+ proc{tap(&:pro)}.should raise_error(NoMethodError, /protected method [`']pro' called/)
+ proc{tap(&:pri)}.should raise_error(NoMethodError, /private method [`']pri' called/)
+ @a.should == [:pub]
- it "produces a Proc that always returns [[:req], [:rest]] for #parameters" do
- pr = :to_s.to_proc
- pr.parameters.should == [[:req], [:rest]]
+ @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
end
diff --git a/spec/ruby/core/thread/backtrace/limit_spec.rb b/spec/ruby/core/thread/backtrace/limit_spec.rb
new file mode 100644
index 0000000000..26a87a806c
--- /dev/null
+++ b/spec/ruby/core/thread/backtrace/limit_spec.rb
@@ -0,0 +1,15 @@
+require_relative '../../../spec_helper'
+
+ruby_version_is "3.1" do
+ describe "Thread::Backtrace.limit" do
+ it "returns maximum backtrace length set by --backtrace-limit command-line option" do
+ out = ruby_exe("print Thread::Backtrace.limit", options: "--backtrace-limit=2")
+ out.should == "2"
+ end
+
+ it "returns -1 when --backtrace-limit command-line option is not set" do
+ out = ruby_exe("print Thread::Backtrace.limit")
+ out.should == "-1"
+ end
+ end
+end
diff --git a/spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb b/spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb
index 4136f09348..6e381e4868 100644
--- a/spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb
+++ b/spec/ruby/core/thread/backtrace/location/absolute_path_spec.rb
@@ -17,6 +17,15 @@ describe 'Thread::Backtrace::Location#absolute_path' do
end
end
+ it 'returns the correct absolute path when using a relative main script path and changing CWD' do
+ script = fixture(__FILE__, 'subdir/absolute_path_main_chdir.rb')
+ sibling = fixture(__FILE__, 'subdir/sibling.rb')
+ subdir = File.dirname script
+ Dir.chdir(fixture(__FILE__)) do
+ ruby_exe('subdir/absolute_path_main_chdir.rb').should == "subdir/absolute_path_main_chdir.rb\n#{subdir}\n#{subdir}\n#{script}\n#{sibling}\n"
+ end
+ end
+
context "when used in eval with a given filename" do
code = "caller_locations(0)[0].absolute_path"
@@ -50,7 +59,7 @@ describe 'Thread::Backtrace::Location#absolute_path' do
it "returns nil" do
location = nil
tap { location = caller_locations(1, 1)[0] }
- location.label.should == "tap"
+ location.label.should =~ /\A(?:Kernel#)?tap\z/
if location.path.start_with?("<internal:")
location.absolute_path.should == nil
else
diff --git a/spec/ruby/core/thread/backtrace/location/fixtures/subdir/absolute_path_main_chdir.rb b/spec/ruby/core/thread/backtrace/location/fixtures/subdir/absolute_path_main_chdir.rb
new file mode 100644
index 0000000000..33c8fb36ef
--- /dev/null
+++ b/spec/ruby/core/thread/backtrace/location/fixtures/subdir/absolute_path_main_chdir.rb
@@ -0,0 +1,11 @@
+puts __FILE__
+puts __dir__
+Dir.chdir __dir__
+
+# Check __dir__ is still correct after chdir
+puts __dir__
+
+puts caller_locations(0)[0].absolute_path
+
+# require_relative also needs to know the absolute path of the current file so we test it here too
+require_relative 'sibling'
diff --git a/spec/ruby/core/thread/backtrace/location/fixtures/subdir/sibling.rb b/spec/ruby/core/thread/backtrace/location/fixtures/subdir/sibling.rb
new file mode 100644
index 0000000000..2a854ddccd
--- /dev/null
+++ b/spec/ruby/core/thread/backtrace/location/fixtures/subdir/sibling.rb
@@ -0,0 +1 @@
+puts __FILE__
diff --git a/spec/ruby/core/thread/backtrace/location/label_spec.rb b/spec/ruby/core/thread/backtrace/location/label_spec.rb
index 7312d017e5..85ddccc8e3 100644
--- a/spec/ruby/core/thread/backtrace/location/label_spec.rb
+++ b/spec/ruby/core/thread/backtrace/location/label_spec.rb
@@ -7,11 +7,11 @@ describe 'Thread::Backtrace::Location#label' do
end
it 'returns the method name for a method location' do
- ThreadBacktraceLocationSpecs.method_location[0].label.should == "method_location"
+ ThreadBacktraceLocationSpecs.method_location[0].label.should =~ /\A(?:ThreadBacktraceLocationSpecs\.)?method_location\z/
end
it 'returns the block name for a block location' do
- ThreadBacktraceLocationSpecs.block_location[0].label.should == "block in block_location"
+ ThreadBacktraceLocationSpecs.block_location[0].label.should =~ /\Ablock in (?:ThreadBacktraceLocationSpecs\.)?block_location\z/
end
it 'returns the module name for a module location' do
@@ -22,9 +22,9 @@ describe 'Thread::Backtrace::Location#label' do
first_level_location, second_level_location, third_level_location =
ThreadBacktraceLocationSpecs.locations_inside_nested_blocks
- first_level_location.label.should == 'block in locations_inside_nested_blocks'
- second_level_location.label.should == 'block (2 levels) in locations_inside_nested_blocks'
- third_level_location.label.should == 'block (3 levels) in locations_inside_nested_blocks'
+ first_level_location.label.should =~ /\Ablock in (?:ThreadBacktraceLocationSpecs\.)?locations_inside_nested_blocks\z/
+ second_level_location.label.should =~ /\Ablock \(2 levels\) in (?:ThreadBacktraceLocationSpecs\.)?locations_inside_nested_blocks\z/
+ third_level_location.label.should =~ /\Ablock \(3 levels\) in (?:ThreadBacktraceLocationSpecs\.)?locations_inside_nested_blocks\z/
end
it 'sets the location label for a top-level block differently depending on it being in the main file or a required file' do
diff --git a/spec/ruby/core/thread/backtrace/location/lineno_spec.rb b/spec/ruby/core/thread/backtrace/location/lineno_spec.rb
index d14cf17514..10457f80f0 100644
--- a/spec/ruby/core/thread/backtrace/location/lineno_spec.rb
+++ b/spec/ruby/core/thread/backtrace/location/lineno_spec.rb
@@ -7,7 +7,7 @@ describe 'Thread::Backtrace::Location#lineno' do
@line = __LINE__ - 1
end
- it 'returns the absolute path of the call frame' do
+ it 'returns the line number of the call frame' do
@frame.lineno.should == @line
end
diff --git a/spec/ruby/core/thread/backtrace/location/path_spec.rb b/spec/ruby/core/thread/backtrace/location/path_spec.rb
index 7863c055d3..75f76833a9 100644
--- a/spec/ruby/core/thread/backtrace/location/path_spec.rb
+++ b/spec/ruby/core/thread/backtrace/location/path_spec.rb
@@ -41,7 +41,7 @@ describe 'Thread::Backtrace::Location#path' do
context 'when using a relative script path' do
it 'returns a path relative to the working directory' do
path = 'fixtures/main.rb'
- directory = File.dirname(__FILE__)
+ directory = __dir__
Dir.chdir(directory) {
ruby_exe(path)
}.should == path
diff --git a/spec/ruby/core/thread/backtrace_locations_spec.rb b/spec/ruby/core/thread/backtrace_locations_spec.rb
index 237941c214..09fe622e0d 100644
--- a/spec/ruby/core/thread/backtrace_locations_spec.rb
+++ b/spec/ruby/core/thread/backtrace_locations_spec.rb
@@ -49,12 +49,10 @@ describe "Thread#backtrace_locations" do
locations2.map(&:to_s).should == locations1[2..-1].map(&:to_s)
end
- ruby_version_is "2.7" do
- it "can be called with an beginless range" do
- locations1 = Thread.current.backtrace_locations(0)
- locations2 = Thread.current.backtrace_locations(eval("(..5)"))
- locations2.map(&:to_s)[eval("(2..)")].should == locations1[eval("(..5)")].map(&:to_s)[eval("(2..)")]
- end
+ it "can be called with an beginless range" do
+ locations1 = Thread.current.backtrace_locations(0)
+ locations2 = Thread.current.backtrace_locations((..5))
+ locations2.map(&:to_s)[eval("(2..)")].should == locations1[(..5)].map(&:to_s)[eval("(2..)")]
end
it "returns nil if omitting more locations than available" do
@@ -72,7 +70,7 @@ describe "Thread#backtrace_locations" do
end
it "the first location reports the call to #backtrace_locations" do
- Thread.current.backtrace_locations(0..0)[0].to_s.should == "#{__FILE__ }:#{__LINE__ }:in `backtrace_locations'"
+ Thread.current.backtrace_locations(0..0)[0].to_s.should =~ /\A#{__FILE__ }:#{__LINE__ }:in [`'](?:Thread#)?backtrace_locations'\z/
end
it "[1..-1] is the same as #caller_locations(0..-1) for Thread.current" do
diff --git a/spec/ruby/core/thread/backtrace_spec.rb b/spec/ruby/core/thread/backtrace_spec.rb
index 9001b1b7eb..15bb29a349 100644
--- a/spec/ruby/core/thread/backtrace_spec.rb
+++ b/spec/ruby/core/thread/backtrace_spec.rb
@@ -13,7 +13,7 @@ describe "Thread#backtrace" do
backtrace = t.backtrace
backtrace.should be_kind_of(Array)
- backtrace.first.should =~ /`sleep'/
+ backtrace.first.should =~ /[`'](?:Kernel#)?sleep'/
t.raise 'finish the thread'
t.join
diff --git a/spec/ruby/core/thread/each_caller_location_spec.rb b/spec/ruby/core/thread/each_caller_location_spec.rb
new file mode 100644
index 0000000000..29c271789b
--- /dev/null
+++ b/spec/ruby/core/thread/each_caller_location_spec.rb
@@ -0,0 +1,49 @@
+require_relative '../../spec_helper'
+
+describe "Thread.each_caller_location" do
+ ruby_version_is "3.2" do
+ it "iterates through the current execution stack and matches caller_locations content and type" do
+ ScratchPad.record []
+ Thread.each_caller_location { |l| ScratchPad << l; }
+
+ ScratchPad.recorded.map(&:to_s).should == caller_locations.map(&:to_s)
+ ScratchPad.recorded[0].should be_kind_of(Thread::Backtrace::Location)
+ end
+
+ it "returns subset of 'Thread.to_enum(:each_caller_location)' locations" do
+ ar = []
+ ecl = Thread.each_caller_location { |x| ar << x }
+
+ (ar.map(&:to_s) - Thread.to_enum(:each_caller_location).to_a.map(&:to_s)).should.empty?
+ end
+
+ it "stops the backtrace iteration if 'break' occurs" do
+ i = 0
+ ar = []
+ ecl = Thread.each_caller_location do |x|
+ ar << x
+ i += 1
+ break x if i == 2
+ end
+
+ ar.map(&:to_s).should == caller_locations(1, 2).map(&:to_s)
+ ecl.should be_kind_of(Thread::Backtrace::Location)
+ end
+
+ it "returns nil" do
+ Thread.each_caller_location {}.should == nil
+ end
+
+ it "raises LocalJumpError when called without a block" do
+ -> {
+ Thread.each_caller_location
+ }.should raise_error(LocalJumpError, "no block given")
+ end
+
+ it "doesn't accept keyword arguments" do
+ -> {
+ Thread.each_caller_location(12, foo: 10) {}
+ }.should raise_error(ArgumentError);
+ end
+ end
+end
diff --git a/spec/ruby/core/thread/exclusive_spec.rb b/spec/ruby/core/thread/exclusive_spec.rb
deleted file mode 100644
index 37c4b19d1a..0000000000
--- a/spec/ruby/core/thread/exclusive_spec.rb
+++ /dev/null
@@ -1,49 +0,0 @@
-require_relative '../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- describe "Thread.exclusive" do
- before :each do
- ScratchPad.clear
- $VERBOSE, @verbose = nil, $VERBOSE
- end
-
- after :each do
- $VERBOSE = @verbose
- end
-
- it "yields to the block" do
- Thread.exclusive { ScratchPad.record true }
- ScratchPad.recorded.should == true
- end
-
- it "returns the result of yielding" do
- Thread.exclusive { :result }.should == :result
- end
-
- it "blocks the caller if another thread is also in an exclusive block" do
- m = Mutex.new
- q1 = Queue.new
- q2 = Queue.new
-
- t = Thread.new {
- Thread.exclusive {
- q1.push :ready
- q2.pop
- }
- }
-
- q1.pop.should == :ready
-
- -> { Thread.exclusive { } }.should block_caller
-
- q2.push :done
- t.join
- end
-
- it "is not recursive" do
- Thread.exclusive do
- -> { Thread.exclusive { } }.should raise_error(ThreadError)
- end
- end
- end
-end
diff --git a/spec/ruby/core/thread/fetch_spec.rb b/spec/ruby/core/thread/fetch_spec.rb
index 6b37d4cfc5..85ffb71874 100644
--- a/spec/ruby/core/thread/fetch_spec.rb
+++ b/spec/ruby/core/thread/fetch_spec.rb
@@ -29,6 +29,36 @@ describe 'Thread#fetch' do
end
end
+ describe 'with a block' do
+ it 'returns the value of the fiber-local variable if value has been assigned' do
+ th = Thread.new { Thread.current[:cat] = 'meow' }
+ th.join
+ th.fetch(:cat) { true }.should == 'meow'
+ end
+
+ it "returns the block value if fiber-local variable hasn't been assigned" do
+ th = Thread.new {}
+ th.join
+ th.fetch(:cat) { true }.should == true
+ end
+
+ it "does not call the block if value has been assigned" do
+ th = Thread.new { Thread.current[:cat] = 'meow' }
+ th.join
+ var = :not_updated
+ th.fetch(:cat) { var = :updated }.should == 'meow'
+ var.should == :not_updated
+ end
+
+ it "uses the block if a default is given and warns about it" do
+ th = Thread.new {}
+ th.join
+ -> {
+ th.fetch(:cat, false) { true }.should == true
+ }.should complain(/warning: block supersedes default value argument/)
+ end
+ end
+
it 'raises an ArgumentError when not passed one or two arguments' do
-> { Thread.current.fetch() }.should raise_error(ArgumentError)
-> { Thread.current.fetch(1, 2, 3) }.should raise_error(ArgumentError)
diff --git a/spec/ruby/core/thread/ignore_deadlock_spec.rb b/spec/ruby/core/thread/ignore_deadlock_spec.rb
index 53cc2a7f5b..b48bc9f9b0 100644
--- a/spec/ruby/core/thread/ignore_deadlock_spec.rb
+++ b/spec/ruby/core/thread/ignore_deadlock_spec.rb
@@ -1,21 +1,19 @@
require_relative '../../spec_helper'
-ruby_version_is "3.0" do
- describe "Thread.ignore_deadlock" do
- it "returns false by default" do
- Thread.ignore_deadlock.should == false
- end
+describe "Thread.ignore_deadlock" do
+ it "returns false by default" do
+ Thread.ignore_deadlock.should == false
end
+end
- describe "Thread.ignore_deadlock=" do
- it "changes the value of Thread.ignore_deadlock" do
- ignore_deadlock = Thread.ignore_deadlock
- Thread.ignore_deadlock = true
- begin
- Thread.ignore_deadlock.should == true
- ensure
- Thread.ignore_deadlock = ignore_deadlock
- end
+describe "Thread.ignore_deadlock=" do
+ it "changes the value of Thread.ignore_deadlock" do
+ ignore_deadlock = Thread.ignore_deadlock
+ Thread.ignore_deadlock = true
+ begin
+ Thread.ignore_deadlock.should == true
+ ensure
+ Thread.ignore_deadlock = ignore_deadlock
end
end
end
diff --git a/spec/ruby/core/thread/kill_spec.rb b/spec/ruby/core/thread/kill_spec.rb
index f932bf5232..4b62c686c7 100644
--- a/spec/ruby/core/thread/kill_spec.rb
+++ b/spec/ruby/core/thread/kill_spec.rb
@@ -9,10 +9,6 @@ platform_is_not :mingw do
it_behaves_like :thread_exit, :kill
end
- describe "Thread#kill!" do
- it "needs to be reviewed for spec completeness"
- end
-
describe "Thread.kill" do
it "causes the given thread to exit" do
thread = Thread.new { sleep }
diff --git a/spec/ruby/core/thread/native_thread_id_spec.rb b/spec/ruby/core/thread/native_thread_id_spec.rb
new file mode 100644
index 0000000000..17a08c8a15
--- /dev/null
+++ b/spec/ruby/core/thread/native_thread_id_spec.rb
@@ -0,0 +1,37 @@
+require_relative '../../spec_helper'
+
+ruby_version_is "3.1" do
+ platform_is :linux, :darwin, :windows, :freebsd do
+ describe "Thread#native_thread_id" do
+ it "returns an integer when the thread is alive" do
+ Thread.current.native_thread_id.should be_kind_of(Integer)
+ end
+
+ it "returns nil when the thread is not running" do
+ t = Thread.new {}
+ t.join
+ t.native_thread_id.should == nil
+ end
+
+ it "each thread has different native thread id" do
+ t = Thread.new { sleep }
+ Thread.pass until t.stop?
+ main_thread_id = Thread.current.native_thread_id
+ t_thread_id = t.native_thread_id
+
+ if ruby_version_is "3.3"
+ # native_thread_id can be nil on a M:N scheduler
+ t_thread_id.should be_kind_of(Integer) if t_thread_id != nil
+ else
+ t_thread_id.should be_kind_of(Integer)
+ end
+
+ main_thread_id.should_not == t_thread_id
+
+ t.run
+ t.join
+ t.native_thread_id.should == nil
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/thread/raise_spec.rb b/spec/ruby/core/thread/raise_spec.rb
index 27de3cc627..49323cf270 100644
--- a/spec/ruby/core/thread/raise_spec.rb
+++ b/spec/ruby/core/thread/raise_spec.rb
@@ -102,6 +102,30 @@ describe "Thread#raise on a sleeping thread" do
raised_again.backtrace.first.should_not include("#{__FILE__}:#{raise_again_line}:")
end
end
+
+ it "calls #exception in both the caller and in the target thread" do
+ cls = Class.new(Exception) do
+ attr_accessor :log
+ def initialize(*args)
+ @log = [] # This is shared because the super #exception uses a shallow clone
+ super
+ end
+
+ def exception(*args)
+ @log << [self, Thread.current, args]
+ super
+ end
+ end
+ exc = cls.new
+
+ @thr.raise exc, "Thread#raise #exception spec"
+ @thr.join
+ ScratchPad.recorded.should.is_a?(cls)
+ exc.log.should == [
+ [exc, Thread.current, ["Thread#raise #exception spec"]],
+ [ScratchPad.recorded, @thr, []]
+ ]
+ end
end
describe "Thread#raise on a running thread" do
diff --git a/spec/ruby/core/thread/report_on_exception_spec.rb b/spec/ruby/core/thread/report_on_exception_spec.rb
index bf50a167df..d9daa041cd 100644
--- a/spec/ruby/core/thread/report_on_exception_spec.rb
+++ b/spec/ruby/core/thread/report_on_exception_spec.rb
@@ -60,6 +60,55 @@ describe "Thread#report_on_exception=" do
t.join
}.should raise_error(RuntimeError, "Thread#report_on_exception specs")
end
+
+ it "prints a backtrace on $stderr in the regular backtrace order" do
+ line_raise = __LINE__ + 2
+ def foo
+ raise RuntimeError, "Thread#report_on_exception specs backtrace order"
+ end
+
+ line_call_foo = __LINE__ + 5
+ go = false
+ t = Thread.new {
+ Thread.current.report_on_exception = true
+ Thread.pass until go
+ foo
+ }
+
+ -> {
+ go = true
+ Thread.pass while t.alive?
+ }.should output("", /\A
+#{Regexp.quote(t.inspect)}\sterminated\swith\sexception\s\(report_on_exception\sis\strue\):\n
+#{Regexp.quote(__FILE__)}:#{line_raise}:in\s[`']foo':\sThread\#report_on_exception\sspecs\sbacktrace\sorder\s\(RuntimeError\)\n
+\tfrom\s#{Regexp.quote(__FILE__)}:#{line_call_foo}:in\s[`']block\s\(4\slevels\)\sin\s<top\s\(required\)>'\n
+\z/x)
+
+ -> {
+ t.join
+ }.should raise_error(RuntimeError, "Thread#report_on_exception specs backtrace order")
+ end
+
+ it "prints the backtrace even if the thread was killed just after Thread#raise" do
+ t = nil
+ ready = false
+ -> {
+ t = Thread.new {
+ Thread.current.report_on_exception = true
+ ready = true
+ sleep
+ }
+
+ Thread.pass until ready and t.stop?
+ t.raise RuntimeError, "Thread#report_on_exception before kill spec"
+ t.kill
+ Thread.pass while t.alive?
+ }.should output("", /Thread.+terminated with exception.+Thread#report_on_exception before kill spec/m)
+
+ -> {
+ t.join
+ }.should raise_error(RuntimeError, "Thread#report_on_exception before kill spec")
+ end
end
describe "when set to false" do
diff --git a/spec/ruby/core/thread/shared/exit.rb b/spec/ruby/core/thread/shared/exit.rb
index 40dc478947..13e8832684 100644
--- a/spec/ruby/core/thread/shared/exit.rb
+++ b/spec/ruby/core/thread/shared/exit.rb
@@ -66,6 +66,26 @@ describe :thread_exit, shared: true do
ScratchPad.recorded.should == nil
end
+ it "does not reset $!" do
+ ScratchPad.record []
+
+ exc = RuntimeError.new("foo")
+ thread = Thread.new do
+ begin
+ raise exc
+ ensure
+ ScratchPad << $!
+ begin
+ Thread.current.send(@method)
+ ensure
+ ScratchPad << $!
+ end
+ end
+ end
+ thread.join
+ ScratchPad.recorded.should == [exc, exc]
+ end
+
it "cannot be rescued" do
thread = Thread.new do
begin
@@ -73,7 +93,7 @@ describe :thread_exit, shared: true do
rescue Exception
ScratchPad.record :in_rescue
end
- ScratchPad.record :end_of_thread_block
+ ScratchPad.record :end_of_thread_block
end
thread.join
@@ -93,6 +113,25 @@ describe :thread_exit, shared: true do
ScratchPad.recorded.should == nil
end
+ it "kills other fibers of that thread without running their ensure clauses" do
+ t = Thread.new do
+ f = Fiber.new do
+ ScratchPad.record :fiber_resumed
+ begin
+ Fiber.yield
+ ensure
+ ScratchPad.record :fiber_ensure
+ end
+ end
+ f.resume
+ sleep
+ end
+ Thread.pass until t.stop?
+ t.send(@method)
+ t.join
+ ScratchPad.recorded.should == :fiber_resumed
+ end
+
# This spec is a mess. It fails randomly, it hangs on MRI, it needs to be removed
quarantine! do
it "killing dying running does nothing" do
diff --git a/spec/ruby/core/thread/shared/to_s.rb b/spec/ruby/core/thread/shared/to_s.rb
index 45c04af627..43640deb33 100644
--- a/spec/ruby/core/thread/shared/to_s.rb
+++ b/spec/ruby/core/thread/shared/to_s.rb
@@ -1,12 +1,10 @@
require_relative '../fixtures/classes'
describe :thread_to_s, shared: true do
- sep = ruby_version_is("2.7") ? " " : "@"
-
it "returns a description including file and line number" do
thread, line = Thread.new { "hello" }, __LINE__
thread.join
- thread.send(@method).should =~ /^#<Thread:([^ ]*?)#{sep}#{Regexp.escape __FILE__}:#{line} \w+>$/
+ thread.send(@method).should =~ /^#<Thread:([^ ]*?) #{Regexp.escape __FILE__}:#{line} \w+>$/
end
it "has a binary encoding" do
diff --git a/spec/ruby/core/thread/thread_variable_get_spec.rb b/spec/ruby/core/thread/thread_variable_get_spec.rb
index 38f90d5830..0ad19bfd88 100644
--- a/spec/ruby/core/thread/thread_variable_get_spec.rb
+++ b/spec/ruby/core/thread/thread_variable_get_spec.rb
@@ -13,7 +13,7 @@ describe "Thread#thread_variable_get" do
@t.thread_variable_get(:a).should be_nil
end
- it "returns the value previously set by #[]=" do
+ it "returns the value previously set by #thread_variable_set" do
@t.thread_variable_set :a, 49
@t.thread_variable_get(:a).should == 49
end
diff --git a/spec/ruby/core/time/_load_spec.rb b/spec/ruby/core/time/_load_spec.rb
index 152934370f..bb0d705bbc 100644
--- a/spec/ruby/core/time/_load_spec.rb
+++ b/spec/ruby/core/time/_load_spec.rb
@@ -44,8 +44,7 @@ describe "Time._load" do
end
it "treats the data as binary data" do
- data = "\x04\bu:\tTime\r\fM\x1C\xC0\x00\x00\xD0\xBE"
- data.force_encoding Encoding::UTF_8
+ data = "\x04\bu:\tTime\r\fM\x1C\xC0\x00\x00\xD0\xBE".dup.force_encoding Encoding::UTF_8
t = Marshal.load(data)
t.to_s.should == "2013-04-08 12:47:45 UTC"
end
diff --git a/spec/ruby/core/time/at_spec.rb b/spec/ruby/core/time/at_spec.rb
index 2cc46ab8c9..48fb3c6f52 100644
--- a/spec/ruby/core/time/at_spec.rb
+++ b/spec/ruby/core/time/at_spec.rb
@@ -32,13 +32,6 @@ describe "Time.at" do
t2.nsec.should == t.nsec
end
- describe "passed BigDecimal" do
- it "doesn't round input value" do
- require 'bigdecimal'
- Time.at(BigDecimal('1.1')).to_f.should == 1.1
- end
- end
-
describe "passed Rational" do
it "returns Time with correct microseconds" do
t = Time.at(Rational(1_486_570_508_539_759, 1_000_000))
@@ -203,7 +196,7 @@ describe "Time.at" do
end
it "does not try to convert format to Symbol with #to_sym" do
- format = "usec"
+ format = +"usec"
format.should_not_receive(:to_sym)
-> { Time.at(0, 123456, format) }.should raise_error(ArgumentError)
end
@@ -251,6 +244,22 @@ describe "Time.at" do
time.to_i.should == @epoch_time
end
+ it "could be UTC offset as a 'UTC' String" do
+ time = Time.at(@epoch_time, in: "UTC")
+
+ time.utc_offset.should == 0
+ time.zone.should == "UTC"
+ time.to_i.should == @epoch_time
+ end
+
+ it "could be UTC offset as a military zone A-Z" do
+ time = Time.at(@epoch_time, in: "B")
+
+ time.utc_offset.should == 3600 * 2
+ time.zone.should == nil
+ time.to_i.should == @epoch_time
+ end
+
it "could be a timezone object" do
zone = TimeSpecs::TimezoneWithName.new(name: "Asia/Colombo")
time = Time.at(@epoch_time, in: zone)
@@ -266,5 +275,10 @@ describe "Time.at" do
time.zone.should == zone
time.to_i.should == @epoch_time
end
+
+ it "raises ArgumentError if format is invalid" do
+ -> { Time.at(@epoch_time, in: "+09:99") }.should raise_error(ArgumentError)
+ -> { Time.at(@epoch_time, in: "ABC") }.should raise_error(ArgumentError)
+ end
end
end
diff --git a/spec/ruby/core/time/ceil_spec.rb b/spec/ruby/core/time/ceil_spec.rb
index 86029554db..9d624a1ed0 100644
--- a/spec/ruby/core/time/ceil_spec.rb
+++ b/spec/ruby/core/time/ceil_spec.rb
@@ -1,46 +1,44 @@
require_relative '../../spec_helper'
-ruby_version_is "2.7" do
- describe "Time#ceil" do
- before do
- @time = Time.utc(2010, 3, 30, 5, 43, "25.0123456789".to_r)
- end
-
- it "defaults to ceiling to 0 places" do
- @time.ceil.should == Time.utc(2010, 3, 30, 5, 43, 26.to_r)
- end
+describe "Time#ceil" do
+ before do
+ @time = Time.utc(2010, 3, 30, 5, 43, "25.0123456789".to_r)
+ end
- it "ceils to 0 decimal places with an explicit argument" do
- @time.ceil(0).should == Time.utc(2010, 3, 30, 5, 43, 26.to_r)
- end
+ it "defaults to ceiling to 0 places" do
+ @time.ceil.should == Time.utc(2010, 3, 30, 5, 43, 26.to_r)
+ end
- it "ceils to 2 decimal places with an explicit argument" do
- @time.ceil(2).should == Time.utc(2010, 3, 30, 5, 43, "25.02".to_r)
- end
+ it "ceils to 0 decimal places with an explicit argument" do
+ @time.ceil(0).should == Time.utc(2010, 3, 30, 5, 43, 26.to_r)
+ end
- it "ceils to 4 decimal places with an explicit argument" do
- @time.ceil(4).should == Time.utc(2010, 3, 30, 5, 43, "25.0124".to_r)
- end
+ it "ceils to 2 decimal places with an explicit argument" do
+ @time.ceil(2).should == Time.utc(2010, 3, 30, 5, 43, "25.02".to_r)
+ end
- it "ceils to 7 decimal places with an explicit argument" do
- @time.ceil(7).should == Time.utc(2010, 3, 30, 5, 43, "25.0123457".to_r)
- end
+ it "ceils to 4 decimal places with an explicit argument" do
+ @time.ceil(4).should == Time.utc(2010, 3, 30, 5, 43, "25.0124".to_r)
+ end
- it "returns an instance of Time, even if #ceil is called on a subclass" do
- subclass = Class.new(Time)
- instance = subclass.at(0)
- instance.class.should equal subclass
- instance.ceil.should be_an_instance_of(Time)
- end
+ it "ceils to 7 decimal places with an explicit argument" do
+ @time.ceil(7).should == Time.utc(2010, 3, 30, 5, 43, "25.0123457".to_r)
+ end
- it "copies own timezone to the returning value" do
- @time.zone.should == @time.ceil.zone
+ it "returns an instance of Time, even if #ceil is called on a subclass" do
+ subclass = Class.new(Time)
+ instance = subclass.at(0)
+ instance.class.should equal subclass
+ instance.ceil.should be_an_instance_of(Time)
+ end
- time = with_timezone "JST-9" do
- Time.at 0, 1
- end
+ it "copies own timezone to the returning value" do
+ @time.zone.should == @time.ceil.zone
- time.zone.should == time.ceil.zone
+ time = with_timezone "JST-9" do
+ Time.at 0, 1
end
+
+ time.zone.should == time.ceil.zone
end
end
diff --git a/spec/ruby/core/time/deconstruct_keys_spec.rb b/spec/ruby/core/time/deconstruct_keys_spec.rb
new file mode 100644
index 0000000000..ee17e7dbd4
--- /dev/null
+++ b/spec/ruby/core/time/deconstruct_keys_spec.rb
@@ -0,0 +1,45 @@
+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
+ end
+end
diff --git a/spec/ruby/core/time/fixtures/classes.rb b/spec/ruby/core/time/fixtures/classes.rb
index 1a9511b261..21c4e1effb 100644
--- a/spec/ruby/core/time/fixtures/classes.rb
+++ b/spec/ruby/core/time/fixtures/classes.rb
@@ -59,7 +59,6 @@ module TimeSpecs
Zone = Struct.new(:std, :dst, :dst_range)
Zones = {
"Asia/Colombo" => Zone[Z[5*3600+30*60, "MMT"], nil, nil],
- "Europe/Kiev" => Zone[Z[2*3600, "EET"], Z[3*3600, "EEST"], 4..10],
"PST" => Zone[Z[(-9*60*60), "PST"], nil, nil],
}
diff --git a/spec/ruby/core/time/floor_spec.rb b/spec/ruby/core/time/floor_spec.rb
index a19585b787..b0003469c9 100644
--- a/spec/ruby/core/time/floor_spec.rb
+++ b/spec/ruby/core/time/floor_spec.rb
@@ -1,38 +1,36 @@
require_relative '../../spec_helper'
-ruby_version_is "2.7" do
- describe "Time#floor" do
- before do
- @time = Time.utc(2010, 3, 30, 5, 43, "25.123456789".to_r)
- end
-
- it "defaults to flooring to 0 places" do
- @time.floor.should == Time.utc(2010, 3, 30, 5, 43, 25.to_r)
- end
+describe "Time#floor" do
+ before do
+ @time = Time.utc(2010, 3, 30, 5, 43, "25.123456789".to_r)
+ end
- it "floors to 0 decimal places with an explicit argument" do
- @time.floor(0).should == Time.utc(2010, 3, 30, 5, 43, 25.to_r)
- end
+ it "defaults to flooring to 0 places" do
+ @time.floor.should == Time.utc(2010, 3, 30, 5, 43, 25.to_r)
+ end
- it "floors to 7 decimal places with an explicit argument" do
- @time.floor(7).should == Time.utc(2010, 3, 30, 5, 43, "25.1234567".to_r)
- end
+ it "floors to 0 decimal places with an explicit argument" do
+ @time.floor(0).should == Time.utc(2010, 3, 30, 5, 43, 25.to_r)
+ end
- it "returns an instance of Time, even if #floor is called on a subclass" do
- subclass = Class.new(Time)
- instance = subclass.at(0)
- instance.class.should equal subclass
- instance.floor.should be_an_instance_of(Time)
- end
+ it "floors to 7 decimal places with an explicit argument" do
+ @time.floor(7).should == Time.utc(2010, 3, 30, 5, 43, "25.1234567".to_r)
+ end
- it "copies own timezone to the returning value" do
- @time.zone.should == @time.floor.zone
+ it "returns an instance of Time, even if #floor is called on a subclass" do
+ subclass = Class.new(Time)
+ instance = subclass.at(0)
+ instance.class.should equal subclass
+ instance.floor.should be_an_instance_of(Time)
+ end
- time = with_timezone "JST-9" do
- Time.at 0, 1
- end
+ it "copies own timezone to the returning value" do
+ @time.zone.should == @time.floor.zone
- time.zone.should == time.floor.zone
+ time = with_timezone "JST-9" do
+ Time.at 0, 1
end
+
+ time.zone.should == time.floor.zone
end
end
diff --git a/spec/ruby/core/time/inspect_spec.rb b/spec/ruby/core/time/inspect_spec.rb
index 6f1b2e3ef1..c3a4519a24 100644
--- a/spec/ruby/core/time/inspect_spec.rb
+++ b/spec/ruby/core/time/inspect_spec.rb
@@ -4,32 +4,30 @@ require_relative 'shared/inspect'
describe "Time#inspect" do
it_behaves_like :inspect, :inspect
- ruby_version_is "2.7" do
- it "preserves microseconds" do
- t = Time.utc(2007, 11, 1, 15, 25, 0, 123456)
- t.inspect.should == "2007-11-01 15:25:00.123456 UTC"
- end
+ it "preserves microseconds" do
+ t = Time.utc(2007, 11, 1, 15, 25, 0, 123456)
+ t.inspect.should == "2007-11-01 15:25:00.123456 UTC"
+ end
- it "omits trailing zeros from microseconds" do
- t = Time.utc(2007, 11, 1, 15, 25, 0, 100000)
- t.inspect.should == "2007-11-01 15:25:00.1 UTC"
- end
+ it "omits trailing zeros from microseconds" do
+ t = Time.utc(2007, 11, 1, 15, 25, 0, 100000)
+ t.inspect.should == "2007-11-01 15:25:00.1 UTC"
+ end
- it "uses the correct time zone without microseconds" do
- t = Time.utc(2000, 1, 1)
- t = t.localtime(9*3600)
- t.inspect.should == "2000-01-01 09:00:00 +0900"
- end
+ it "uses the correct time zone without microseconds" do
+ t = Time.utc(2000, 1, 1)
+ t = t.localtime(9*3600)
+ t.inspect.should == "2000-01-01 09:00:00 +0900"
+ end
- it "uses the correct time zone with microseconds" do
- t = Time.utc(2000, 1, 1, 0, 0, 0, 123456)
- t = t.localtime(9*3600)
- t.inspect.should == "2000-01-01 09:00:00.123456 +0900"
- end
+ it "uses the correct time zone with microseconds" do
+ t = Time.utc(2000, 1, 1, 0, 0, 0, 123456)
+ t = t.localtime(9*3600)
+ t.inspect.should == "2000-01-01 09:00:00.123456 +0900"
+ end
- it "preserves nanoseconds" do
- t = Time.utc(2007, 11, 1, 15, 25, 0, 123456.789r)
- t.inspect.should == "2007-11-01 15:25:00.123456789 UTC"
- end
+ it "preserves nanoseconds" do
+ t = Time.utc(2007, 11, 1, 15, 25, 0, 123456.789r)
+ t.inspect.should == "2007-11-01 15:25:00.123456789 UTC"
end
end
diff --git a/spec/ruby/core/time/localtime_spec.rb b/spec/ruby/core/time/localtime_spec.rb
index 2975e112d0..609b6532a1 100644
--- a/spec/ruby/core/time/localtime_spec.rb
+++ b/spec/ruby/core/time/localtime_spec.rb
@@ -29,10 +29,10 @@ describe "Time#localtime" do
time.localtime.should equal(time)
end
- it "raises a RuntimeError if the time has a different time zone" do
+ it "raises a FrozenError if the time has a different time zone" do
time = Time.gm(2007, 1, 9, 12, 0, 0)
time.freeze
- -> { time.localtime }.should raise_error(RuntimeError)
+ -> { time.localtime }.should raise_error(FrozenError)
end
end
@@ -79,6 +79,18 @@ describe "Time#localtime" do
t.utc_offset.should == -3600
end
+ it "returns a Time with a UTC offset specified as UTC" do
+ t = Time.new(2007, 1, 9, 12, 0, 0, 3600)
+ t.localtime("UTC")
+ t.utc_offset.should == 0
+ end
+
+ it "returns a Time with a UTC offset specified as A-Z military zone" do
+ t = Time.new(2007, 1, 9, 12, 0, 0, 3600)
+ t.localtime("B")
+ t.utc_offset.should == 3600 * 2
+ end
+
platform_is_not :windows do
it "changes the timezone according to the set one" do
t = Time.new(2005, 2, 27, 22, 50, 0, -3600)
diff --git a/spec/ruby/core/time/new_spec.rb b/spec/ruby/core/time/new_spec.rb
index 09b4d03a44..d686355270 100644
--- a/spec/ruby/core/time/new_spec.rb
+++ b/spec/ruby/core/time/new_spec.rb
@@ -58,6 +58,32 @@ describe "Time.new with a utc_offset argument" do
Time.new(2000, 1, 1, 0, 0, 0, "-04:10:43").utc_offset.should == -15043
end
+ ruby_bug '#13669', ''...'3.1' do
+ it "returns a Time with a UTC offset specified as +HH" do
+ Time.new(2000, 1, 1, 0, 0, 0, "+05").utc_offset.should == 3600 * 5
+ end
+
+ it "returns a Time with a UTC offset specified as -HH" do
+ Time.new(2000, 1, 1, 0, 0, 0, "-05").utc_offset.should == -3600 * 5
+ end
+
+ it "returns a Time with a UTC offset specified as +HHMM" do
+ Time.new(2000, 1, 1, 0, 0, 0, "+0530").utc_offset.should == 19800
+ end
+
+ it "returns a Time with a UTC offset specified as -HHMM" do
+ Time.new(2000, 1, 1, 0, 0, 0, "-0530").utc_offset.should == -19800
+ end
+
+ it "returns a Time with a UTC offset specified as +HHMMSS" do
+ Time.new(2000, 1, 1, 0, 0, 0, "+053037").utc_offset.should == 19837
+ end
+
+ it "returns a Time with a UTC offset specified as -HHMMSS" do
+ Time.new(2000, 1, 1, 0, 0, 0, "-053037").utc_offset.should == -19837
+ end
+ end
+
describe "with an argument that responds to #to_str" do
it "coerces using #to_str" do
o = mock('string')
@@ -66,6 +92,57 @@ describe "Time.new with a utc_offset argument" do
end
end
+ it "returns a Time with UTC offset specified as UTC" do
+ Time.new(2000, 1, 1, 0, 0, 0, "UTC").utc_offset.should == 0
+ end
+
+ it "returns a Time with UTC offset specified as a single letter military timezone" do
+ [
+ ["A", 3600],
+ ["B", 3600 * 2],
+ ["C", 3600 * 3],
+ ["D", 3600 * 4],
+ ["E", 3600 * 5],
+ ["F", 3600 * 6],
+ ["G", 3600 * 7],
+ ["H", 3600 * 8],
+ ["I", 3600 * 9],
+ # J is not supported
+ ["K", 3600 * 10],
+ ["L", 3600 * 11],
+ ["M", 3600 * 12],
+ ["N", 3600 * -1],
+ ["O", 3600 * -2],
+ ["P", 3600 * -3],
+ ["Q", 3600 * -4],
+ ["R", 3600 * -5],
+ ["S", 3600 * -6],
+ ["T", 3600 * -7],
+ ["U", 3600 * -8],
+ ["V", 3600 * -9],
+ ["W", 3600 * -10],
+ ["X", 3600 * -11],
+ ["Y", 3600 * -12],
+ ["Z", 0]
+ ].each do |letter, offset|
+ Time.new(2000, 1, 1, 0, 0, 0, letter).utc_offset.should == offset
+ end
+ end
+
+ ruby_version_is ""..."3.1" do
+ it "raises ArgumentError if the string argument is J" do
+ message = '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset'
+ -> { Time.new(2000, 1, 1, 0, 0, 0, "J") }.should raise_error(ArgumentError, message)
+ end
+ end
+
+ ruby_version_is "3.1" do
+ it "raises ArgumentError if the string argument is J" do
+ message = '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: J'
+ -> { Time.new(2000, 1, 1, 0, 0, 0, "J") }.should raise_error(ArgumentError, message)
+ end
+ end
+
it "returns a local Time if the argument is nil" do
with_timezone("PST", -8) do
t = Time.new(2000, 1, 1, 0, 0, 0, nil)
@@ -93,7 +170,12 @@ describe "Time.new with a utc_offset argument" do
end
it "raises ArgumentError if the String argument is not in an ASCII-compatible encoding" do
- -> { Time.new(2000, 1, 1, 0, 0, 0, "-04:10".encode("UTF-16LE")) }.should raise_error(ArgumentError)
+ # Don't check exception message - it was changed in previous CRuby versions:
+ # - "string contains null byte"
+ # - '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset'
+ -> {
+ Time.new(2000, 1, 1, 0, 0, 0, "-04:10".encode("UTF-16LE"))
+ }.should raise_error(ArgumentError)
end
it "raises ArgumentError if the argument represents a value less than or equal to -86400 seconds" do
@@ -106,19 +188,9 @@ describe "Time.new with a utc_offset argument" do
-> { Time.new(2000, 1, 1, 0, 0, 0, 86400) }.should raise_error(ArgumentError)
end
- it "raises ArgumentError if the seconds argument is negative" do
- -> { Time.new(2000, 1, 1, 0, 0, -1) }.should raise_error(ArgumentError)
- end
-
it "raises ArgumentError if the utc_offset argument is greater than or equal to 10e9" do
-> { Time.new(2000, 1, 1, 0, 0, 0, 1000000000) }.should raise_error(ArgumentError)
end
-
- it "raises ArgumentError if the month is greater than 12" do
- # For some reason MRI uses a different message for month in 13-15 and month>=16
- -> { Time.new(2000, 13, 1, 0, 0, 0, "+01:00") }.should raise_error(ArgumentError, /(mon|argument) out of range/)
- -> { Time.new(2000, 16, 1, 0, 0, 0, "+01:00") }.should raise_error(ArgumentError, "argument out of range")
- end
end
describe "Time.new with a timezone argument" do
@@ -128,10 +200,8 @@ describe "Time.new with a timezone argument" do
time.zone.should == zone
time.utc_offset.should == 5*3600+30*60
- ruby_version_is "3.0" do
- time.wday.should == 6
- time.yday.should == 1
- end
+ time.wday.should == 6
+ time.yday.should == 1
end
it "accepts timezone argument that must have #local_to_utc and #utc_to_local methods" do
@@ -288,7 +358,7 @@ describe "Time.new with a timezone argument" do
-> {
Marshal.dump(time)
- }.should raise_error(NoMethodError, /undefined method `name' for/)
+ }.should raise_error(NoMethodError, /undefined method [`']name' for/)
end
end
@@ -332,4 +402,245 @@ describe "Time.new with a timezone argument" do
end
end
end
+
+ ruby_version_is '3.1' do # https://bugs.ruby-lang.org/issues/17485
+ describe ":in keyword argument" do
+ it "could be UTC offset as a String in '+HH:MM or '-HH:MM' format" do
+ time = Time.new(2000, 1, 1, 12, 0, 0, in: "+05:00")
+
+ time.utc_offset.should == 5*60*60
+ time.zone.should == nil
+
+ time = Time.new(2000, 1, 1, 12, 0, 0, in: "-09:00")
+
+ time.utc_offset.should == -9*60*60
+ time.zone.should == nil
+ end
+
+ it "could be UTC offset as a number of seconds" do
+ time = Time.new(2000, 1, 1, 12, 0, 0, in: 5*60*60)
+
+ time.utc_offset.should == 5*60*60
+ time.zone.should == nil
+
+ time = Time.new(2000, 1, 1, 12, 0, 0, in: -9*60*60)
+
+ time.utc_offset.should == -9*60*60
+ time.zone.should == nil
+ end
+
+ it "returns a Time with UTC offset specified as a single letter military timezone" do
+ Time.new(2000, 1, 1, 0, 0, 0, in: "W").utc_offset.should == 3600 * -10
+ end
+
+ it "could be a timezone object" do
+ zone = TimeSpecs::TimezoneWithName.new(name: "Asia/Colombo")
+ time = Time.new(2000, 1, 1, 12, 0, 0, in: zone)
+
+ time.utc_offset.should == 5*3600+30*60
+ time.zone.should == zone
+
+ zone = TimeSpecs::TimezoneWithName.new(name: "PST")
+ time = Time.new(2000, 1, 1, 12, 0, 0, in: zone)
+
+ time.utc_offset.should == -9*60*60
+ time.zone.should == zone
+ end
+
+ it "allows omitting minor arguments" do
+ Time.new(2000, 1, 1, 12, 1, 1, in: "+05:00").should == Time.new(2000, 1, 1, 12, 1, 1, "+05:00")
+ Time.new(2000, 1, 1, 12, 1, in: "+05:00").should == Time.new(2000, 1, 1, 12, 1, 0, "+05:00")
+ Time.new(2000, 1, 1, 12, in: "+05:00").should == Time.new(2000, 1, 1, 12, 0, 0, "+05:00")
+ Time.new(2000, 1, 1, in: "+05:00").should == Time.new(2000, 1, 1, 0, 0, 0, "+05:00")
+ Time.new(2000, 1, in: "+05:00").should == Time.new(2000, 1, 1, 0, 0, 0, "+05:00")
+ Time.new(2000, in: "+05:00").should == Time.new(2000, 1, 1, 0, 0, 0, "+05:00")
+ Time.new(in: "+05:00").should be_close(Time.now.getlocal("+05:00"), TIME_TOLERANCE)
+ end
+
+ it "converts to a provided timezone if all the positional arguments are omitted" do
+ Time.new(in: "+05:00").utc_offset.should == 5*3600
+ end
+
+ it "raises ArgumentError if format is invalid" do
+ -> { Time.new(2000, 1, 1, 12, 0, 0, in: "+09:99") }.should raise_error(ArgumentError)
+ -> { Time.new(2000, 1, 1, 12, 0, 0, in: "ABC") }.should raise_error(ArgumentError)
+ end
+
+ it "raises ArgumentError if two offset arguments are given" do
+ -> {
+ Time.new(2000, 1, 1, 12, 0, 0, "+05:00", in: "+05:00")
+ }.should raise_error(ArgumentError, "timezone argument given as positional and keyword arguments")
+ end
+ end
+ end
+
+ ruby_version_is "3.2" do
+ describe "Time.new with a String argument" do
+ it "parses an ISO-8601 like format" do
+ t = Time.utc(2020, 12, 24, 15, 56, 17)
+
+ Time.new("2020-12-24T15:56:17Z").should == t
+ Time.new("2020-12-25 00:56:17 +09:00").should == t
+ Time.new("2020-12-25 00:57:47 +09:01:30").should == t
+ Time.new("2020-12-25 00:56:17 +0900").should == t
+ Time.new("2020-12-25 00:57:47 +090130").should == t
+ Time.new("2020-12-25T00:56:17+09:00").should == t
+ end
+
+ it "accepts precision keyword argument and truncates specified digits of sub-second part" do
+ Time.new("2021-12-25 00:00:00.123456789876 +09:00").subsec.should == 0.123456789r
+ Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: nil).subsec.should == 0.123456789876r
+ Time.new("2021-12-25 00:00:00 +09:00", precision: 0).subsec.should == 0
+ Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: -1).subsec.should == 0.123456789876r
+ end
+
+ it "returns Time in local timezone if not provided in the String argument" do
+ Time.new("2021-12-25 00:00:00").zone.should == Time.new(2021, 12, 25).zone
+ Time.new("2021-12-25 00:00:00").utc_offset.should == Time.new(2021, 12, 25).utc_offset
+ end
+
+ it "returns Time in timezone specified in the String argument" do
+ Time.new("2021-12-25 00:00:00 +05:00").to_s.should == "2021-12-25 00:00:00 +0500"
+ end
+
+ it "returns Time in timezone specified in the String argument even if the in keyword argument provided" do
+ Time.new("2021-12-25 00:00:00 +09:00", in: "-01:00").to_s.should == "2021-12-25 00:00:00 +0900"
+ end
+
+ it "returns Time in timezone specified with in keyword argument if timezone isn't provided in the String argument" do
+ Time.new("2021-12-25 00:00:00", in: "-01:00").to_s.should == "2021-12-25 00:00:00 -0100"
+ end
+
+ it "converts precision keyword argument into Integer if is not nil" do
+ obj = Object.new
+ def obj.to_int; 3; end
+
+ Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: 1.2).subsec.should == 0.1r
+ Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: obj).subsec.should == 0.123r
+ Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: 3r).subsec.should == 0.123r
+ end
+
+ ruby_version_is ""..."3.3" do
+ it "raise TypeError is can't convert precision keyword argument into Integer" do
+ -> {
+ Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: "")
+ }.should raise_error(TypeError, "no implicit conversion from string")
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it "raise TypeError is can't convert precision keyword argument into Integer" do
+ -> {
+ Time.new("2021-12-25 00:00:00.123456789876 +09:00", precision: "")
+ }.should raise_error(TypeError, "no implicit conversion of String into Integer")
+ end
+ end
+
+ it "raises ArgumentError if part of time string is missing" do
+ -> {
+ Time.new("2020-12-25 00:56 +09:00")
+ }.should raise_error(ArgumentError, "missing sec part: 00:56 ")
+
+ -> {
+ Time.new("2020-12-25 00 +09:00")
+ }.should raise_error(ArgumentError, "missing min part: 00 ")
+ end
+
+ it "raises ArgumentError if subsecond is missing after dot" do
+ -> {
+ Time.new("2020-12-25 00:56:17. +0900")
+ }.should raise_error(ArgumentError, "subsecond expected after dot: 00:56:17. ")
+ end
+
+ it "raises ArgumentError if String argument is not in the supported format" do
+ -> {
+ Time.new("021-12-25 00:00:00.123456 +09:00")
+ }.should raise_error(ArgumentError, "year must be 4 or more digits: 021")
+
+ -> {
+ Time.new("2020-012-25 00:56:17 +0900")
+ }.should raise_error(ArgumentError, /\Atwo digits mon is expected after [`']-': -012-25 00:\z/)
+
+ -> {
+ Time.new("2020-2-25 00:56:17 +0900")
+ }.should raise_error(ArgumentError, /\Atwo digits mon is expected after [`']-': -2-25 00:56\z/)
+
+ -> {
+ Time.new("2020-12-215 00:56:17 +0900")
+ }.should raise_error(ArgumentError, /\Atwo digits mday is expected after [`']-': -215 00:56:\z/)
+
+ -> {
+ Time.new("2020-12-25 000:56:17 +0900")
+ }.should raise_error(ArgumentError, "two digits hour is expected: 000:56:17 ")
+
+ -> {
+ Time.new("2020-12-25 0:56:17 +0900")
+ }.should raise_error(ArgumentError, "two digits hour is expected: 0:56:17 +0")
+
+ -> {
+ Time.new("2020-12-25 00:516:17 +0900")
+ }.should raise_error(ArgumentError, /\Atwo digits min is expected after [`']:': :516:17 \+09\z/)
+
+ -> {
+ Time.new("2020-12-25 00:6:17 +0900")
+ }.should raise_error(ArgumentError, /\Atwo digits min is expected after [`']:': :6:17 \+0900\z/)
+
+ -> {
+ Time.new("2020-12-25 00:56:137 +0900")
+ }.should raise_error(ArgumentError, /\Atwo digits sec is expected after [`']:': :137 \+0900\z/)
+
+ -> {
+ Time.new("2020-12-25 00:56:7 +0900")
+ }.should raise_error(ArgumentError, /\Atwo digits sec is expected after [`']:': :7 \+0900\z/)
+
+ -> {
+ Time.new("2020-12-25 00:56. +0900")
+ }.should raise_error(ArgumentError, "fraction min is not supported: 00:56.")
+
+ -> {
+ Time.new("2020-12-25 00. +0900")
+ }.should raise_error(ArgumentError, "fraction hour is not supported: 00.")
+ end
+
+ it "raises ArgumentError if date/time parts values are not valid" do
+ -> {
+ Time.new("2020-13-25 00:56:17 +09:00")
+ }.should raise_error(ArgumentError, "mon out of range")
+
+ -> {
+ Time.new("2020-12-32 00:56:17 +09:00")
+ }.should raise_error(ArgumentError, "mday out of range")
+
+ -> {
+ Time.new("2020-12-25 25:56:17 +09:00")
+ }.should raise_error(ArgumentError, "hour out of range")
+
+ -> {
+ Time.new("2020-12-25 00:61:17 +09:00")
+ }.should raise_error(ArgumentError, "min out of range")
+
+ -> {
+ Time.new("2020-12-25 00:56:61 +09:00")
+ }.should raise_error(ArgumentError, "sec out of range")
+
+ -> {
+ Time.new("2020-12-25 00:56:17 +23:59:60")
+ }.should raise_error(ArgumentError, "utc_offset out of range")
+
+ -> {
+ Time.new("2020-12-25 00:56:17 +24:00")
+ }.should raise_error(ArgumentError, "utc_offset out of range")
+
+ -> {
+ Time.new("2020-12-25 00:56:17 +23:61")
+ }.should raise_error(ArgumentError, '"+HH:MM", "-HH:MM", "UTC" or "A".."I","K".."Z" expected for utc_offset: +23:61')
+ end
+
+ it "raises ArgumentError if string has not ascii-compatible encoding" do
+ -> {
+ Time.new("2021-11-31 00:00:60 +09:00".encode("utf-32le"))
+ }.should raise_error(ArgumentError, "time string should have ASCII compatible encoding")
+ end
+ end
+ end
end
diff --git a/spec/ruby/core/time/now_spec.rb b/spec/ruby/core/time/now_spec.rb
index 7dc7951996..d47f00723e 100644
--- a/spec/ruby/core/time/now_spec.rb
+++ b/spec/ruby/core/time/now_spec.rb
@@ -3,4 +3,55 @@ require_relative 'shared/now'
describe "Time.now" do
it_behaves_like :time_now, :now
+
+ ruby_version_is '3.1' do # https://bugs.ruby-lang.org/issues/17485
+ describe ":in keyword argument" do
+ it "could be UTC offset as a String in '+HH:MM or '-HH:MM' format" do
+ time = Time.now(in: "+05:00")
+
+ time.utc_offset.should == 5*60*60
+ time.zone.should == nil
+
+ time = Time.now(in: "-09:00")
+
+ time.utc_offset.should == -9*60*60
+ time.zone.should == nil
+ end
+
+ it "could be UTC offset as a number of seconds" do
+ time = Time.now(in: 5*60*60)
+
+ time.utc_offset.should == 5*60*60
+ time.zone.should == nil
+
+ time = Time.now(in: -9*60*60)
+
+ time.utc_offset.should == -9*60*60
+ time.zone.should == nil
+ end
+
+ it "returns a Time with UTC offset specified as a single letter military timezone" do
+ Time.now(in: "W").utc_offset.should == 3600 * -10
+ end
+
+ it "could be a timezone object" do
+ zone = TimeSpecs::TimezoneWithName.new(name: "Asia/Colombo")
+ time = Time.now(in: zone)
+
+ time.utc_offset.should == 5*3600+30*60
+ time.zone.should == zone
+
+ zone = TimeSpecs::TimezoneWithName.new(name: "PST")
+ time = Time.now(in: zone)
+
+ time.utc_offset.should == -9*60*60
+ time.zone.should == zone
+ end
+
+ it "raises ArgumentError if format is invalid" do
+ -> { Time.now(in: "+09:99") }.should raise_error(ArgumentError)
+ -> { Time.now(in: "ABC") }.should raise_error(ArgumentError)
+ end
+ end
+ end
end
diff --git a/spec/ruby/core/time/shared/gmtime.rb b/spec/ruby/core/time/shared/gmtime.rb
index 5ed64c2ab6..bae19da462 100644
--- a/spec/ruby/core/time/shared/gmtime.rb
+++ b/spec/ruby/core/time/shared/gmtime.rb
@@ -22,11 +22,11 @@ describe :time_gmtime, shared: true do
time.send(@method).should equal(time)
end
- it "raises a RuntimeError if the time is not UTC" do
+ it "raises a FrozenError if the time is not UTC" do
with_timezone("CST", -6) do
time = Time.now
time.freeze
- -> { time.send(@method) }.should raise_error(RuntimeError)
+ -> { time.send(@method) }.should raise_error(FrozenError)
end
end
end
diff --git a/spec/ruby/core/time/shared/local.rb b/spec/ruby/core/time/shared/local.rb
index 43f331c4c1..068e314999 100644
--- a/spec/ruby/core/time/shared/local.rb
+++ b/spec/ruby/core/time/shared/local.rb
@@ -7,12 +7,10 @@ describe :time_local, shared: true do
end
platform_is_not :windows do
- describe "timezone changes" do
- it "correctly adjusts the timezone change to 'CEST' on 'Europe/Amsterdam'" do
- with_timezone("Europe/Amsterdam") do
- Time.send(@method, 1940, 5, 16).to_a.should ==
- [0, 40, 1, 16, 5, 1940, 4, 137, true, "CEST"]
- end
+ it "uses the 'CET' timezone with TZ=Europe/Amsterdam in 1970" do
+ with_timezone("Europe/Amsterdam") do
+ Time.send(@method, 1970, 5, 16).to_a.should ==
+ [0, 0, 0, 16, 5, 1970, 6, 136, false, "CET"]
end
end
end
@@ -41,5 +39,4 @@ describe :time_local_10_arg, shared: true do
end
end
end
-
end
diff --git a/spec/ruby/core/time/shared/time_params.rb b/spec/ruby/core/time/shared/time_params.rb
index 63d0dbc120..b6a6c88c8e 100644
--- a/spec/ruby/core/time/shared/time_params.rb
+++ b/spec/ruby/core/time/shared/time_params.rb
@@ -145,9 +145,10 @@ describe :time_params, shared: true do
end
it "raises an ArgumentError for out of range month" do
+ # For some reason MRI uses a different message for month in 13-15 and month>=16
-> {
- Time.send(@method, 2008, 13, 31, 23, 59, 59)
- }.should raise_error(ArgumentError)
+ Time.send(@method, 2008, 16, 31, 23, 59, 59)
+ }.should raise_error(ArgumentError, /(mon|argument) out of range/)
end
it "raises an ArgumentError for out of range day" do
@@ -169,9 +170,13 @@ describe :time_params, shared: true do
end
it "raises an ArgumentError for out of range second" do
+ # For some reason MRI uses different messages for seconds 61-63 and seconds >= 64
-> {
Time.send(@method, 2008, 12, 31, 23, 59, 61)
- }.should raise_error(ArgumentError)
+ }.should raise_error(ArgumentError, /(sec|argument) out of range/)
+ -> {
+ Time.send(@method, 2008, 12, 31, 23, 59, -1)
+ }.should raise_error(ArgumentError, "argument out of range")
end
it "raises ArgumentError when given 9 arguments" do
diff --git a/spec/ruby/core/time/strftime_spec.rb b/spec/ruby/core/time/strftime_spec.rb
index 1bd24b0538..4cb300c916 100644
--- a/spec/ruby/core/time/strftime_spec.rb
+++ b/spec/ruby/core/time/strftime_spec.rb
@@ -49,4 +49,45 @@ describe "Time#strftime" do
time = @new_time_with_offset[2012, 1, 1, 0, 0, 0, Rational(36645, 10)]
time.strftime("%::z").should == "+01:01:05"
end
+
+ ruby_version_is "3.1" do
+ it "supports RFC 3339 UTC for unknown offset local time, -0000, as %-z" do
+ time = Time.gm(2022)
+
+ time.strftime("%z").should == "+0000"
+ time.strftime("%-z").should == "-0000"
+ time.strftime("%-:z").should == "-00:00"
+ time.strftime("%-::z").should == "-00:00:00"
+ end
+
+ it "applies '-' flag to UTC time" do
+ time = Time.utc(2022)
+ time.strftime("%-z").should == "-0000"
+
+ time = Time.gm(2022)
+ time.strftime("%-z").should == "-0000"
+
+ time = Time.new(2022, 1, 1, 0, 0, 0, "Z")
+ time.strftime("%-z").should == "-0000"
+
+ time = Time.new(2022, 1, 1, 0, 0, 0, "-00:00")
+ time.strftime("%-z").should == "-0000"
+
+ time = Time.new(2022, 1, 1, 0, 0, 0, "+03:00").utc
+ time.strftime("%-z").should == "-0000"
+ end
+
+ it "ignores '-' flag for non-UTC time" do
+ time = Time.new(2022, 1, 1, 0, 0, 0, "+03:00")
+ time.strftime("%-z").should == "+0300"
+ end
+
+ it "works correctly with width, _ and 0 flags, and :" do
+ Time.now.utc.strftime("%-_10z").should == " -000"
+ Time.now.utc.strftime("%-10z").should == "-000000000"
+ Time.now.utc.strftime("%-010:z").should == "-000000:00"
+ Time.now.utc.strftime("%-_10:z").should == " -0:00"
+ Time.now.utc.strftime("%-_10::z").should == " -0:00:00"
+ end
+ end
end
diff --git a/spec/ruby/core/time/succ_spec.rb b/spec/ruby/core/time/succ_spec.rb
deleted file mode 100644
index e8249059d1..0000000000
--- a/spec/ruby/core/time/succ_spec.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-ruby_version_is ""..."3.0" do
- require_relative '../../spec_helper'
- require_relative 'fixtures/classes'
-
- describe "Time#succ" do
- it "returns a new time one second later than time" do
- suppress_warning {
- @result = Time.at(100).succ
- }
-
- @result.should == Time.at(101)
- end
-
- it "returns a new instance" do
- time = Time.at(100)
-
- suppress_warning {
- @result = time.succ
- }
-
- @result.should_not equal time
- end
-
- it "is obsolete" do
- -> {
- Time.at(100).succ
- }.should complain(/Time#succ is obsolete/)
- end
-
- context "zone is a timezone object" do
- it "preserves time zone" do
- zone = TimeSpecs::Timezone.new(offset: (5*3600+30*60))
- time = Time.new(2012, 1, 1, 12, 0, 0, zone) - 1
-
- time.zone.should == zone
- end
- end
- end
-end
diff --git a/spec/ruby/core/time/utc_spec.rb b/spec/ruby/core/time/utc_spec.rb
index 74c17a93d1..566509fd33 100644
--- a/spec/ruby/core/time/utc_spec.rb
+++ b/spec/ruby/core/time/utc_spec.rb
@@ -4,8 +4,55 @@ require_relative 'shared/gmtime'
require_relative 'shared/time_params'
describe "Time#utc?" do
- it "returns true if time represents a time in UTC (GMT)" do
- Time.now.should_not.utc?
+ it "returns true only if time represents a time in UTC (GMT)" do
+ Time.now.utc?.should == false
+ Time.now.utc.utc?.should == true
+ end
+
+ it "treats time as UTC what was created in different ways" do
+ Time.now.utc.utc?.should == true
+ Time.now.gmtime.utc?.should == true
+ Time.now.getgm.utc?.should == true
+ Time.now.getutc.utc?.should == true
+ Time.utc(2022).utc?.should == true
+ end
+
+ it "does treat time with 'UTC' offset as UTC" do
+ Time.new(2022, 1, 1, 0, 0, 0, "UTC").utc?.should == true
+ Time.now.localtime("UTC").utc?.should == true
+ Time.at(Time.now, in: 'UTC').utc?.should == true
+
+ ruby_version_is "3.1" do
+ Time.new(2022, 1, 1, 0, 0, 0, in: "UTC").utc?.should == true
+ Time.now(in: "UTC").utc?.should == true
+ end
+ end
+
+ it "does treat time with Z offset as UTC" do
+ Time.new(2022, 1, 1, 0, 0, 0, "Z").utc?.should == true
+ Time.now.localtime("Z").utc?.should == true
+ Time.at(Time.now, in: 'Z').utc?.should == true
+
+ ruby_version_is "3.1" do
+ Time.new(2022, 1, 1, 0, 0, 0, in: "Z").utc?.should == true
+ Time.now(in: "Z").utc?.should == true
+ end
+ end
+
+ ruby_version_is "3.1" do
+ it "does treat time with -00:00 offset as UTC" do
+ Time.new(2022, 1, 1, 0, 0, 0, "-00:00").utc?.should == true
+ Time.now.localtime("-00:00").utc?.should == true
+ Time.at(Time.now, in: '-00:00').utc?.should == true
+ end
+ end
+
+ it "does not treat time with +00:00 offset as UTC" do
+ Time.new(2022, 1, 1, 0, 0, 0, "+00:00").utc?.should == false
+ end
+
+ it "does not treat time with 0 offset as UTC" do
+ Time.new(2022, 1, 1, 0, 0, 0, 0).utc?.should == false
end
end
diff --git a/spec/ruby/core/time/zone_spec.rb b/spec/ruby/core/time/zone_spec.rb
index 907ccf9f4b..63c92602d1 100644
--- a/spec/ruby/core/time/zone_spec.rb
+++ b/spec/ruby/core/time/zone_spec.rb
@@ -52,14 +52,39 @@ describe "Time#zone" do
end
it "doesn't raise errors for a Time with a fixed offset" do
- -> {
- Time.new(2001, 1, 1, 0, 0, 0, "+05:00").zone
- }.should_not raise_error
+ Time.new(2001, 1, 1, 0, 0, 0, "+05:00").zone.should == nil
end
end
it "returns UTC when called on a UTC time" do
Time.now.utc.zone.should == "UTC"
+ Time.now.gmtime.zone.should == "UTC"
+ Time.now.getgm.zone.should == "UTC"
+ Time.now.getutc.zone.should == "UTC"
+ Time.utc(2022).zone.should == "UTC"
+ Time.new(2022, 1, 1, 0, 0, 0, "UTC").zone.should == "UTC"
+ Time.new(2022, 1, 1, 0, 0, 0, "Z").zone.should == "UTC"
+ Time.now.localtime("UTC").zone.should == "UTC"
+ Time.now.localtime("Z").zone.should == "UTC"
+ Time.at(Time.now, in: 'UTC').zone.should == "UTC"
+ Time.at(Time.now, in: 'Z').zone.should == "UTC"
+
+ ruby_version_is "3.1" do
+ Time.new(2022, 1, 1, 0, 0, 0, "-00:00").zone.should == "UTC"
+ Time.now.localtime("-00:00").zone.should == "UTC"
+ Time.at(Time.now, in: '-00:00').zone.should == "UTC"
+ end
+
+ ruby_version_is "3.1" do
+ Time.new(2022, 1, 1, 0, 0, 0, in: "UTC").zone.should == "UTC"
+ Time.new(2022, 1, 1, 0, 0, 0, in: "Z").zone.should == "UTC"
+
+ Time.now(in: 'UTC').zone.should == "UTC"
+ Time.now(in: 'Z').zone.should == "UTC"
+
+ Time.at(Time.now, in: 'UTC').zone.should == "UTC"
+ Time.at(Time.now, in: 'Z').zone.should == "UTC"
+ end
end
platform_is_not :aix, :windows do
diff --git a/spec/ruby/core/tracepoint/allow_reentry_spec.rb b/spec/ruby/core/tracepoint/allow_reentry_spec.rb
new file mode 100644
index 0000000000..6bff1bed76
--- /dev/null
+++ b/spec/ruby/core/tracepoint/allow_reentry_spec.rb
@@ -0,0 +1,32 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+
+ruby_version_is "3.1" do
+ describe 'TracePoint.allow_reentry' do
+ it 'allows the reentrance in a given block' do
+ event_lines = []
+ l1 = l2 = l3 = l4 = nil
+ TracePoint.new(:line) do |tp|
+ next unless TracePointSpec.target_thread?
+
+ event_lines << tp.lineno
+ next if (__LINE__ + 2 .. __LINE__ + 4).cover?(tp.lineno)
+ TracePoint.allow_reentry do
+ a = 1; l3 = __LINE__
+ b = 2; l4 = __LINE__
+ end
+ end.enable do
+ c = 3; l1 = __LINE__
+ d = 4; l2 = __LINE__
+ end
+
+ event_lines.should == [l1, l3, l4, l2, l3, l4]
+ end
+
+ it 'raises RuntimeError when not called inside a TracePoint' do
+ -> {
+ TracePoint.allow_reentry{}
+ }.should raise_error(RuntimeError)
+ end
+ end
+end
diff --git a/spec/ruby/core/tracepoint/enable_spec.rb b/spec/ruby/core/tracepoint/enable_spec.rb
index ab392c7583..6cc8bb3897 100644
--- a/spec/ruby/core/tracepoint/enable_spec.rb
+++ b/spec/ruby/core/tracepoint/enable_spec.rb
@@ -57,25 +57,50 @@ describe 'TracePoint#enable' do
end.enable { event_name.should equal(:line) }
end
- it 'enables the trace object for any thread' do
- threads = []
- trace = TracePoint.new(:line) do |tp|
- # Runs on purpose on any Thread
- threads << Thread.current
- end
+ ruby_version_is '3.2' do
+ it 'enables the trace object only for the current thread' do
+ threads = []
+ trace = TracePoint.new(:line) do |tp|
+ # Runs on purpose on any Thread
+ threads << Thread.current
+ end
- thread = nil
- trace.enable do
- line_event = true
- thread = Thread.new do
- event_in_other_thread = true
+ thread = nil
+ trace.enable do
+ line_event = true
+ thread = Thread.new do
+ event_in_other_thread = true
+ end
+ thread.join
end
- thread.join
+
+ threads = threads.uniq
+ threads.should.include?(Thread.current)
+ threads.should_not.include?(thread)
end
+ end
+
+ ruby_version_is ''...'3.2' do
+ it 'enables the trace object for any thread' do
+ threads = []
+ trace = TracePoint.new(:line) do |tp|
+ # Runs on purpose on any Thread
+ threads << Thread.current
+ end
+
+ thread = nil
+ trace.enable do
+ line_event = true
+ thread = Thread.new do
+ event_in_other_thread = true
+ end
+ thread.join
+ end
- threads = threads.uniq
- threads.should.include?(Thread.current)
- threads.should.include?(thread)
+ threads = threads.uniq
+ threads.should.include?(Thread.current)
+ threads.should.include?(thread)
+ end
end
it 'can accept arguments within a block but it should not yield arguments' do
@@ -124,13 +149,7 @@ describe 'TracePoint#enable' do
describe "when nested" do
before do
- ruby_version_is ""..."3.0" do
- @path_prefix = '@'
- end
-
- ruby_version_is "3.0" do
- @path_prefix = ' '
- end
+ @path_prefix = ' '
end
it "enables both TracePoints but only calls the respective callbacks" do
diff --git a/spec/ruby/core/tracepoint/inspect_spec.rb b/spec/ruby/core/tracepoint/inspect_spec.rb
index b9d7f35c32..cc6bf0f842 100644
--- a/spec/ruby/core/tracepoint/inspect_spec.rb
+++ b/spec/ruby/core/tracepoint/inspect_spec.rb
@@ -3,19 +3,22 @@ require_relative 'fixtures/classes'
describe 'TracePoint#inspect' do
before do
- ruby_version_is ""..."3.0" do
- @path_prefix = '@'
- end
-
- ruby_version_is "3.0" do
- @path_prefix = ' '
- end
+ @path_prefix = ' '
end
it 'returns a string containing a human-readable TracePoint status' do
TracePoint.new(:line) {}.inspect.should == '#<TracePoint:disabled>'
end
+ it "shows only whether it's enabled when outside the TracePoint handler" do
+ trace = TracePoint.new(:line) {}
+ trace.enable
+
+ trace.inspect.should == '#<TracePoint:enabled>'
+
+ trace.disable
+ end
+
it 'returns a String showing the event, path and line' do
inspect = nil
line = nil
@@ -41,7 +44,7 @@ describe 'TracePoint#inspect' do
trace_point_spec_test_call
end
- inspect.should == "#<TracePoint:call `trace_point_spec_test_call'#{@path_prefix}#{__FILE__}:#{line}>"
+ inspect.should =~ /\A#<TracePoint:call [`']trace_point_spec_test_call'#{@path_prefix}#{__FILE__}:#{line}>\z/
end
it 'returns a String showing the event, method, path and line for a :return event' do
@@ -59,7 +62,7 @@ describe 'TracePoint#inspect' do
trace_point_spec_test_return
end
- inspect.should == "#<TracePoint:return `trace_point_spec_test_return'#{@path_prefix}#{__FILE__}:#{line}>"
+ inspect.should =~ /\A#<TracePoint:return [`']trace_point_spec_test_return'#{@path_prefix}#{__FILE__}:#{line}>\z/
end
it 'returns a String showing the event, method, path and line for a :c_call event' do
@@ -73,7 +76,7 @@ describe 'TracePoint#inspect' do
[0, 1].max
end
- inspect.should == "#<TracePoint:c_call `max'#{@path_prefix}#{__FILE__}:#{line}>"
+ inspect.should =~ /\A#<TracePoint:c_call [`']max'#{@path_prefix}#{__FILE__}:#{line}>\z/
end
it 'returns a String showing the event, path and line for a :class event' do
@@ -98,7 +101,7 @@ describe 'TracePoint#inspect' do
TracePoint.new(:thread_begin) { |tp|
next unless Thread.current == thread
inspect ||= tp.inspect
- }.enable do
+ }.enable(target_thread: nil) do
thread = Thread.new {}
thread_inspection = thread.inspect
thread.join
@@ -114,7 +117,7 @@ describe 'TracePoint#inspect' do
TracePoint.new(:thread_end) { |tp|
next unless Thread.current == thread
inspect ||= tp.inspect
- }.enable do
+ }.enable(target_thread: nil) do
thread = Thread.new {}
thread_inspection = thread.inspect
thread.join
diff --git a/spec/ruby/core/tracepoint/path_spec.rb b/spec/ruby/core/tracepoint/path_spec.rb
index 5b6c6d4cfc..dc2ca840b8 100644
--- a/spec/ruby/core/tracepoint/path_spec.rb
+++ b/spec/ruby/core/tracepoint/path_spec.rb
@@ -13,14 +13,29 @@ describe 'TracePoint#path' do
path.should == "#{__FILE__}"
end
- it 'equals (eval) inside an eval for :end event' do
- path = nil
- TracePoint.new(:end) { |tp|
- next unless TracePointSpec.target_thread?
- path = tp.path
- }.enable do
- eval("module TracePointSpec; end")
+ ruby_version_is ""..."3.3" do
+ it 'equals (eval) inside an eval for :end event' do
+ path = nil
+ TracePoint.new(:end) { |tp|
+ next unless TracePointSpec.target_thread?
+ path = tp.path
+ }.enable do
+ eval("module TracePointSpec; end")
+ end
+ path.should == '(eval)'
+ end
+ end
+
+ ruby_version_is "3.3" do
+ it 'equals "(eval at __FILE__:__LINE__)" inside an eval for :end event' do
+ path = nil
+ TracePoint.new(:end) { |tp|
+ next unless TracePointSpec.target_thread?
+ path = tp.path
+ }.enable do
+ eval("module TracePointSpec; end")
+ end
+ path.should == "(eval at #{__FILE__}:#{__LINE__ - 2})"
end
- path.should == '(eval)'
end
end
diff --git a/spec/ruby/core/true/singleton_method_spec.rb b/spec/ruby/core/true/singleton_method_spec.rb
new file mode 100644
index 0000000000..c06793850f
--- /dev/null
+++ b/spec/ruby/core/true/singleton_method_spec.rb
@@ -0,0 +1,15 @@
+require_relative '../../spec_helper'
+
+describe "TrueClass#singleton_method" do
+ ruby_version_is '3.3' do
+ it "raises regardless of whether TrueClass defines the method" do
+ -> { true.singleton_method(:foo) }.should raise_error(NameError)
+ begin
+ def (true).foo; end
+ -> { true.singleton_method(:foo) }.should raise_error(NameError)
+ ensure
+ TrueClass.send(:remove_method, :foo)
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/true/to_s_spec.rb b/spec/ruby/core/true/to_s_spec.rb
index f26cd138e2..fa1b53a580 100644
--- a/spec/ruby/core/true/to_s_spec.rb
+++ b/spec/ruby/core/true/to_s_spec.rb
@@ -5,13 +5,11 @@ describe "TrueClass#to_s" do
true.to_s.should == "true"
end
- ruby_version_is "2.7" do
- it "returns a frozen string" do
- true.to_s.should.frozen?
- end
+ it "returns a frozen string" do
+ true.to_s.should.frozen?
+ end
- it "always returns the same string" do
- true.to_s.should equal(true.to_s)
- end
+ it "always returns the same string" do
+ true.to_s.should equal(true.to_s)
end
end
diff --git a/spec/ruby/core/unboundmethod/bind_call_spec.rb b/spec/ruby/core/unboundmethod/bind_call_spec.rb
index c5d392156c..80b2095d86 100644
--- a/spec/ruby/core/unboundmethod/bind_call_spec.rb
+++ b/spec/ruby/core/unboundmethod/bind_call_spec.rb
@@ -1,52 +1,58 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-ruby_version_is '2.7' do
- describe "UnboundMethod#bind_call" do
- before :each do
- @normal_um = UnboundMethodSpecs::Methods.new.method(:foo).unbind
- @parent_um = UnboundMethodSpecs::Parent.new.method(:foo).unbind
- @child1_um = UnboundMethodSpecs::Child1.new.method(:foo).unbind
- @child2_um = UnboundMethodSpecs::Child2.new.method(:foo).unbind
- end
+describe "UnboundMethod#bind_call" do
+ before :each do
+ @normal_um = UnboundMethodSpecs::Methods.new.method(:foo).unbind
+ @parent_um = UnboundMethodSpecs::Parent.new.method(:foo).unbind
+ @child1_um = UnboundMethodSpecs::Child1.new.method(:foo).unbind
+ @child2_um = UnboundMethodSpecs::Child2.new.method(:foo).unbind
+ @normal_um_super = UnboundMethodSpecs::Mod.instance_method(:foo_super)
+ @parent_um_super = UnboundMethodSpecs::Parent.new.method(:foo_super).unbind
+ end
- it "raises TypeError if object is not kind_of? the Module the method defined in" do
- -> { @normal_um.bind_call(UnboundMethodSpecs::B.new) }.should raise_error(TypeError)
- end
+ it "raises TypeError if object is not kind_of? the Module the method defined in" do
+ -> { @normal_um.bind_call(UnboundMethodSpecs::B.new) }.should raise_error(TypeError)
+ end
- it "binds and calls the method if object is kind_of the Module the method defined in" do
- @normal_um.bind_call(UnboundMethodSpecs::Methods.new).should == true
- end
+ it "binds and calls the method if object is kind_of the Module the method defined in" do
+ @normal_um.bind_call(UnboundMethodSpecs::Methods.new).should == true
+ end
- it "binds and calls the method on any object when UnboundMethod is unbound from a module" do
- UnboundMethodSpecs::Mod.instance_method(:from_mod).bind_call(Object.new).should == nil
- end
+ it "binds and calls the method on any object when UnboundMethod is unbound from a module" do
+ UnboundMethodSpecs::Mod.instance_method(:from_mod).bind_call(Object.new).should == nil
+ end
- it "binds and calls the method for any object kind_of? the Module the method is defined in" do
- @parent_um.bind_call(UnboundMethodSpecs::Child1.new).should == nil
- @child1_um.bind_call(UnboundMethodSpecs::Parent.new).should == nil
- @child2_um.bind_call(UnboundMethodSpecs::Child1.new).should == nil
- end
+ it "binds and calls the method for any object kind_of? the Module the method is defined in" do
+ @parent_um.bind_call(UnboundMethodSpecs::Child1.new).should == nil
+ @child1_um.bind_call(UnboundMethodSpecs::Parent.new).should == nil
+ @child2_um.bind_call(UnboundMethodSpecs::Child1.new).should == nil
+ end
- it "binds and calls a Kernel method retrieved from Object on BasicObject" do
- Object.instance_method(:instance_of?).bind_call(BasicObject.new, BasicObject).should == true
- end
+ it "binds and calls a Kernel method retrieved from Object on BasicObject" do
+ Object.instance_method(:instance_of?).bind_call(BasicObject.new, BasicObject).should == true
+ end
- it "binds and calls a Parent's class method to any Child's class methods" do
- um = UnboundMethodSpecs::Parent.method(:class_method).unbind
- um.bind_call(UnboundMethodSpecs::Child1).should == "I am UnboundMethodSpecs::Child1"
- end
+ it "binds and calls a Parent's class method to any Child's class methods" do
+ um = UnboundMethodSpecs::Parent.method(:class_method).unbind
+ um.bind_call(UnboundMethodSpecs::Child1).should == "I am UnboundMethodSpecs::Child1"
+ end
- it "will raise when binding a an object singleton's method to another object" do
- other = UnboundMethodSpecs::Parent.new
- p = UnboundMethodSpecs::Parent.new
- class << p
- def singleton_method
- :single
- end
+ it "will raise when binding a an object singleton's method to another object" do
+ other = UnboundMethodSpecs::Parent.new
+ p = UnboundMethodSpecs::Parent.new
+ class << p
+ def singleton_method
+ :single
end
- um = p.method(:singleton_method).unbind
- ->{ um.bind_call(other) }.should raise_error(TypeError)
end
+ um = p.method(:singleton_method).unbind
+ ->{ um.bind_call(other) }.should raise_error(TypeError)
+ end
+
+ it "allows calling super for module methods bound to hierarchies that do not already have that module" do
+ p = UnboundMethodSpecs::Parent.new
+
+ @normal_um_super.bind_call(p).should == true
end
end
diff --git a/spec/ruby/core/unboundmethod/bind_spec.rb b/spec/ruby/core/unboundmethod/bind_spec.rb
index 03aaa22e74..7658b664e5 100644
--- a/spec/ruby/core/unboundmethod/bind_spec.rb
+++ b/spec/ruby/core/unboundmethod/bind_spec.rb
@@ -7,6 +7,8 @@ describe "UnboundMethod#bind" do
@parent_um = UnboundMethodSpecs::Parent.new.method(:foo).unbind
@child1_um = UnboundMethodSpecs::Child1.new.method(:foo).unbind
@child2_um = UnboundMethodSpecs::Child2.new.method(:foo).unbind
+ @normal_um_super = UnboundMethodSpecs::Mod.instance_method(:foo_super)
+ @parent_um_super = UnboundMethodSpecs::Parent.new.method(:foo_super).unbind
end
it "raises TypeError if object is not kind_of? the Module the method defined in" do
@@ -58,4 +60,10 @@ describe "UnboundMethod#bind" do
um = p.method(:singleton_method).unbind
->{ um.bind(other) }.should raise_error(TypeError)
end
+
+ it "allows calling super for module methods bound to hierarchies that do not already have that module" do
+ p = UnboundMethodSpecs::Parent.new
+
+ @normal_um_super.bind(p).call.should == true
+ end
end
diff --git a/spec/ruby/core/unboundmethod/clone_spec.rb b/spec/ruby/core/unboundmethod/clone_spec.rb
index 098ee61476..1e7fb18744 100644
--- a/spec/ruby/core/unboundmethod/clone_spec.rb
+++ b/spec/ruby/core/unboundmethod/clone_spec.rb
@@ -1,12 +1,13 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
+require_relative 'shared/dup'
describe "UnboundMethod#clone" do
- it "returns a copy of the UnboundMethod" do
- um1 = UnboundMethodSpecs::Methods.instance_method(:foo)
- um2 = um1.clone
+ it_behaves_like :unboundmethod_dup, :clone
- (um1 == um2).should == true
- um1.bind(UnboundMethodSpecs::Methods.new).call.should == um2.bind(UnboundMethodSpecs::Methods.new).call
+ it "preserves frozen status" do
+ method = Class.instance_method(:instance_method)
+ method.freeze
+ method.frozen?.should == true
+ method.clone.frozen?.should == true
end
end
diff --git a/spec/ruby/core/unboundmethod/dup_spec.rb b/spec/ruby/core/unboundmethod/dup_spec.rb
new file mode 100644
index 0000000000..5a78dd8e36
--- /dev/null
+++ b/spec/ruby/core/unboundmethod/dup_spec.rb
@@ -0,0 +1,15 @@
+require_relative '../../spec_helper'
+require_relative 'shared/dup'
+
+describe "UnboundMethod#dup" do
+ ruby_version_is "3.4" do
+ it_behaves_like :unboundmethod_dup, :dup
+
+ it "resets frozen status" do
+ method = Class.instance_method(:instance_method)
+ method.freeze
+ method.frozen?.should == true
+ method.dup.frozen?.should == false
+ end
+ end
+end
diff --git a/spec/ruby/core/unboundmethod/equal_value_spec.rb b/spec/ruby/core/unboundmethod/equal_value_spec.rb
index 6242b04884..036c6b7f8c 100644
--- a/spec/ruby/core/unboundmethod/equal_value_spec.rb
+++ b/spec/ruby/core/unboundmethod/equal_value_spec.rb
@@ -76,19 +76,38 @@ describe "UnboundMethod#==" do
(@identical_body == @original_body).should == false
end
- it "returns false if same method but one extracted from a subclass" do
- (@parent == @child1).should == false
- (@child1 == @parent).should == false
- end
+ ruby_version_is ""..."3.2" do
+ it "returns 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 same method but extracted from two different subclasses" do
- (@child2 == @child1).should == false
- (@child1 == @child2).should == false
+ it "returns false if methods are the same but added from an included Module" do
+ (@includee == @includer).should == false
+ (@includer == @includee).should == false
+ end
end
- it "returns false if methods are the same but added from an included Module" do
- (@includee == @includer).should == false
- (@includer == @includee).should == false
+ 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 methods are the same but added from an included Module" do
+ (@includee == @includer).should == true
+ (@includer == @includee).should == true
+ end
end
it "returns false if both have same Module, same name, identical body but not the same" do
@@ -98,4 +117,41 @@ describe "UnboundMethod#==" do
(@discard_1 == UnboundMethodSpecs::Methods.instance_method(:discard_1)).should == false
end
+
+ it "considers methods through aliasing equal" do
+ c = Class.new do
+ class << self
+ alias_method :n, :new
+ end
+ end
+
+ c.method(:new).should == c.method(:n)
+ c.method(:n).should == Class.instance_method(:new).bind(c)
+ end
+
+ # On CRuby < 3.2, the 2 specs below pass due to method/instance_method skipping zsuper methods.
+ # We are interested in the general pattern working, i.e. the combination of method/instance_method
+ # and #== exposes the wanted behavior.
+ it "considers methods through visibility change equal" do
+ c = Class.new do
+ class << self
+ private :new
+ end
+ end
+
+ c.method(:new).should == Class.instance_method(:new).bind(c)
+ end
+
+ it "considers methods through aliasing and visibility change equal" do
+ c = Class.new do
+ class << self
+ alias_method :n, :new
+ private :new
+ end
+ end
+
+ c.method(:new).should == c.method(:n)
+ c.method(:n).should == Class.instance_method(:new).bind(c)
+ c.method(:new).should == Class.instance_method(:new).bind(c)
+ end
end
diff --git a/spec/ruby/core/unboundmethod/fixtures/classes.rb b/spec/ruby/core/unboundmethod/fixtures/classes.rb
index 46b1c51669..28d8e0a965 100644
--- a/spec/ruby/core/unboundmethod/fixtures/classes.rb
+++ b/spec/ruby/core/unboundmethod/fixtures/classes.rb
@@ -22,6 +22,7 @@ module UnboundMethodSpecs
module Mod
def from_mod; end
+ def foo_super; super; end
end
class Methods
@@ -53,10 +54,19 @@ module UnboundMethodSpecs
def discard_1(); :discard; end
def discard_2(); :discard; end
+
+ def my_public_method; end
+ def my_protected_method; end
+ def my_private_method; end
+ protected :my_protected_method
+ private :my_private_method
end
class Parent
def foo; end
+ def foo_super
+ true
+ end
def self.class_method
"I am #{name}"
end
@@ -84,4 +94,14 @@ module UnboundMethodSpecs
class C < B
def overridden; end
end
+
+ module HashSpecs
+ class SuperClass
+ def foo
+ end
+ end
+
+ class SubClass < SuperClass
+ end
+ end
end
diff --git a/spec/ruby/core/unboundmethod/hash_spec.rb b/spec/ruby/core/unboundmethod/hash_spec.rb
index 12dce0020f..6888675bc1 100644
--- a/spec/ruby/core/unboundmethod/hash_spec.rb
+++ b/spec/ruby/core/unboundmethod/hash_spec.rb
@@ -12,4 +12,11 @@ describe "UnboundMethod#hash" do
to_s, inspect = Array.instance_method(:to_s), Array.instance_method(:inspect)
to_s.hash.should == inspect.hash
end
+
+ it "equals a hash of the same method in the superclass" do
+ foo_in_superclass = UnboundMethodSpecs::HashSpecs::SuperClass.instance_method(:foo)
+ foo = UnboundMethodSpecs::HashSpecs::SubClass.instance_method(:foo)
+
+ foo.hash.should == foo_in_superclass.hash
+ end
end
diff --git a/spec/ruby/core/unboundmethod/owner_spec.rb b/spec/ruby/core/unboundmethod/owner_spec.rb
index 5f1f4646b3..e8a734dac4 100644
--- a/spec/ruby/core/unboundmethod/owner_spec.rb
+++ b/spec/ruby/core/unboundmethod/owner_spec.rb
@@ -1,5 +1,6 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
+require_relative '../method/fixtures/classes'
describe "UnboundMethod#owner" do
it "returns the owner of the method" do
@@ -23,4 +24,10 @@ describe "UnboundMethod#owner" do
child_singleton_class.instance_method(:class_method).owner.should == parent_singleton_class
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
+ end
end
diff --git a/spec/ruby/core/unboundmethod/private_spec.rb b/spec/ruby/core/unboundmethod/private_spec.rb
new file mode 100644
index 0000000000..8ea50bb5d4
--- /dev/null
+++ b/spec/ruby/core/unboundmethod/private_spec.rb
@@ -0,0 +1,28 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+
+describe "UnboundMethod#private?" do
+ ruby_version_is "3.1"..."3.2" do
+ it "returns false when the method is public" do
+ obj = UnboundMethodSpecs::Methods.new
+ obj.method(:my_public_method).unbind.private?.should == false
+ end
+
+ it "returns false when the method is protected" do
+ obj = UnboundMethodSpecs::Methods.new
+ obj.method(:my_protected_method).unbind.private?.should == false
+ end
+
+ it "returns true when the method is private" do
+ obj = UnboundMethodSpecs::Methods.new
+ obj.method(:my_private_method).unbind.private?.should == true
+ end
+ end
+
+ ruby_version_is "3.2" do
+ it "has been removed" do
+ obj = UnboundMethodSpecs::Methods.new
+ obj.method(:my_private_method).unbind.should_not.respond_to?(:private?)
+ end
+ end
+end
diff --git a/spec/ruby/core/unboundmethod/protected_spec.rb b/spec/ruby/core/unboundmethod/protected_spec.rb
new file mode 100644
index 0000000000..0c215d8638
--- /dev/null
+++ b/spec/ruby/core/unboundmethod/protected_spec.rb
@@ -0,0 +1,28 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+
+describe "UnboundMethod#protected?" do
+ ruby_version_is "3.1"..."3.2" do
+ it "returns false when the method is public" do
+ obj = UnboundMethodSpecs::Methods.new
+ obj.method(:my_public_method).unbind.protected?.should == false
+ end
+
+ it "returns true when the method is protected" do
+ obj = UnboundMethodSpecs::Methods.new
+ obj.method(:my_protected_method).unbind.protected?.should == true
+ end
+
+ it "returns false when the method is private" do
+ obj = UnboundMethodSpecs::Methods.new
+ obj.method(:my_private_method).unbind.protected?.should == false
+ end
+ end
+
+ ruby_version_is "3.2" do
+ it "has been removed" do
+ obj = UnboundMethodSpecs::Methods.new
+ obj.method(:my_protected_method).unbind.should_not.respond_to?(:protected?)
+ end
+ end
+end
diff --git a/spec/ruby/core/unboundmethod/public_spec.rb b/spec/ruby/core/unboundmethod/public_spec.rb
new file mode 100644
index 0000000000..552bbf6eab
--- /dev/null
+++ b/spec/ruby/core/unboundmethod/public_spec.rb
@@ -0,0 +1,28 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+
+describe "UnboundMethod#public?" do
+ ruby_version_is "3.1"..."3.2" do
+ it "returns true when the method is public" do
+ obj = UnboundMethodSpecs::Methods.new
+ obj.method(:my_public_method).unbind.public?.should == true
+ end
+
+ it "returns false when the method is protected" do
+ obj = UnboundMethodSpecs::Methods.new
+ obj.method(:my_protected_method).unbind.public?.should == false
+ end
+
+ it "returns false when the method is private" do
+ obj = UnboundMethodSpecs::Methods.new
+ obj.method(:my_private_method).unbind.public?.should == false
+ end
+ end
+
+ ruby_version_is "3.2" do
+ it "has been removed" do
+ obj = UnboundMethodSpecs::Methods.new
+ obj.method(:my_public_method).unbind.should_not.respond_to?(:public?)
+ end
+ end
+end
diff --git a/spec/ruby/core/unboundmethod/shared/dup.rb b/spec/ruby/core/unboundmethod/shared/dup.rb
new file mode 100644
index 0000000000..943a7faaa3
--- /dev/null
+++ b/spec/ruby/core/unboundmethod/shared/dup.rb
@@ -0,0 +1,32 @@
+describe :unboundmethod_dup, shared: true do
+ it "returns a copy of self" do
+ a = Class.instance_method(:instance_method)
+ b = a.send(@method)
+
+ a.should == b
+ a.should_not equal(b)
+ end
+
+ ruby_version_is "3.4" do
+ it "copies instance variables" do
+ method = Class.instance_method(:instance_method)
+ method.instance_variable_set(:@ivar, 1)
+ cl = method.send(@method)
+ cl.instance_variables.should == [:@ivar]
+ end
+
+ it "copies the finalizer" do
+ code = <<-RUBY
+ obj = Class.instance_method(:instance_method)
+
+ ObjectSpace.define_finalizer(obj, Proc.new { STDOUT.write "finalized\n" })
+
+ obj.clone
+
+ exit 0
+ RUBY
+
+ ruby_exe(code).lines.sort.should == ["finalized\n", "finalized\n"]
+ end
+ end
+end
diff --git a/spec/ruby/core/unboundmethod/shared/to_s.rb b/spec/ruby/core/unboundmethod/shared/to_s.rb
index 38503c3c60..b92bb0b207 100644
--- a/spec/ruby/core/unboundmethod/shared/to_s.rb
+++ b/spec/ruby/core/unboundmethod/shared/to_s.rb
@@ -20,12 +20,22 @@ 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/
- @from_method.send(@method).should =~ /\bUnboundMethodSpecs::Methods\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
- @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"
+ 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
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 96933a5d40..5c2f14362c 100644
--- a/spec/ruby/core/unboundmethod/source_location_spec.rb
+++ b/spec/ruby/core/unboundmethod/source_location_spec.rb
@@ -9,7 +9,7 @@ describe "UnboundMethod#source_location" do
it "sets the first value to the path of the file in which the method was defined" do
file = @method.source_location.first
file.should be_an_instance_of(String)
- file.should == File.realpath('../fixtures/classes.rb', __FILE__)
+ 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
@@ -49,4 +49,11 @@ describe "UnboundMethod#source_location" do
method.source_location[0].should =~ /#{__FILE__}/
method.source_location[1].should == line
end
+
+ it "works for eval with a given line" do
+ c = Class.new do
+ eval('def m; end', nil, "foo", 100)
+ end
+ c.instance_method(:m).source_location.should == ["foo", 100]
+ end
end
diff --git a/spec/ruby/core/unboundmethod/super_method_spec.rb b/spec/ruby/core/unboundmethod/super_method_spec.rb
index c9fa1ec533..aa7c129377 100644
--- a/spec/ruby/core/unboundmethod/super_method_spec.rb
+++ b/spec/ruby/core/unboundmethod/super_method_spec.rb
@@ -1,5 +1,6 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
+require_relative '../method/fixtures/classes'
describe "UnboundMethod#super_method" do
it "returns the method that would be called by super in the method" do
@@ -25,4 +26,24 @@ describe "UnboundMethod#super_method" do
method.super_method.should == nil
end
+
+ # https://github.com/jruby/jruby/issues/7240
+ context "after changing an inherited methods visibility" do
+ it "calls the proper super method" do
+ method = MethodSpecs::InheritedMethods::C.instance_method(:derp)
+ method.bind(MethodSpecs::InheritedMethods::C.new).call.should == 'BA'
+ end
+
+ it "returns the expected super_method" do
+ method = MethodSpecs::InheritedMethods::C.instance_method(:derp)
+ method.super_method.owner.should == MethodSpecs::InheritedMethods::A
+ end
+ end
+
+ context "after aliasing an inherited method" do
+ it "returns the expected super_method" do
+ method = MethodSpecs::InheritedMethods::C.instance_method(:meow)
+ method.super_method.owner.should == MethodSpecs::InheritedMethods::A
+ end
+ end
end
diff --git a/spec/ruby/core/warning/element_reference_spec.rb b/spec/ruby/core/warning/element_reference_spec.rb
index f51cc87de5..8cb4018c20 100644
--- a/spec/ruby/core/warning/element_reference_spec.rb
+++ b/spec/ruby/core/warning/element_reference_spec.rb
@@ -1,22 +1,25 @@
require_relative '../../spec_helper'
-ruby_version_is '2.7' do
- describe "Warning.[]" do
- ruby_version_is '2.7.2' do
- it "returns default values for categories :deprecated and :experimental" do
- ruby_exe('p Warning[:deprecated]').chomp.should == "false"
- ruby_exe('p Warning[:experimental]').chomp.should == "true"
- end
- end
+describe "Warning.[]" do
+ it "returns default values for categories :deprecated and :experimental" do
+ ruby_exe('p [Warning[:deprecated], Warning[:experimental]]').chomp.should == "[false, true]"
+ ruby_exe('p [Warning[:deprecated], Warning[:experimental]]', options: "-w").chomp.should == "[true, true]"
+ end
- it "raises for unknown category" do
- -> { Warning[:noop] }.should raise_error(ArgumentError, /unknown category: noop/)
+ ruby_version_is '3.3' do
+ it "returns default values for :performance category" do
+ ruby_exe('p Warning[:performance]').chomp.should == "false"
+ ruby_exe('p Warning[:performance]', options: "-w").chomp.should == "false"
end
+ end
- it "raises for non-Symbol category" do
- -> { Warning[42] }.should raise_error(TypeError)
- -> { Warning[false] }.should raise_error(TypeError)
- -> { Warning["noop"] }.should raise_error(TypeError)
- end
+ it "raises for unknown category" do
+ -> { Warning[:noop] }.should raise_error(ArgumentError, /unknown category: noop/)
+ end
+
+ it "raises for non-Symbol category" do
+ -> { Warning[42] }.should raise_error(TypeError)
+ -> { Warning[false] }.should raise_error(TypeError)
+ -> { Warning["noop"] }.should raise_error(TypeError)
end
end
diff --git a/spec/ruby/core/warning/element_set_spec.rb b/spec/ruby/core/warning/element_set_spec.rb
index 611060fb3a..d59a7d4c9e 100644
--- a/spec/ruby/core/warning/element_set_spec.rb
+++ b/spec/ruby/core/warning/element_set_spec.rb
@@ -1,37 +1,41 @@
require_relative '../../spec_helper'
-ruby_version_is '2.7' do
- describe "Warning.[]=" do
- it "emits and suppresses warnings for :deprecated" do
- ruby_exe('Warning[:deprecated] = true; $; = ""', args: "2>&1").should =~ /is deprecated/
- ruby_exe('Warning[:deprecated] = false; $; = ""', args: "2>&1").should == ""
- end
+describe "Warning.[]=" do
+ it "emits and suppresses warnings for :deprecated" do
+ ruby_exe('Warning[:deprecated] = true; $; = ""', args: "2>&1").should =~ /is deprecated/
+ ruby_exe('Warning[:deprecated] = false; $; = ""', args: "2>&1").should == ""
+ end
- describe ":experimental" do
- before do
- ruby_version_is ""..."3.0" do
- @src = 'case [0, 1]; in [a, b]; end'
- end
+ describe ":experimental" do
+ before do
+ @src = 'warn "This is experimental warning.", category: :experimental'
+ end
- ruby_version_is "3.0" do
- @src = 'warn "This is experimental warning.", category: :experimental'
- end
- end
+ it "emits and suppresses warnings for :experimental" do
+ ruby_exe("Warning[:experimental] = true; eval('#{@src}')", args: "2>&1").should =~ /is experimental/
+ ruby_exe("Warning[:experimental] = false; eval('#{@src}')", args: "2>&1").should == ""
+ end
+ end
- it "emits and suppresses warnings for :experimental" do
- ruby_exe("Warning[:experimental] = true; eval('#{@src}')", args: "2>&1").should =~ /is experimental/
- ruby_exe("Warning[:experimental] = false; eval('#{@src}')", args: "2>&1").should == ""
+ ruby_version_is '3.3' do
+ it "enables or disables performance warnings" do
+ original = Warning[:performance]
+ begin
+ Warning[:performance] = !original
+ Warning[:performance].should == !original
+ ensure
+ Warning[:performance] = original
end
end
+ end
- it "raises for unknown category" do
- -> { Warning[:noop] = false }.should raise_error(ArgumentError, /unknown category: noop/)
- end
+ it "raises for unknown category" do
+ -> { Warning[:noop] = false }.should raise_error(ArgumentError, /unknown category: noop/)
+ end
- it "raises for non-Symbol category" do
- -> { Warning[42] = false }.should raise_error(TypeError)
- -> { Warning[false] = false }.should raise_error(TypeError)
- -> { Warning["noop"] = false }.should raise_error(TypeError)
- end
+ it "raises for non-Symbol category" do
+ -> { Warning[42] = false }.should raise_error(TypeError)
+ -> { Warning[false] = false }.should raise_error(TypeError)
+ -> { Warning["noop"] = false }.should raise_error(TypeError)
end
end
diff --git a/spec/ruby/core/warning/warn_spec.rb b/spec/ruby/core/warning/warn_spec.rb
index 5ccff3aa2b..8f96fe9287 100644
--- a/spec/ruby/core/warning/warn_spec.rb
+++ b/spec/ruby/core/warning/warn_spec.rb
@@ -51,40 +51,85 @@ describe "Warning.warn" do
end
end
- ruby_version_is '3.0' do
- it "is called by Kernel.warn with nil category keyword" do
- Warning.should_receive(:warn).with("Chunky bacon!\n", category: nil)
- verbose = $VERBOSE
- $VERBOSE = false
- begin
- Kernel.warn("Chunky bacon!")
- ensure
- $VERBOSE = verbose
- end
+ it "is called by Kernel.warn with nil category keyword" do
+ Warning.should_receive(:warn).with("Chunky bacon!\n", category: nil)
+ verbose = $VERBOSE
+ $VERBOSE = false
+ begin
+ Kernel.warn("Chunky bacon!")
+ ensure
+ $VERBOSE = verbose
end
+ end
- it "is called by Kernel.warn with given category keyword converted to a symbol" do
- Warning.should_receive(:warn).with("Chunky bacon!\n", category: :deprecated)
- verbose = $VERBOSE
- $VERBOSE = false
- begin
- Kernel.warn("Chunky bacon!", category: "deprecated")
- ensure
- $VERBOSE = verbose
- end
+ it "is called by Kernel.warn with given category keyword converted to a symbol" do
+ Warning.should_receive(:warn).with("Chunky bacon!\n", category: :deprecated)
+ verbose = $VERBOSE
+ $VERBOSE = false
+ begin
+ Kernel.warn("Chunky bacon!", category: "deprecated")
+ ensure
+ $VERBOSE = verbose
end
end
- ruby_version_is ''...'3.0' do
- it "is called by Kernel.warn" do
- Warning.should_receive(:warn).with("Chunky bacon!\n")
- verbose = $VERBOSE
- $VERBOSE = false
- begin
- Kernel.warn("Chunky bacon!")
- ensure
- $VERBOSE = verbose
- end
+ it "warns when category is :deprecated and Warning[:deprecated] is true" do
+ warn_deprecated = Warning[:deprecated]
+ Warning[:deprecated] = true
+ begin
+ -> {
+ Warning.warn("foo", category: :deprecated)
+ }.should complain("foo")
+ ensure
+ Warning[:deprecated] = warn_deprecated
end
end
+
+ it "warns when category is :experimental and Warning[:experimental] is true" do
+ warn_experimental = Warning[:experimental]
+ Warning[:experimental] = true
+ begin
+ -> {
+ Warning.warn("foo", category: :experimental)
+ }.should complain("foo")
+ ensure
+ Warning[:experimental] = warn_experimental
+ end
+ end
+
+ it "doesn't print message when category is :deprecated but Warning[:deprecated] is false" do
+ warn_deprecated = Warning[:deprecated]
+ Warning[:deprecated] = false
+ begin
+ -> {
+ Warning.warn("foo", category: :deprecated)
+ }.should_not complain
+ ensure
+ Warning[:deprecated] = warn_deprecated
+ end
+ end
+
+ it "doesn't print message when category is :experimental but Warning[:experimental] is false" do
+ warn_experimental = Warning[:experimental]
+ Warning[:experimental] = false
+ begin
+ -> {
+ Warning.warn("foo", category: :experimental)
+ }.should_not complain
+ ensure
+ Warning[:experimental] = warn_experimental
+ end
+ end
+
+ it "prints the message when VERBOSE is false" do
+ -> { Warning.warn("foo") }.should complain("foo")
+ end
+
+ it "prints the message when VERBOSE is nil" do
+ -> { Warning.warn("foo") }.should complain("foo", verbose: nil)
+ end
+
+ it "prints the message when VERBOSE is true" do
+ -> { Warning.warn("foo") }.should complain("foo", verbose: true)
+ end
end
diff --git a/spec/ruby/default.mspec b/spec/ruby/default.mspec
index a0dc69c03d..1e8f8893aa 100644
--- a/spec/ruby/default.mspec
+++ b/spec/ruby/default.mspec
@@ -1,3 +1,4 @@
+# -*- ruby -*-
# Configuration file for Ruby >= 2.0 implementations.
class MSpecScript
diff --git a/spec/ruby/fixtures/code/c/load_fixture.rb b/spec/ruby/fixtures/code/c/load_fixture.rb
new file mode 100644
index 0000000000..4a6e9c9601
--- /dev/null
+++ b/spec/ruby/fixtures/code/c/load_fixture.rb
@@ -0,0 +1 @@
+ScratchPad << :loaded
diff --git a/spec/ruby/fixtures/code/concurrent_require_fixture.rb b/spec/ruby/fixtures/code/concurrent_require_fixture.rb
new file mode 100644
index 0000000000..d4ce734183
--- /dev/null
+++ b/spec/ruby/fixtures/code/concurrent_require_fixture.rb
@@ -0,0 +1,4 @@
+object = ScratchPad.recorded
+thread = Thread.new { object.require(__FILE__) }
+Thread.pass until thread.stop?
+ScratchPad.record(thread)
diff --git a/spec/ruby/fixtures/code/d/load_fixture.rb.rb b/spec/ruby/fixtures/code/d/load_fixture.rb.rb
new file mode 100644
index 0000000000..7e9217729a
--- /dev/null
+++ b/spec/ruby/fixtures/code/d/load_fixture.rb.rb
@@ -0,0 +1 @@
+ScratchPad << :rbrb
diff --git a/spec/ruby/fixtures/code/load_wrap_fixture.rb b/spec/ruby/fixtures/code/load_wrap_fixture.rb
new file mode 100644
index 0000000000..526bbf8c82
--- /dev/null
+++ b/spec/ruby/fixtures/code/load_wrap_fixture.rb
@@ -0,0 +1,12 @@
+class LoadSpecWrap
+ ScratchPad << String
+end
+
+LOAD_WRAP_SPECS_TOP_LEVEL_CONSTANT = 1
+
+def load_wrap_specs_top_level_method
+ :load_wrap_specs_top_level_method
+end
+ScratchPad << method(:load_wrap_specs_top_level_method).owner
+
+ScratchPad << self
diff --git a/spec/ruby/fixtures/code/wrap_fixture.rb b/spec/ruby/fixtures/code/wrap_fixture.rb
deleted file mode 100644
index 7ddf5a62e0..0000000000
--- a/spec/ruby/fixtures/code/wrap_fixture.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-class LoadSpecWrap
- ScratchPad << String
-end
-
-def load_wrap_specs_top_level_method
-end
-ScratchPad << method(:load_wrap_specs_top_level_method).owner
-
-ScratchPad << self
diff --git a/spec/ruby/fixtures/constants.rb b/spec/ruby/fixtures/constants.rb
index 37271ddcc8..ffe45fb1f6 100644
--- a/spec/ruby/fixtures/constants.rb
+++ b/spec/ruby/fixtures/constants.rb
@@ -44,6 +44,7 @@ module ConstantSpecs
# Included in ParentA
module ModuleB
+ LINE = __LINE__ - 1
CS_CONST10 = :const10_9
CS_CONST11 = :const11_2
CS_CONST12 = :const12_1
@@ -75,12 +76,19 @@ module ConstantSpecs
CS_CONST10 = :const10_8
end
+ # Included in ContainerA
+ module ModuleIncludePrepended
+ prepend ModuleD
+
+ CS_CONST11 = :const11_8
+ end
+
# The following classes/modules have all the constants set "statically".
# Contrast with the classes below where the constants are set as the specs
# are run.
class ClassA
- CS_CLASS_A_LINE = __LINE__ - 1
+ LINE = __LINE__ - 1
CS_CONST10 = :const10_10
CS_CONST10_LINE = __LINE__ - 1
CS_CONST16 = :const16
@@ -169,6 +177,10 @@ module ConstantSpecs
def const10; CS_CONST10; end
end
+ class ContainerPrepend
+ include ModuleIncludePrepended
+ end
+
class ContainerA::ChildA
def self.const23; CS_CONST23; end
end
@@ -299,4 +311,14 @@ module ConstantSpecs
private_constant :CS_PRIVATE
end
+module ConstantSpecsThree
+ module ConstantSpecsTwo
+ Foo = :cs_three_foo
+ end
+end
+
+module ConstantSpecsTwo
+ Foo = :cs_two_foo
+end
+
include ConstantSpecs::ModuleA
diff --git a/spec/ruby/language/END_spec.rb b/spec/ruby/language/END_spec.rb
index 762a8db0c0..c84f0cc9ac 100644
--- a/spec/ruby/language/END_spec.rb
+++ b/spec/ruby/language/END_spec.rb
@@ -1,15 +1,33 @@
require_relative '../spec_helper'
+require_relative '../shared/kernel/at_exit'
describe "The END keyword" do
+ it_behaves_like :kernel_at_exit, :END
+
it "runs only once for multiple calls" do
ruby_exe("10.times { END { puts 'foo' }; } ").should == "foo\n"
end
- it "runs last in a given code unit" do
- ruby_exe("END { puts 'bar' }; puts'foo'; ").should == "foo\nbar\n"
+ it "is affected by the toplevel assignment" do
+ ruby_exe("foo = 'foo'; END { puts foo }").should == "foo\n"
+ end
+
+ it "warns when END is used in a method" do
+ ruby_exe(<<~ruby, args: "2>&1").should =~ /warning: END in method; use at_exit/
+ def foo
+ END { }
+ end
+ ruby
end
- it "runs multiple ends in LIFO order" do
- ruby_exe("END { puts 'foo' }; END { puts 'bar' }").should == "bar\nfoo\n"
+ context "END blocks and at_exit callbacks are mixed" do
+ it "runs them all in reverse order of registration" do
+ ruby_exe(<<~ruby).should == "at_exit#2\nEND#2\nat_exit#1\nEND#1\n"
+ END { puts 'END#1' }
+ at_exit { puts 'at_exit#1' }
+ END { puts 'END#2' }
+ at_exit { puts 'at_exit#2' }
+ ruby
+ end
end
end
diff --git a/spec/ruby/language/alias_spec.rb b/spec/ruby/language/alias_spec.rb
index d1d06e3fac..61fddb0184 100644
--- a/spec/ruby/language/alias_spec.rb
+++ b/spec/ruby/language/alias_spec.rb
@@ -52,6 +52,15 @@ describe "The alias keyword" do
@obj.a.should == 5
end
+ it "works with an interpolated symbol with non-literal embedded expression on the left-hand side" do
+ @meta.class_eval do
+ eval %Q{
+ alias :"#{'a' + ''.to_s}" value
+ }
+ end
+ @obj.a.should == 5
+ end
+
it "works with a simple symbol on the right-hand side" do
@meta.class_eval do
alias a :value
@@ -80,6 +89,15 @@ describe "The alias keyword" do
@obj.a.should == 5
end
+ it "works with an interpolated symbol with non-literal embedded expression on the right-hand side" do
+ @meta.class_eval do
+ eval %Q{
+ alias a :"#{'value' + ''.to_s}"
+ }
+ end
+ @obj.a.should == 5
+ end
+
it "adds the new method to the list of methods" do
original_methods = @obj.methods
@meta.class_eval do
@@ -234,7 +252,7 @@ describe "The alias keyword" do
it "on top level defines the alias on Object" do
# because it defines on the default definee / current module
- ruby_exe("def foo; end; alias bla foo; print method(:bla).owner", escape: true).should == "Object"
+ ruby_exe("def foo; end; alias bla foo; print method(:bla).owner").should == "Object"
end
it "raises a NameError when passed a missing name" do
@@ -243,6 +261,19 @@ describe "The alias keyword" do
e.class.should == NameError
}
end
+
+ it "defines the method on the aliased class when the original method is from a parent class" do
+ parent = Class.new do
+ def parent_method
+ end
+ end
+ child = Class.new(parent) do
+ alias parent_method_alias parent_method
+ end
+
+ child.instance_method(:parent_method_alias).owner.should == child
+ child.instance_methods(false).should include(:parent_method_alias)
+ end
end
describe "The alias keyword" do
diff --git a/spec/ruby/language/assignments_spec.rb b/spec/ruby/language/assignments_spec.rb
new file mode 100644
index 0000000000..2773508d8d
--- /dev/null
+++ b/spec/ruby/language/assignments_spec.rb
@@ -0,0 +1,529 @@
+require_relative '../spec_helper'
+
+# Should be synchronized with spec/ruby/language/optional_assignments_spec.rb
+# Some specs for assignments are located in language/variables_spec.rb
+describe 'Assignments' do
+ describe 'using =' do
+ describe 'evaluation order' do
+ it 'evaluates expressions left to right when assignment with an accessor' do
+ object = Object.new
+ def object.a=(value) end
+ ScratchPad.record []
+
+ (ScratchPad << :receiver; object).a = (ScratchPad << :rhs; :value)
+ ScratchPad.recorded.should == [:receiver, :rhs]
+ end
+
+ it 'evaluates expressions left to right when assignment with a #[]=' do
+ object = Object.new
+ def object.[]=(_, _) end
+ ScratchPad.record []
+
+ (ScratchPad << :receiver; object)[(ScratchPad << :argument; :a)] = (ScratchPad << :rhs; :value)
+ ScratchPad.recorded.should == [:receiver, :argument, :rhs]
+ end
+
+ # similar tests for evaluation order are located in language/constants_spec.rb
+ ruby_version_is ''...'3.2' do
+ it 'evaluates expressions right to left when assignment with compounded constant' do
+ m = Module.new
+ ScratchPad.record []
+
+ (ScratchPad << :module; m)::A = (ScratchPad << :rhs; :value)
+ ScratchPad.recorded.should == [:rhs, :module]
+ end
+ end
+
+ ruby_version_is '3.2' do
+ it 'evaluates expressions left to right when assignment with compounded constant' do
+ m = Module.new
+ ScratchPad.record []
+
+ (ScratchPad << :module; m)::A = (ScratchPad << :rhs; :value)
+ ScratchPad.recorded.should == [:module, :rhs]
+ end
+ end
+
+ it 'raises TypeError after evaluation of right-hand-side when compounded constant module is not a module' do
+ ScratchPad.record []
+
+ -> {
+ (:not_a_module)::A = (ScratchPad << :rhs; :value)
+ }.should raise_error(TypeError)
+
+ ScratchPad.recorded.should == [:rhs]
+ end
+ end
+ end
+
+ describe 'using +=' do
+ describe 'using an accessor' do
+ before do
+ klass = Class.new { attr_accessor :b }
+ @a = klass.new
+ end
+
+ it 'does evaluate receiver only once when assigns' do
+ ScratchPad.record []
+ @a.b = 1
+
+ (ScratchPad << :evaluated; @a).b += 2
+
+ ScratchPad.recorded.should == [:evaluated]
+ @a.b.should == 3
+ end
+
+ it 'ignores method visibility when receiver is self' do
+ klass_with_private_methods = Class.new do
+ def initialize(n) @a = n end
+ def public_method(n); self.a += n end
+ private
+ def a; @a end
+ def a=(n) @a = n; 42 end
+ end
+
+ a = klass_with_private_methods.new(0)
+ a.public_method(2).should == 2
+ end
+ end
+
+ describe 'using a #[]' do
+ before do
+ klass = Class.new do
+ def [](k)
+ @hash ||= {}
+ @hash[k]
+ end
+
+ def []=(k, v)
+ @hash ||= {}
+ @hash[k] = v
+ 7
+ end
+ end
+ @b = klass.new
+ end
+
+ it 'evaluates receiver only once when assigns' do
+ ScratchPad.record []
+ a = {k: 1}
+
+ (ScratchPad << :evaluated; a)[:k] += 2
+
+ ScratchPad.recorded.should == [:evaluated]
+ a[:k].should == 3
+ end
+
+ it 'ignores method visibility when receiver is self' do
+ klass_with_private_methods = Class.new do
+ def initialize(h) @a = h end
+ def public_method(k, n); self[k] += n end
+ private
+ def [](k) @a[k] end
+ def []=(k, v) @a[k] = v; 42 end
+ end
+
+ a = klass_with_private_methods.new(k: 0)
+ a.public_method(:k, 2).should == 2
+ end
+
+ context 'splatted argument' do
+ it 'correctly handles it' do
+ @b[:m] = 10
+ (@b[*[:m]] += 10).should == 20
+ @b[:m].should == 20
+
+ @b[:n] = 10
+ (@b[*(1; [:n])] += 10).should == 20
+ @b[:n].should == 20
+
+ @b[:k] = 10
+ (@b[*begin 1; [:k] end] += 10).should == 20
+ @b[:k].should == 20
+ end
+
+ it 'calls #to_a only once' do
+ k = Object.new
+ def k.to_a
+ ScratchPad << :to_a
+ [:k]
+ end
+
+ ScratchPad.record []
+ @b[:k] = 10
+ (@b[*k] += 10).should == 20
+ @b[:k].should == 20
+ ScratchPad.recorded.should == [:to_a]
+ end
+
+ it 'correctly handles a nested splatted argument' do
+ @b[:k] = 10
+ (@b[*[*[:k]]] += 10).should == 20
+ @b[:k].should == 20
+ end
+
+ it 'correctly handles multiple nested splatted arguments' do
+ klass_with_multiple_parameters = Class.new do
+ def [](k1, k2, k3)
+ @hash ||= {}
+ @hash[:"#{k1}#{k2}#{k3}"]
+ end
+
+ def []=(k1, k2, k3, v)
+ @hash ||= {}
+ @hash[:"#{k1}#{k2}#{k3}"] = v
+ 7
+ end
+ end
+ a = klass_with_multiple_parameters.new
+
+ a[:a, :b, :c] = 10
+ (a[*[:a], *[:b], *[:c]] += 10).should == 20
+ a[:a, :b, :c].should == 20
+ end
+ end
+ end
+
+ describe 'using compounded constants' do
+ it 'causes side-effects of the module part to be applied only once (when assigns)' do
+ module ConstantSpecs
+ OpAssignTrue = 1
+ end
+
+ suppress_warning do # already initialized constant
+ x = 0
+ (x += 1; ConstantSpecs)::OpAssignTrue += 2
+ x.should == 1
+ ConstantSpecs::OpAssignTrue.should == 3
+ end
+
+ ConstantSpecs.send :remove_const, :OpAssignTrue
+ end
+ end
+ end
+end
+
+# generic cases
+describe 'Multiple assignments' do
+ it 'assigns multiple targets when assignment with an accessor' do
+ object = Object.new
+ class << object
+ attr_accessor :a, :b
+ end
+
+ object.a, object.b = :a, :b
+
+ object.a.should == :a
+ object.b.should == :b
+ end
+
+ it 'assigns multiple targets when assignment with a nested accessor' do
+ object = Object.new
+ class << object
+ attr_accessor :a, :b
+ end
+
+ (object.a, object.b), c = [:a, :b], nil
+
+ object.a.should == :a
+ object.b.should == :b
+ end
+
+ it 'assigns multiple targets when assignment with a #[]=' do
+ object = Object.new
+ class << object
+ def []=(k, v) (@h ||= {})[k] = v; end
+ def [](k) (@h ||= {})[k]; end
+ end
+
+ object[:a], object[:b] = :a, :b
+
+ object[:a].should == :a
+ object[:b].should == :b
+ end
+
+ it 'assigns multiple targets when assignment with a nested #[]=' do
+ object = Object.new
+ class << object
+ def []=(k, v) (@h ||= {})[k] = v; end
+ def [](k) (@h ||= {})[k]; end
+ end
+
+ (object[:a], object[:b]), c = [:v1, :v2], nil
+
+ object[:a].should == :v1
+ object[:b].should == :v2
+ end
+
+ it 'assigns multiple targets when assignment with compounded constant' do
+ m = Module.new
+
+ m::A, m::B = :a, :b
+
+ m::A.should == :a
+ m::B.should == :b
+ end
+
+ it 'assigns multiple targets when assignment with a nested compounded constant' do
+ m = Module.new
+
+ (m::A, m::B), c = [:a, :b], nil
+
+ m::A.should == :a
+ m::B.should == :b
+ end
+end
+
+describe 'Multiple assignments' do
+ describe 'evaluation order' do
+ ruby_version_is ''...'3.1' do
+ it 'evaluates expressions right to left when assignment with an accessor' do
+ object = Object.new
+ def object.a=(value) end
+ ScratchPad.record []
+
+ (ScratchPad << :a; object).a, (ScratchPad << :b; object).a = (ScratchPad << :c; :c), (ScratchPad << :d; :d)
+ ScratchPad.recorded.should == [:c, :d, :a, :b]
+ end
+
+ it 'evaluates expressions right to left when assignment with a nested accessor' do
+ object = Object.new
+ def object.a=(value) end
+ ScratchPad.record []
+
+ ((ScratchPad << :a; object).a, foo), bar = [(ScratchPad << :b; :b)]
+ ScratchPad.recorded.should == [:b, :a]
+ end
+ end
+
+ ruby_version_is '3.1' do
+ it 'evaluates expressions left to right when assignment with an accessor' do
+ object = Object.new
+ def object.a=(value) end
+ ScratchPad.record []
+
+ (ScratchPad << :a; object).a, (ScratchPad << :b; object).a = (ScratchPad << :c; :c), (ScratchPad << :d; :d)
+ ScratchPad.recorded.should == [:a, :b, :c, :d]
+ end
+
+ it 'evaluates expressions left to right when assignment with a nested accessor' do
+ object = Object.new
+ def object.a=(value) end
+ ScratchPad.record []
+
+ ((ScratchPad << :a; object).a, foo), bar = [(ScratchPad << :b; :b)]
+ ScratchPad.recorded.should == [:a, :b]
+ end
+
+ it 'evaluates expressions left to right when assignment with a deeply nested accessor' do
+ o = Object.new
+ def o.a=(value) end
+ def o.b=(value) end
+ def o.c=(value) end
+ def o.d=(value) end
+ def o.e=(value) end
+ def o.f=(value) end
+ ScratchPad.record []
+
+ (ScratchPad << :a; o).a,
+ ((ScratchPad << :b; o).b,
+ ((ScratchPad << :c; o).c, (ScratchPad << :d; o).d),
+ (ScratchPad << :e; o).e),
+ (ScratchPad << :f; o).f = (ScratchPad << :value; :value)
+
+ ScratchPad.recorded.should == [:a, :b, :c, :d, :e, :f, :value]
+ end
+ end
+
+ ruby_version_is ''...'3.1' do
+ it 'evaluates expressions right to left when assignment with a #[]=' do
+ object = Object.new
+ def object.[]=(_, _) end
+ ScratchPad.record []
+
+ (ScratchPad << :a; object)[(ScratchPad << :b; :b)], (ScratchPad << :c; object)[(ScratchPad << :d; :d)] = (ScratchPad << :e; :e), (ScratchPad << :f; :f)
+ ScratchPad.recorded.should == [:e, :f, :a, :b, :c, :d]
+ end
+
+ it 'evaluates expressions right to left when assignment with a nested #[]=' do
+ object = Object.new
+ def object.[]=(_, _) end
+ ScratchPad.record []
+
+ ((ScratchPad << :a; object)[(ScratchPad << :b; :b)], foo), bar = [(ScratchPad << :c; :c)]
+ ScratchPad.recorded.should == [:c, :a, :b]
+ end
+ end
+
+ ruby_version_is '3.1' do
+ it 'evaluates expressions left to right when assignment with a #[]=' do
+ object = Object.new
+ def object.[]=(_, _) end
+ ScratchPad.record []
+
+ (ScratchPad << :a; object)[(ScratchPad << :b; :b)], (ScratchPad << :c; object)[(ScratchPad << :d; :d)] = (ScratchPad << :e; :e), (ScratchPad << :f; :f)
+ ScratchPad.recorded.should == [:a, :b, :c, :d, :e, :f]
+ end
+
+ it 'evaluates expressions left to right when assignment with a nested #[]=' do
+ object = Object.new
+ def object.[]=(_, _) end
+ ScratchPad.record []
+
+ ((ScratchPad << :a; object)[(ScratchPad << :b; :b)], foo), bar = [(ScratchPad << :c; :c)]
+ ScratchPad.recorded.should == [:a, :b, :c]
+ end
+
+ it 'evaluates expressions left to right when assignment with a deeply nested #[]=' do
+ o = Object.new
+ def o.[]=(_, _) end
+ ScratchPad.record []
+
+ (ScratchPad << :ra; o)[(ScratchPad << :aa; :aa)],
+ ((ScratchPad << :rb; o)[(ScratchPad << :ab; :ab)],
+ ((ScratchPad << :rc; o)[(ScratchPad << :ac; :ac)], (ScratchPad << :rd; o)[(ScratchPad << :ad; :ad)]),
+ (ScratchPad << :re; o)[(ScratchPad << :ae; :ae)]),
+ (ScratchPad << :rf; o)[(ScratchPad << :af; :af)] = (ScratchPad << :value; :value)
+
+ ScratchPad.recorded.should == [:ra, :aa, :rb, :ab, :rc, :ac, :rd, :ad, :re, :ae, :rf, :af, :value]
+ end
+ end
+
+ ruby_version_is ''...'3.2' do
+ it 'evaluates expressions right to left when assignment with compounded constant' do
+ m = Module.new
+ ScratchPad.record []
+
+ (ScratchPad << :a; m)::A, (ScratchPad << :b; m)::B = (ScratchPad << :c; :c), (ScratchPad << :d; :d)
+ ScratchPad.recorded.should == [:c, :d, :a, :b]
+ end
+ end
+
+ ruby_version_is '3.2' do
+ it 'evaluates expressions left to right when assignment with compounded constant' do
+ m = Module.new
+ ScratchPad.record []
+
+ (ScratchPad << :a; m)::A, (ScratchPad << :b; m)::B = (ScratchPad << :c; :c), (ScratchPad << :d; :d)
+ ScratchPad.recorded.should == [:a, :b, :c, :d]
+ end
+
+ it 'evaluates expressions left to right when assignment with a nested compounded constant' do
+ m = Module.new
+ ScratchPad.record []
+
+ ((ScratchPad << :a; m)::A, foo), bar = [(ScratchPad << :b; :b)]
+ ScratchPad.recorded.should == [:a, :b]
+ end
+
+ it 'evaluates expressions left to right when assignment with deeply nested compounded constants' do
+ m = Module.new
+ ScratchPad.record []
+
+ (ScratchPad << :a; m)::A,
+ ((ScratchPad << :b; m)::B,
+ ((ScratchPad << :c; m)::C, (ScratchPad << :d; m)::D),
+ (ScratchPad << :e; m)::E),
+ (ScratchPad << :f; m)::F = (ScratchPad << :value; :value)
+
+ ScratchPad.recorded.should == [:a, :b, :c, :d, :e, :f, :value]
+ end
+ end
+ end
+
+ context 'when assignment with method call and receiver is self' do
+ it 'assigns values correctly when assignment with accessor' do
+ object = Object.new
+ class << object
+ attr_accessor :a, :b
+
+ def assign(v1, v2)
+ self.a, self.b = v1, v2
+ end
+ end
+
+ object.assign :v1, :v2
+ object.a.should == :v1
+ object.b.should == :v2
+ end
+
+ it 'evaluates expressions right to left when assignment with a nested accessor' do
+ object = Object.new
+ class << object
+ attr_accessor :a, :b
+
+ def assign(v1, v2)
+ (self.a, self.b), c = [v1, v2], nil
+ end
+ end
+
+ object.assign :v1, :v2
+ object.a.should == :v1
+ object.b.should == :v2
+ end
+
+ it 'assigns values correctly when assignment with a #[]=' do
+ object = Object.new
+ class << object
+ def []=(key, v)
+ @h ||= {}
+ @h[key] = v
+ end
+
+ def [](key)
+ (@h || {})[key]
+ end
+
+ def assign(k1, v1, k2, v2)
+ self[k1], self[k2] = v1, v2
+ end
+ end
+
+ object.assign :k1, :v1, :k2, :v2
+ object[:k1].should == :v1
+ object[:k2].should == :v2
+ end
+
+ it 'assigns values correctly when assignment with a nested #[]=' do
+ object = Object.new
+ class << object
+ def []=(key, v)
+ @h ||= {}
+ @h[key] = v
+ end
+
+ def [](key)
+ (@h || {})[key]
+ end
+
+ def assign(k1, v1, k2, v2)
+ (self[k1], self[k2]), c = [v1, v2], nil
+ end
+ end
+
+ object.assign :k1, :v1, :k2, :v2
+ object[:k1].should == :v1
+ object[:k2].should == :v2
+ end
+
+ it 'assigns values correctly when assignment with compounded constant' do
+ m = Module.new
+ m.module_exec do
+ self::A, self::B = :v1, :v2
+ end
+
+ m::A.should == :v1
+ m::B.should == :v2
+ end
+
+ it 'assigns values correctly when assignment with a nested compounded constant' do
+ m = Module.new
+ m.module_exec do
+ (self::A, self::B), c = [:v1, :v2], nil
+ end
+
+ m::A.should == :v1
+ m::B.should == :v2
+ end
+ end
+end
diff --git a/spec/ruby/language/block_spec.rb b/spec/ruby/language/block_spec.rb
index b2a3cc84c4..578d9cb3b0 100644
--- a/spec/ruby/language/block_spec.rb
+++ b/spec/ruby/language/block_spec.rb
@@ -40,80 +40,73 @@ describe "A block yielded a single" do
m([1, 2]) { |a=5, b, c, d| [a, b, c, d] }.should == [5, 1, 2, nil]
end
- it "assigns elements to required arguments when a keyword rest argument is present" do
- m([1, 2]) { |a, **k| [a, k] }.should == [1, {}]
+ it "assigns elements to pre arguments" do
+ m([1, 2]) { |a, b, c, d=5| [a, b, c, d] }.should == [1, 2, nil, 5]
end
- ruby_version_is ''..."3.0" do
- it "assigns elements to mixed argument types" do
- suppress_keyword_warning do
- result = m([1, 2, 3, {x: 9}]) { |a, b=5, *c, d, e: 2, **k| [a, b, c, d, e, k] }
- result.should == [1, 2, [], 3, 2, {x: 9}]
- end
- end
+ it "assigns elements to pre and post arguments" do
+ m([1 ]) { |a, b=5, c=6, d, e| [a, b, c, d, e] }.should == [1, 5, 6, nil, nil]
+ m([1, 2 ]) { |a, b=5, c=6, d, e| [a, b, c, d, e] }.should == [1, 5, 6, 2, nil]
+ m([1, 2, 3 ]) { |a, b=5, c=6, d, e| [a, b, c, d, e] }.should == [1, 5, 6, 2, 3]
+ m([1, 2, 3, 4 ]) { |a, b=5, c=6, d, e| [a, b, c, d, e] }.should == [1, 2, 6, 3, 4]
+ m([1, 2, 3, 4, 5 ]) { |a, b=5, c=6, d, e| [a, b, c, d, e] }.should == [1, 2, 3, 4, 5]
+ m([1, 2, 3, 4, 5, 6]) { |a, b=5, c=6, d, e| [a, b, c, d, e] }.should == [1, 2, 3, 4, 5]
+ end
- it "assigns symbol keys from a Hash to keyword arguments" do
- suppress_keyword_warning do
- result = m(["a" => 1, a: 10]) { |a=nil, **b| [a, b] }
- result.should == [{"a" => 1}, a: 10]
- end
+ it "assigns elements to pre and post arguments when *rest is present" do
+ m([1 ]) { |a, b=5, c=6, *d, e, f| [a, b, c, d, e, f] }.should == [1, 5, 6, [], nil, nil]
+ m([1, 2 ]) { |a, b=5, c=6, *d, e, f| [a, b, c, d, e, f] }.should == [1, 5, 6, [], 2, nil]
+ m([1, 2, 3 ]) { |a, b=5, c=6, *d, e, f| [a, b, c, d, e, f] }.should == [1, 5, 6, [], 2, 3]
+ m([1, 2, 3, 4 ]) { |a, b=5, c=6, *d, e, f| [a, b, c, d, e, f] }.should == [1, 2, 6, [], 3, 4]
+ m([1, 2, 3, 4, 5 ]) { |a, b=5, c=6, *d, e, f| [a, b, c, d, e, f] }.should == [1, 2, 3, [], 4, 5]
+ m([1, 2, 3, 4, 5, 6]) { |a, b=5, c=6, *d, e, f| [a, b, c, d, e, f] }.should == [1, 2, 3, [4], 5, 6]
+ end
+
+ ruby_version_is "3.2" do
+ it "does not autosplat single argument to required arguments when a keyword rest argument is present" do
+ m([1, 2]) { |a, **k| [a, k] }.should == [[1, 2], {}]
end
- it "assigns symbol keys from a Hash returned by #to_hash to keyword arguments" do
- suppress_keyword_warning do
- obj = mock("coerce block keyword arguments")
- obj.should_receive(:to_hash).and_return({"a" => 1, b: 2})
+ it "does not autosplat single argument to required arguments when keyword arguments are present" do
+ m([1, 2]) { |a, b: :b, c: :c| [a, b, c] }.should == [[1, 2], :b, :c]
+ end
- result = m([obj]) { |a=nil, **b| [a, b] }
- result.should == [{"a" => 1}, b: 2]
- end
+ it "raises error when required keyword arguments are present" do
+ -> {
+ m([1, 2]) { |a, b:, c:| [a, b, c] }
+ }.should raise_error(ArgumentError, "missing keywords: :b, :c")
end
end
- ruby_version_is "3.0" do
- it "assigns elements to mixed argument types" do
- result = m([1, 2, 3, {x: 9}]) { |a, b=5, *c, d, e: 2, **k| [a, b, c, d, e, k] }
- result.should == [1, 2, [3], {x: 9}, 2, {}]
+ ruby_version_is ''..."3.2" do
+ # https://bugs.ruby-lang.org/issues/18633
+ it "autosplats single argument to required arguments when a keyword rest argument is present" do
+ m([1, 2]) { |a, **k| [a, k] }.should == [1, {}]
end
- it "does not treat final Hash as keyword arguments and does not autosplat" do
- result = m(["a" => 1, a: 10]) { |a=nil, **b| [a, b] }
- result.should == [[{"a" => 1, a: 10}], {}]
+ it "autosplats single argument to required arguments when optional keyword arguments are present" do
+ m([1, 2]) { |a, b: :b, c: :c| [a, b, c] }.should == [1, :b, :c]
end
- it "does not call #to_hash on final argument to get keyword arguments and does not autosplat" do
- suppress_keyword_warning do
- obj = mock("coerce block keyword arguments")
- obj.should_not_receive(:to_hash)
-
- result = m([obj]) { |a=nil, **b| [a, b] }
- result.should == [[obj], {}]
- end
+ it "raises error when required keyword arguments are present" do
+ -> {
+ m([1, 2]) { |a, b:, c:| [a, b, c] }
+ }.should raise_error(ArgumentError, "missing keywords: :b, :c")
end
end
- ruby_version_is ""..."2.7" do
- it "calls #to_hash on the argument and uses resulting hash as first argument when optional argument and keyword argument accepted" do
- obj = mock("coerce block keyword arguments")
- obj.should_receive(:to_hash).and_return({"a" => 1, "b" => 2})
-
- result = m([obj]) { |a=nil, **b| [a, b] }
- result.should == [{"a" => 1, "b" => 2}, {}]
- end
+ it "assigns elements to mixed argument types" do
+ result = m([1, 2, 3, {x: 9}]) { |a, b=5, *c, d, e: 2, **k| [a, b, c, d, e, k] }
+ result.should == [1, 2, [3], {x: 9}, 2, {}]
end
- ruby_version_is "2.7"...'3.0' do
- it "calls #to_hash on the argument but ignores result when optional argument and keyword argument accepted" do
- obj = mock("coerce block keyword arguments")
- obj.should_receive(:to_hash).and_return({"a" => 1, "b" => 2})
-
- result = m([obj]) { |a=nil, **b| [a, b] }
- result.should == [obj, {}]
- end
+ it "does not treat final Hash as keyword arguments and does not autosplat" do
+ result = m(["a" => 1, a: 10]) { |a=nil, **b| [a, b] }
+ result.should == [[{"a" => 1, a: 10}], {}]
end
- ruby_version_is "3.0" do
- it "does not call #to_hash on the argument when optional argument and keyword argument accepted and does not autosplat" do
+ it "does not call #to_hash on final argument to get keyword arguments and does not autosplat" do
+ suppress_keyword_warning do
obj = mock("coerce block keyword arguments")
obj.should_not_receive(:to_hash)
@@ -122,102 +115,42 @@ describe "A block yielded a single" do
end
end
- describe "when non-symbol keys are in a keyword arguments Hash" do
- ruby_version_is ""..."3.0" do
- it "separates non-symbol keys and symbol keys" do
- suppress_keyword_warning do
- result = m(["a" => 10, b: 2]) { |a=nil, **b| [a, b] }
- result.should == [{"a" => 10}, {b: 2}]
- end
- end
- end
- ruby_version_is "3.0" do
- it "does not separate non-symbol keys and symbol keys and does not autosplat" do
- suppress_keyword_warning do
- result = m(["a" => 10, b: 2]) { |a=nil, **b| [a, b] }
- result.should == [[{"a" => 10, b: 2}], {}]
- end
- end
- end
- end
-
- ruby_version_is ""..."3.0" do
- it "does not treat hashes with string keys as keyword arguments" do
- result = m(["a" => 10]) { |a = nil, **b| [a, b] }
- result.should == [{"a" => 10}, {}]
- end
- end
+ it "does not call #to_hash on the argument when optional argument and keyword argument accepted and does not autosplat" do
+ obj = mock("coerce block keyword arguments")
+ obj.should_not_receive(:to_hash)
- ruby_version_is "3.0" do
- it "does not treat hashes with string keys as keyword arguments and does not autosplat" do
- result = m(["a" => 10]) { |a = nil, **b| [a, b] }
- result.should == [[{"a" => 10}], {}]
- end
+ result = m([obj]) { |a=nil, **b| [a, b] }
+ result.should == [[obj], {}]
end
- ruby_version_is ''...'3.0' do
- it "calls #to_hash on the last element if keyword arguments are present" do
- suppress_keyword_warning do
- obj = mock("destructure block keyword arguments")
- obj.should_receive(:to_hash).and_return({x: 9})
-
- result = m([1, 2, 3, obj]) { |a, *b, c, **k| [a, b, c, k] }
- result.should == [1, [2], 3, {x: 9}]
- end
- end
-
- it "assigns the last element to a non-keyword argument if #to_hash returns nil" do
- suppress_keyword_warning do
- obj = mock("destructure block keyword arguments")
- obj.should_receive(:to_hash).and_return(nil)
-
- result = m([1, 2, 3, obj]) { |a, *b, c, **k| [a, b, c, k] }
- result.should == [1, [2, 3], obj, {}]
- end
- end
-
- it "calls #to_hash on the last element when there are more arguments than parameters" do
+ describe "when non-symbol keys are in a keyword arguments Hash" do
+ it "does not separate non-symbol keys and symbol keys and does not autosplat" do
suppress_keyword_warning do
- x = mock("destructure matching block keyword argument")
- x.should_receive(:to_hash).and_return({x: 9})
-
- result = m([1, 2, 3, {y: 9}, 4, 5, x]) { |a, b=5, c, **k| [a, b, c, k] }
- result.should == [1, 2, 3, {x: 9}]
+ result = m(["a" => 10, b: 2]) { |a=nil, **b| [a, b] }
+ result.should == [[{"a" => 10, b: 2}], {}]
end
end
+ end
- it "raises a TypeError if #to_hash does not return a Hash" do
- obj = mock("destructure block keyword arguments")
- obj.should_receive(:to_hash).and_return(1)
-
- -> { m([1, 2, 3, obj]) { |a, *b, c, **k| } }.should raise_error(TypeError)
- end
-
- it "raises the error raised inside #to_hash" do
- obj = mock("destructure block keyword arguments")
- error = RuntimeError.new("error while converting to a hash")
- obj.should_receive(:to_hash).and_raise(error)
-
- -> { m([1, 2, 3, obj]) { |a, *b, c, **k| } }.should raise_error(error)
- end
+ it "does not treat hashes with string keys as keyword arguments and does not autosplat" do
+ result = m(["a" => 10]) { |a = nil, **b| [a, b] }
+ result.should == [[{"a" => 10}], {}]
end
- ruby_version_is '3.0' do
- it "does not call #to_hash on the last element if keyword arguments are present" do
- obj = mock("destructure block keyword arguments")
- obj.should_not_receive(:to_hash)
+ it "does not call #to_hash on the last element if keyword arguments are present" do
+ obj = mock("destructure block keyword arguments")
+ obj.should_not_receive(:to_hash)
- result = m([1, 2, 3, obj]) { |a, *b, c, **k| [a, b, c, k] }
- result.should == [1, [2, 3], obj, {}]
- end
+ result = m([1, 2, 3, obj]) { |a, *b, c, **k| [a, b, c, k] }
+ result.should == [1, [2, 3], obj, {}]
+ end
- it "does not call #to_hash on the last element when there are more arguments than parameters" do
- x = mock("destructure matching block keyword argument")
- x.should_not_receive(:to_hash)
+ it "does not call #to_hash on the last element when there are more arguments than parameters" do
+ x = mock("destructure matching block keyword argument")
+ x.should_not_receive(:to_hash)
- result = m([1, 2, 3, {y: 9}, 4, 5, x]) { |a, b=5, c, **k| [a, b, c, k] }
- result.should == [1, 2, 3, {}]
- end
+ result = m([1, 2, 3, {y: 9}, 4, 5, x]) { |a, b=5, c, **k| [a, b, c, k] }
+ result.should == [1, 2, 3, {}]
end
it "does not call #to_ary on the Array" do
@@ -264,12 +197,55 @@ describe "A block yielded a single" do
m(obj) { |a, b, c| [a, b, c] }.should == [obj, nil, nil]
end
+ it "receives the object if it does not respond to #to_ary" do
+ obj = Object.new
+
+ m(obj) { |a, b, c| [a, b, c] }.should == [obj, nil, nil]
+ end
+
+ it "calls #respond_to? to check if object has method #to_ary" do
+ obj = mock("destructure block arguments")
+ obj.should_receive(:respond_to?).with(:to_ary, true).and_return(true)
+ obj.should_receive(:to_ary).and_return([1, 2])
+
+ m(obj) { |a, b, c| [a, b, c] }.should == [1, 2, nil]
+ end
+
+ it "receives the object if it does not respond to #respond_to?" do
+ obj = BasicObject.new
+
+ m(obj) { |a, b, c| [a, b, c] }.should == [obj, nil, nil]
+ end
+
+ it "calls #to_ary on the object when it is defined dynamically" do
+ obj = Object.new
+ def obj.method_missing(name, *args, &block)
+ if name == :to_ary
+ [1, 2]
+ else
+ super
+ end
+ end
+ def obj.respond_to_missing?(name, include_private)
+ name == :to_ary
+ end
+
+ m(obj) { |a, b, c| [a, b, c] }.should == [1, 2, nil]
+ end
+
it "raises a TypeError if #to_ary does not return an Array" do
obj = mock("destructure block arguments")
obj.should_receive(:to_ary).and_return(1)
-> { m(obj) { |a, b| } }.should raise_error(TypeError)
end
+
+ it "raises error transparently if #to_ary raises error on its own" do
+ obj = Object.new
+ def obj.to_ary; raise "Exception raised in #to_ary" end
+
+ -> { m(obj) { |a, b| } }.should raise_error(RuntimeError, "Exception raised in #to_ary")
+ end
end
end
@@ -434,7 +410,6 @@ describe "A block" do
-> { @y.s(obj) { |a, b| } }.should raise_error(ZeroDivisionError)
end
-
end
describe "taking |a, *b| arguments" do
@@ -767,6 +742,42 @@ describe "A block" do
eval("Proc.new { |_,_| }").should be_an_instance_of(Proc)
end
end
+
+ describe 'pre and post parameters' do
+ it "assigns nil to unassigned required arguments" do
+ proc { |a, *b, c, d| [a, b, c, d] }.call(1, 2).should == [1, [], 2, nil]
+ end
+
+ it "assigns elements to optional arguments" do
+ proc { |a=5, b=4, c=3| [a, b, c] }.call(1, 2).should == [1, 2, 3]
+ end
+
+ it "assigns elements to post arguments" do
+ proc { |a=5, b, c, d| [a, b, c, d] }.call(1, 2).should == [5, 1, 2, nil]
+ end
+
+ it "assigns elements to pre arguments" do
+ proc { |a, b, c, d=5| [a, b, c, d] }.call(1, 2).should == [1, 2, nil, 5]
+ end
+
+ it "assigns elements to pre and post arguments" do
+ proc { |a, b=5, c=6, d, e| [a, b, c, d, e] }.call(1 ).should == [1, 5, 6, nil, nil]
+ proc { |a, b=5, c=6, d, e| [a, b, c, d, e] }.call(1, 2 ).should == [1, 5, 6, 2, nil]
+ proc { |a, b=5, c=6, d, e| [a, b, c, d, e] }.call(1, 2, 3 ).should == [1, 5, 6, 2, 3]
+ proc { |a, b=5, c=6, d, e| [a, b, c, d, e] }.call(1, 2, 3, 4 ).should == [1, 2, 6, 3, 4]
+ proc { |a, b=5, c=6, d, e| [a, b, c, d, e] }.call(1, 2, 3, 4, 5 ).should == [1, 2, 3, 4, 5]
+ proc { |a, b=5, c=6, d, e| [a, b, c, d, e] }.call(1, 2, 3, 4, 5, 6).should == [1, 2, 3, 4, 5]
+ end
+
+ it "assigns elements to pre and post arguments when *rest is present" do
+ proc { |a, b=5, c=6, *d, e, f| [a, b, c, d, e, f] }.call(1 ).should == [1, 5, 6, [], nil, nil]
+ proc { |a, b=5, c=6, *d, e, f| [a, b, c, d, e, f] }.call(1, 2 ).should == [1, 5, 6, [], 2, nil]
+ proc { |a, b=5, c=6, *d, e, f| [a, b, c, d, e, f] }.call(1, 2, 3 ).should == [1, 5, 6, [], 2, 3]
+ proc { |a, b=5, c=6, *d, e, f| [a, b, c, d, e, f] }.call(1, 2, 3, 4 ).should == [1, 2, 6, [], 3, 4]
+ proc { |a, b=5, c=6, *d, e, f| [a, b, c, d, e, f] }.call(1, 2, 3, 4, 5 ).should == [1, 2, 3, [], 4, 5]
+ proc { |a, b=5, c=6, *d, e, f| [a, b, c, d, e, f] }.call(1, 2, 3, 4, 5, 6).should == [1, 2, 3, [4], 5, 6]
+ end
+ end
end
describe "Block-local variables" do
@@ -949,38 +960,18 @@ describe "Post-args" do
end
describe "with a circular argument reference" do
- ruby_version_is ''...'2.7' do
- it "warns and uses a nil value when there is an existing local variable with same name" do
- a = 1
- -> {
- @proc = eval "proc { |a=a| a }"
- }.should complain(/circular argument reference/)
- @proc.call.should == nil
- end
-
- it "warns and uses a nil value when there is an existing method with same name" do
- def a; 1; end
- -> {
- @proc = eval "proc { |a=a| a }"
- }.should complain(/circular argument reference/)
- @proc.call.should == nil
- end
+ it "raises a SyntaxError if using an existing local with the same name as the argument" do
+ a = 1
+ -> {
+ @proc = eval "proc { |a=a| a }"
+ }.should raise_error(SyntaxError)
end
- ruby_version_is '2.7' do
- it "raises a SyntaxError if using an existing local with the same name as the argument" do
- a = 1
- -> {
- @proc = eval "proc { |a=a| a }"
- }.should raise_error(SyntaxError)
- end
-
- it "raises a SyntaxError if there is an existing method with the same name as the argument" do
- def a; 1; end
- -> {
- @proc = eval "proc { |a=a| a }"
- }.should raise_error(SyntaxError)
- end
+ it "raises a SyntaxError if there is an existing method with the same name as the argument" do
+ def a; 1; end
+ -> {
+ @proc = eval "proc { |a=a| a }"
+ }.should raise_error(SyntaxError)
end
it "calls an existing method with the same name as the argument if explicitly using ()" do
@@ -1004,3 +995,77 @@ describe "Post-args" do
end
end
end
+
+describe "Anonymous block forwarding" do
+ ruby_version_is "3.1" do
+ it "forwards blocks to other method that formally declares anonymous block" do
+ eval <<-EOF
+ def b(&); c(&) end
+ def c(&); yield :non_null end
+ EOF
+
+ b { |c| c }.should == :non_null
+ end
+
+ it "requires the anonymous block parameter to be declared if directly passing a block" do
+ -> { eval "def a; b(&); end; def b; end" }.should raise_error(SyntaxError)
+ end
+
+ it "works when it's the only declared parameter" do
+ eval <<-EOF
+ def inner; yield end
+ def block_only(&); inner(&) end
+ EOF
+
+ block_only { 1 }.should == 1
+ end
+
+ it "works alongside positional parameters" do
+ eval <<-EOF
+ def inner; yield end
+ def pos(arg1, &); inner(&) end
+ EOF
+
+ pos(:a) { 1 }.should == 1
+ end
+
+ it "works alongside positional arguments and splatted keyword arguments" do
+ eval <<-EOF
+ def inner; yield end
+ def pos_kwrest(arg1, **kw, &); inner(&) end
+ EOF
+
+ pos_kwrest(:a, arg: 3) { 1 }.should == 1
+ end
+
+ it "works alongside positional arguments and disallowed keyword arguments" do
+ eval <<-EOF
+ def inner; yield end
+ def no_kw(arg1, **nil, &); inner(&) end
+ EOF
+
+ no_kw(:a) { 1 }.should == 1
+ end
+ end
+
+ ruby_version_is "3.2" do
+ it "works alongside explicit keyword arguments" do
+ eval <<-EOF
+ def inner; yield end
+ def rest_kw(*a, kwarg: 1, &); inner(&) end
+ def kw(kwarg: 1, &); inner(&) end
+ def pos_kw_kwrest(arg1, kwarg: 1, **kw, &); inner(&) end
+ def pos_rkw(arg1, kwarg1:, &); inner(&) end
+ def all(arg1, arg2, *rest, post1, post2, kw1: 1, kw2: 2, okw1:, okw2:, &); inner(&) end
+ def all_kwrest(arg1, arg2, *rest, post1, post2, kw1: 1, kw2: 2, okw1:, okw2:, **kw, &); inner(&) end
+ EOF
+
+ rest_kw { 1 }.should == 1
+ kw { 1 }.should == 1
+ pos_kw_kwrest(:a) { 1 }.should == 1
+ pos_rkw(:a, kwarg1: 3) { 1 }.should == 1
+ all(:a, :b, :c, :d, :e, okw1: 'x', okw2: 'y') { 1 }.should == 1
+ all_kwrest(:a, :b, :c, :d, :e, okw1: 'x', okw2: 'y') { 1 }.should == 1
+ end
+ end
+end
diff --git a/spec/ruby/language/break_spec.rb b/spec/ruby/language/break_spec.rb
index 627cb4a071..e725e77e80 100644
--- a/spec/ruby/language/break_spec.rb
+++ b/spec/ruby/language/break_spec.rb
@@ -372,7 +372,7 @@ describe "Executing break from within a block" do
end.should_not raise_error
end
- it "raises LocalJumpError when converted into a proc during a a super call" do
+ it "raises LocalJumpError when converted into a proc during a super call" do
cls1 = Class.new { def foo(&b); b; end }
cls2 = Class.new(cls1) { def foo; super { break 1 }.call; end }
diff --git a/spec/ruby/language/case_spec.rb b/spec/ruby/language/case_spec.rb
index bf06803764..3262f09dd5 100644
--- a/spec/ruby/language/case_spec.rb
+++ b/spec/ruby/language/case_spec.rb
@@ -103,7 +103,7 @@ describe "The 'case'-construct" do
$1.should == "42"
end
- it "tests with a regexp interpolated within another regexp" do
+ it "tests with a string interpolated in a regexp" do
digits = '\d+'
case "foo44"
when /oo(#{digits})/
@@ -116,7 +116,7 @@ describe "The 'case'-construct" do
$1.should == "44"
end
- it "tests with a string interpolated in a regexp" do
+ it "tests with a regexp interpolated within another regexp" do
digits_regexp = /\d+/
case "foo43"
when /oo(#{digits_regexp})/
@@ -329,49 +329,6 @@ describe "The 'case'-construct" do
100
end.should == 100
end
-end
-
-describe "The 'case'-construct with no target expression" do
- it "evaluates the body of the first clause when at least one of its condition expressions is true" do
- case
- when true, false; 'foo'
- end.should == 'foo'
- end
-
- it "evaluates the body of the first when clause that is not false/nil" do
- case
- when false; 'foo'
- when 2; 'bar'
- when 1 == 1; 'baz'
- end.should == 'bar'
-
- case
- when false; 'foo'
- when nil; 'foo'
- when 1 == 1; 'bar'
- end.should == 'bar'
- end
-
- it "evaluates the body of the else clause if all when clauses are false/nil" do
- case
- when false; 'foo'
- when nil; 'foo'
- when 1 == 2; 'bar'
- else 'baz'
- end.should == 'baz'
- end
-
- it "evaluates multiple conditional expressions as a boolean disjunction" do
- case
- when true, false; 'foo'
- else 'bar'
- end.should == 'foo'
-
- case
- when false, true; 'foo'
- else 'bar'
- end.should == 'foo'
- end
it "evaluates true as only 'true' when true is the first clause" do
case 1
@@ -434,6 +391,87 @@ describe "The 'case'-construct with no target expression" do
end.should == :called
end
+ it "only matches last value in complex expressions within ()" do
+ case 'a'
+ when ('a'; 'b')
+ :wrong_called
+ when ('b'; 'a')
+ :called
+ end.should == :called
+ end
+
+ it "supports declaring variables in the case target expression" do
+ def test(v)
+ case new_variable_in_expression = v
+ when true
+ # This extra block is a test that `new_variable_in_expression` is declared outside of it and not inside
+ self.then { new_variable_in_expression }
+ else
+ # Same
+ self.then { new_variable_in_expression.casecmp?("foo") }
+ end
+ end
+
+ self.test("bar").should == false
+ self.test(true).should == true
+ end
+
+ it "warns if there are identical when clauses" do
+ -> {
+ eval <<~RUBY
+ case 1
+ when 2
+ :foo
+ when 2
+ :bar
+ end
+ RUBY
+ }.should complain(/warning: duplicated .when' clause with line \d+ is ignored/, verbose: true)
+ end
+end
+
+describe "The 'case'-construct with no target expression" do
+ it "evaluates the body of the first clause when at least one of its condition expressions is true" do
+ case
+ when true, false; 'foo'
+ end.should == 'foo'
+ end
+
+ it "evaluates the body of the first when clause that is not false/nil" do
+ case
+ when false; 'foo'
+ when 2; 'bar'
+ when 1 == 1; 'baz'
+ end.should == 'bar'
+
+ case
+ when false; 'foo'
+ when nil; 'foo'
+ when 1 == 1; 'bar'
+ end.should == 'bar'
+ end
+
+ it "evaluates the body of the else clause if all when clauses are false/nil" do
+ case
+ when false; 'foo'
+ when nil; 'foo'
+ when 1 == 2; 'bar'
+ else 'baz'
+ end.should == 'baz'
+ end
+
+ it "evaluates multiple conditional expressions as a boolean disjunction" do
+ case
+ when true, false; 'foo'
+ else 'bar'
+ end.should == 'foo'
+
+ case
+ when false, true; 'foo'
+ else 'bar'
+ end.should == 'foo'
+ end
+
# Homogeneous cases are often optimized to avoid === using a jump table, and should be tested separately.
# See https://github.com/jruby/jruby/issues/6440
it "handles homogeneous cases" do
@@ -442,4 +480,13 @@ describe "The 'case'-construct with no target expression" do
when 2; 'bar'
end.should == 'foo'
end
+
+ it "expands arrays to lists of values" do
+ case
+ when *[false]
+ "foo"
+ when *[true]
+ "bar"
+ end.should == "bar"
+ end
end
diff --git a/spec/ruby/language/class_spec.rb b/spec/ruby/language/class_spec.rb
index 877895bf15..eab3cd0651 100644
--- a/spec/ruby/language/class_spec.rb
+++ b/spec/ruby/language/class_spec.rb
@@ -308,20 +308,10 @@ describe "A class definition extending an object (sclass)" do
-> { class TestClass < BasicObject.new; end }.should raise_error(TypeError, error_msg)
end
- ruby_version_is ""..."3.0" do
- it "allows accessing the block of the original scope" do
- suppress_warning do
- ClassSpecs.sclass_with_block { 123 }.should == 123
- end
- end
- end
-
- ruby_version_is "3.0" do
- it "does not allow accessing the block of the original scope" do
- -> {
- ClassSpecs.sclass_with_block { 123 }
- }.should raise_error(SyntaxError)
- end
+ it "does not allow accessing the block of the original scope" do
+ -> {
+ ClassSpecs.sclass_with_block { 123 }
+ }.should raise_error(SyntaxError)
end
it "can use return to cause the enclosing method to return" do
diff --git a/spec/ruby/language/class_variable_spec.rb b/spec/ruby/language/class_variable_spec.rb
index f98deaa081..a26a3fb8de 100644
--- a/spec/ruby/language/class_variable_spec.rb
+++ b/spec/ruby/language/class_variable_spec.rb
@@ -83,34 +83,32 @@ describe 'A class variable definition' do
end
end
-ruby_version_is "3.0" do
- describe 'Accessing a class variable' do
- it "raises a RuntimeError when accessed from the toplevel scope (not in some module or class)" do
- -> {
- eval "@@cvar_toplevel1"
- }.should raise_error(RuntimeError, 'class variable access from toplevel')
- -> {
- eval "@@cvar_toplevel2 = 2"
- }.should raise_error(RuntimeError, 'class variable access from toplevel')
- end
-
- it "does not raise an error when checking if defined from the toplevel scope" do
- -> {
- eval "defined?(@@cvar_toplevel1)"
- }.should_not raise_error
- end
-
- it "raises a RuntimeError when a class variable is overtaken in an ancestor class" do
- parent = Class.new()
- subclass = Class.new(parent)
- subclass.class_variable_set(:@@cvar_overtaken, :subclass)
- parent.class_variable_set(:@@cvar_overtaken, :parent)
-
- -> {
- subclass.class_variable_get(:@@cvar_overtaken)
- }.should raise_error(RuntimeError, /class variable @@cvar_overtaken of .+ is overtaken by .+/)
-
- parent.class_variable_get(:@@cvar_overtaken).should == :parent
- end
+describe 'Accessing a class variable' do
+ it "raises a RuntimeError when accessed from the toplevel scope (not in some module or class)" do
+ -> {
+ eval "@@cvar_toplevel1"
+ }.should raise_error(RuntimeError, 'class variable access from toplevel')
+ -> {
+ eval "@@cvar_toplevel2 = 2"
+ }.should raise_error(RuntimeError, 'class variable access from toplevel')
+ end
+
+ it "does not raise an error when checking if defined from the toplevel scope" do
+ -> {
+ eval "defined?(@@cvar_toplevel1)"
+ }.should_not raise_error
+ end
+
+ it "raises a RuntimeError when a class variable is overtaken in an ancestor class" do
+ parent = Class.new()
+ subclass = Class.new(parent)
+ subclass.class_variable_set(:@@cvar_overtaken, :subclass)
+ parent.class_variable_set(:@@cvar_overtaken, :parent)
+
+ -> {
+ subclass.class_variable_get(:@@cvar_overtaken)
+ }.should raise_error(RuntimeError, /class variable @@cvar_overtaken of .+ is overtaken by .+/)
+
+ parent.class_variable_get(:@@cvar_overtaken).should == :parent
end
end
diff --git a/spec/ruby/language/comment_spec.rb b/spec/ruby/language/comment_spec.rb
index 690e844dc0..dd788e681c 100644
--- a/spec/ruby/language/comment_spec.rb
+++ b/spec/ruby/language/comment_spec.rb
@@ -1,15 +1,13 @@
require_relative '../spec_helper'
describe "The comment" do
- ruby_version_is "2.7" do
- it "can be placed between fluent dot now" do
- code = <<~CODE
- 10
- # some comment
- .to_s
- CODE
+ it "can be placed between fluent dot now" do
+ code = <<~CODE
+ 10
+ # some comment
+ .to_s
+ CODE
- eval(code).should == '10'
- end
+ eval(code).should == '10'
end
end
diff --git a/spec/ruby/language/constants_spec.rb b/spec/ruby/language/constants_spec.rb
index 8586e46158..08c534487e 100644
--- a/spec/ruby/language/constants_spec.rb
+++ b/spec/ruby/language/constants_spec.rb
@@ -170,34 +170,32 @@ describe "Literal (A::X) constant resolution" do
-> { ConstantSpecs::ParentA::CS_CONSTX }.should raise_error(NameError)
end
- ruby_version_is "3.0" do
- it "uses the module or class #name to craft the error message" do
- mod = Module.new do
- def self.name
- "ModuleName"
- end
-
- def self.inspect
- "<unusable info>"
- end
+ it "uses the module or class #name to craft the error message" do
+ mod = Module.new do
+ def self.name
+ "ModuleName"
end
- -> { mod::DOES_NOT_EXIST }.should raise_error(NameError, /uninitialized constant ModuleName::DOES_NOT_EXIST/)
+ def self.inspect
+ "<unusable info>"
+ end
end
- it "uses the module or class #inspect to craft the error message if they are anonymous" do
- mod = Module.new do
- def self.name
- nil
- end
+ -> { mod::DOES_NOT_EXIST }.should raise_error(NameError, /uninitialized constant ModuleName::DOES_NOT_EXIST/)
+ end
- def self.inspect
- "<unusable info>"
- end
+ it "uses the module or class #inspect to craft the error message if they are anonymous" do
+ mod = Module.new do
+ def self.name
+ nil
end
- -> { mod::DOES_NOT_EXIST }.should raise_error(NameError, /uninitialized constant <unusable info>::DOES_NOT_EXIST/)
+ def self.inspect
+ "<unusable info>"
+ end
end
+
+ -> { mod::DOES_NOT_EXIST }.should raise_error(NameError, /uninitialized constant <unusable info>::DOES_NOT_EXIST/)
end
it "sends #const_missing to the original class or module scope" do
diff --git a/spec/ruby/language/def_spec.rb b/spec/ruby/language/def_spec.rb
index d72f8fa888..42e721c68c 100644
--- a/spec/ruby/language/def_spec.rb
+++ b/spec/ruby/language/def_spec.rb
@@ -197,32 +197,15 @@ describe "An instance method with a default argument" do
foo(2,3,3).should == [2,3,[3]]
end
- ruby_version_is ''...'2.7' do
- it "warns and uses a nil value when there is an existing local method with same name" do
- def bar
- 1
- end
- -> {
- eval "def foo(bar = bar)
- bar
- end"
- }.should complain(/circular argument reference/)
- foo.should == nil
- foo(2).should == 2
- end
- end
-
- ruby_version_is '2.7' do
- it "raises a SyntaxError when there is an existing method with the same name as the local variable" do
- def bar
- 1
- end
- -> {
- eval "def foo(bar = bar)
- bar
- end"
- }.should raise_error(SyntaxError)
+ it "raises a SyntaxError when there is an existing method with the same name as the local variable" do
+ def bar
+ 1
end
+ -> {
+ eval "def foo(bar = bar)
+ bar
+ end"
+ }.should raise_error(SyntaxError)
end
it "calls a method with the same name as the local when explicitly using ()" do
@@ -255,7 +238,7 @@ describe "A singleton method definition" do
end
it "can be declared for a global variable" do
- $__a__ = "hi"
+ $__a__ = +"hi"
def $__a__.foo
7
end
diff --git a/spec/ruby/language/defined_spec.rb b/spec/ruby/language/defined_spec.rb
index 38345c3727..34408c0190 100644
--- a/spec/ruby/language/defined_spec.rb
+++ b/spec/ruby/language/defined_spec.rb
@@ -48,6 +48,20 @@ describe "The defined? keyword for literals" do
end
describe "The defined? keyword when called with a method name" do
+ before :each do
+ ScratchPad.clear
+ end
+
+ it "does not call the method" do
+ defined?(DefinedSpecs.side_effects).should == "method"
+ ScratchPad.recorded.should != :defined_specs_side_effects
+ end
+
+ it "does not execute the arguments" do
+ defined?(DefinedSpecs.any_args(DefinedSpecs.side_effects)).should == "method"
+ ScratchPad.recorded.should != :defined_specs_side_effects
+ end
+
describe "without a receiver" do
it "returns 'method' if the method is defined" do
ret = defined?(puts)
@@ -102,6 +116,11 @@ describe "The defined? keyword when called with a method name" do
defined?(obj.a_defined_method).should == "method"
end
+ it "returns 'method' for []=" do
+ a = []
+ defined?(a[0] = 1).should == "method"
+ end
+
it "returns nil if the method is not defined" do
obj = DefinedSpecs::Basic.new
defined?(obj.an_undefined_method).should be_nil
@@ -166,6 +185,32 @@ describe "The defined? keyword when called with a method name" do
ScratchPad.recorded.should == :defined_specs_fixnum_method
end
end
+
+ describe "having a throw in the receiver" do
+ it "escapes defined? and performs the throw semantics as normal" do
+ defined_returned = false
+ catch(:out) {
+ # NOTE: defined? behaves differently if it is called in a void context, see below
+ defined?(throw(:out, 42).foo).should == :unreachable
+ defined_returned = true
+ }.should == 42
+ defined_returned.should == false
+ end
+ end
+
+ describe "in a void context" do
+ it "does not execute the receiver" do
+ ScratchPad.record :not_executed
+ defined?(DefinedSpecs.side_effects / 2)
+ ScratchPad.recorded.should == :not_executed
+ end
+
+ it "warns about the void context when parsing it" do
+ -> {
+ eval "defined?(DefinedSpecs.side_effects / 2); 42"
+ }.should complain(/warning: possibly useless use of defined\? in void context/, verbose: true)
+ end
+ end
end
describe "The defined? keyword for an expression" do
@@ -191,6 +236,14 @@ describe "The defined? keyword for an expression" do
defined?(@@defined_specs_x = 2).should == "assignment"
end
+ it "returns 'assignment' for assigning a constant" do
+ defined?(A = 2).should == "assignment"
+ end
+
+ it "returns 'assignment' for assigning a fully qualified constant" do
+ defined?(Object::A = 2).should == "assignment"
+ end
+
it "returns 'assignment' for assigning multiple variables" do
defined?((a, b = 1, 2)).should == "assignment"
end
@@ -208,7 +261,27 @@ describe "The defined? keyword for an expression" do
end
it "returns 'assignment' for an expression with '+='" do
- defined?(x += 2).should == "assignment"
+ defined?(a += 1).should == "assignment"
+ defined?(@a += 1).should == "assignment"
+ defined?(@@a += 1).should == "assignment"
+ defined?($a += 1).should == "assignment"
+ defined?(A += 1).should == "assignment"
+ # fully qualified constant check is moved out into a separate test case
+ defined?(a.b += 1).should == "assignment"
+ defined?(a[:b] += 1).should == "assignment"
+ end
+
+ # https://bugs.ruby-lang.org/issues/20111
+ ruby_version_is ""..."3.4" do
+ it "returns 'expression' for an assigning a fully qualified constant with '+='" do
+ defined?(Object::A += 1).should == "expression"
+ end
+ end
+
+ ruby_version_is "3.4" do
+ it "returns 'assignment' for an assigning a fully qualified constant with '+='" do
+ defined?(Object::A += 1).should == "assignment"
+ end
end
it "returns 'assignment' for an expression with '*='" do
@@ -239,12 +312,90 @@ describe "The defined? keyword for an expression" do
defined?(x >>= 2).should == "assignment"
end
- it "returns 'assignment' for an expression with '||='" do
- defined?(x ||= 2).should == "assignment"
+ context "||=" do
+ it "returns 'assignment' for assigning a local variable with '||='" do
+ defined?(a ||= true).should == "assignment"
+ end
+
+ it "returns 'assignment' for assigning an instance variable with '||='" do
+ defined?(@a ||= true).should == "assignment"
+ end
+
+ it "returns 'assignment' for assigning a class variable with '||='" do
+ defined?(@@a ||= true).should == "assignment"
+ end
+
+ it "returns 'assignment' for assigning a global variable with '||='" do
+ defined?($a ||= true).should == "assignment"
+ end
+
+ it "returns 'assignment' for assigning a constant with '||='" do
+ defined?(A ||= true).should == "assignment"
+ end
+
+ # https://bugs.ruby-lang.org/issues/20111
+ ruby_version_is ""..."3.4" do
+ it "returns 'expression' for assigning a fully qualified constant with '||='" do
+ defined?(Object::A ||= true).should == "expression"
+ end
+ end
+
+ ruby_version_is "3.4" do
+ it "returns 'assignment' for assigning a fully qualified constant with '||='" do
+ defined?(Object::A ||= true).should == "assignment"
+ end
+ end
+
+ it "returns 'assignment' for assigning an attribute with '||='" do
+ defined?(a.b ||= true).should == "assignment"
+ end
+
+ it "returns 'assignment' for assigning a referenced element with '||='" do
+ defined?(a[:b] ||= true).should == "assignment"
+ end
end
- it "returns 'assignment' for an expression with '&&='" do
- defined?(x &&= 2).should == "assignment"
+ context "&&=" do
+ it "returns 'assignment' for assigning a local variable with '&&='" do
+ defined?(a &&= true).should == "assignment"
+ end
+
+ it "returns 'assignment' for assigning an instance variable with '&&='" do
+ defined?(@a &&= true).should == "assignment"
+ end
+
+ it "returns 'assignment' for assigning a class variable with '&&='" do
+ defined?(@@a &&= true).should == "assignment"
+ end
+
+ it "returns 'assignment' for assigning a global variable with '&&='" do
+ defined?($a &&= true).should == "assignment"
+ end
+
+ it "returns 'assignment' for assigning a constant with '&&='" do
+ defined?(A &&= true).should == "assignment"
+ end
+
+ # https://bugs.ruby-lang.org/issues/20111
+ ruby_version_is ""..."3.4" do
+ it "returns 'expression' for assigning a fully qualified constant with '&&='" do
+ defined?(Object::A &&= true).should == "expression"
+ end
+ end
+
+ ruby_version_is "3.4" do
+ it "returns 'assignment' for assigning a fully qualified constant with '&&='" do
+ defined?(Object::A &&= true).should == "assignment"
+ end
+ end
+
+ it "returns 'assignment' for assigning an attribute with '&&='" do
+ defined?(a.b &&= true).should == "assignment"
+ end
+
+ it "returns 'assignment' for assigning a referenced element with '&&='" do
+ defined?(a[:b] &&= true).should == "assignment"
+ end
end
it "returns 'assignment' for an expression with '**='" do
diff --git a/spec/ruby/language/delegation_spec.rb b/spec/ruby/language/delegation_spec.rb
index 8e4183cbcc..d780506421 100644
--- a/spec/ruby/language/delegation_spec.rb
+++ b/spec/ruby/language/delegation_spec.rb
@@ -1,68 +1,93 @@
require_relative '../spec_helper'
require_relative 'fixtures/delegation'
-ruby_version_is "2.7" do
- describe "delegation with def(...)" do
- it "delegates rest and kwargs" do
- a = Class.new(DelegationSpecs::Target)
+describe "delegation with def(...)" do
+ it "delegates rest and kwargs" do
+ a = Class.new(DelegationSpecs::Target)
+ a.class_eval(<<-RUBY)
+ def delegate(...)
+ target(...)
+ end
+ RUBY
+
+ a.new.delegate(1, b: 2).should == [[1], {b: 2}]
+ end
+
+ it "delegates block" do
+ a = Class.new(DelegationSpecs::Target)
+ a.class_eval(<<-RUBY)
+ def delegate_block(...)
+ target_block(...)
+ end
+ RUBY
+
+ a.new.delegate_block(1, b: 2) { |x| x }.should == [{b: 2}, [1]]
+ end
+
+ it "parses as open endless Range when brackets are omitted" do
+ a = Class.new(DelegationSpecs::Target)
+ suppress_warning do
a.class_eval(<<-RUBY)
def delegate(...)
- target(...)
+ target ...
end
RUBY
-
- a.new.delegate(1, b: 2).should == [[1], {b: 2}]
end
- it "delegates block" do
- a = Class.new(DelegationSpecs::Target)
- a.class_eval(<<-RUBY)
- def delegate_block(...)
- target_block(...)
- end
- RUBY
+ a.new.delegate(1, b: 2).should == Range.new([[], {}], nil, true)
+ end
+end
- a.new.delegate_block(1, b: 2) { |x| x }.should == [{b: 2}, [1]]
- end
+describe "delegation with def(x, ...)" do
+ it "delegates rest and kwargs" do
+ a = Class.new(DelegationSpecs::Target)
+ a.class_eval(<<-RUBY)
+ def delegate(x, ...)
+ target(...)
+ end
+ RUBY
- it "parses as open endless Range when brackets are omitted" do
- a = Class.new(DelegationSpecs::Target)
- suppress_warning do
- a.class_eval(<<-RUBY)
- def delegate(...)
- target ...
- end
- RUBY
- end
+ a.new.delegate(0, 1, b: 2).should == [[1], {b: 2}]
+ end
- a.new.delegate(1, b: 2).should == Range.new([[], {}], nil, true)
- end
+ it "delegates block" do
+ a = Class.new(DelegationSpecs::Target)
+ a.class_eval(<<-RUBY)
+ def delegate_block(x, ...)
+ target_block(...)
+ end
+ RUBY
+
+ a.new.delegate_block(0, 1, b: 2) { |x| x }.should == [{b: 2}, [1]]
end
end
-ruby_version_is "2.7.3" do
- describe "delegation with def(x, ...)" do
- it "delegates rest and kwargs" do
+ruby_version_is "3.2" do
+ describe "delegation with def(*)" do
+ it "delegates rest" do
a = Class.new(DelegationSpecs::Target)
a.class_eval(<<-RUBY)
- def delegate(x, ...)
- target(...)
- end
- RUBY
+ def delegate(*)
+ target(*)
+ end
+ RUBY
- a.new.delegate(0, 1, b: 2).should == [[1], {b: 2}]
+ a.new.delegate(0, 1).should == [[0, 1], {}]
end
+ end
+end
- it "delegates block" do
+ruby_version_is "3.2" do
+ describe "delegation with def(**)" do
+ it "delegates kwargs" do
a = Class.new(DelegationSpecs::Target)
a.class_eval(<<-RUBY)
- def delegate_block(x, ...)
- target_block(...)
- end
- RUBY
+ def delegate(**)
+ target(**)
+ end
+ RUBY
- a.new.delegate_block(0, 1, b: 2) { |x| x }.should == [{b: 2}, [1]]
+ a.new.delegate(a: 1) { |x| x }.should == [[], {a: 1}]
end
-
end
end
diff --git a/spec/ruby/language/encoding_spec.rb b/spec/ruby/language/encoding_spec.rb
index 5430c9cb98..e761a53cb6 100644
--- a/spec/ruby/language/encoding_spec.rb
+++ b/spec/ruby/language/encoding_spec.rb
@@ -13,15 +13,15 @@ describe "The __ENCODING__ pseudo-variable" do
end
it "is the evaluated strings's one inside an eval" do
- eval("__ENCODING__".force_encoding("US-ASCII")).should == Encoding::US_ASCII
- eval("__ENCODING__".force_encoding("BINARY")).should == Encoding::BINARY
+ eval("__ENCODING__".dup.force_encoding("US-ASCII")).should == Encoding::US_ASCII
+ eval("__ENCODING__".dup.force_encoding("BINARY")).should == Encoding::BINARY
end
it "is the encoding specified by a magic comment inside an eval" do
- code = "# encoding: BINARY\n__ENCODING__".force_encoding("US-ASCII")
+ code = "# encoding: BINARY\n__ENCODING__".dup.force_encoding("US-ASCII")
eval(code).should == Encoding::BINARY
- code = "# encoding: us-ascii\n__ENCODING__".force_encoding("BINARY")
+ code = "# encoding: us-ascii\n__ENCODING__".dup.force_encoding("BINARY")
eval(code).should == Encoding::US_ASCII
end
diff --git a/spec/ruby/language/ensure_spec.rb b/spec/ruby/language/ensure_spec.rb
index e893904bcb..16e626b4d0 100644
--- a/spec/ruby/language/ensure_spec.rb
+++ b/spec/ruby/language/ensure_spec.rb
@@ -328,4 +328,21 @@ describe "An ensure block inside 'do end' block" do
result.should == :begin
end
+
+ ruby_version_is "3.4" do
+ it "does not introduce extra backtrace entries" do
+ def foo
+ begin
+ raise "oops"
+ ensure
+ return caller(0, 2) # rubocop:disable Lint/EnsureReturn
+ end
+ end
+ line = __LINE__
+ foo.should == [
+ "#{__FILE__}:#{line-3}:in 'foo'",
+ "#{__FILE__}:#{line+1}:in 'block (3 levels) in <top (required)>'"
+ ]
+ end
+ end
end
diff --git a/spec/ruby/language/execution_spec.rb b/spec/ruby/language/execution_spec.rb
index 4e0310946d..ef1de38899 100644
--- a/spec/ruby/language/execution_spec.rb
+++ b/spec/ruby/language/execution_spec.rb
@@ -5,6 +5,45 @@ describe "``" do
ip = 'world'
`echo disc #{ip}`.should == "disc world\n"
end
+
+ it "can be redefined and receive a frozen string as argument" do
+ called = false
+ runner = Object.new
+
+ runner.singleton_class.define_method(:`) do |str|
+ called = true
+
+ str.should == "test command"
+ str.frozen?.should == true
+ end
+
+ runner.instance_exec do
+ `test command`
+ end
+
+ called.should == true
+ end
+
+ it "the argument isn't frozen if it contains interpolation" do
+ called = false
+ runner = Object.new
+
+ runner.singleton_class.define_method(:`) do |str|
+ called = true
+
+ str.should == "test command"
+ str.frozen?.should == false
+ str << "mutated"
+ end
+
+ 2.times do
+ runner.instance_exec do
+ `test #{:command}`
+ end
+ end
+
+ called.should == true
+ end
end
describe "%x" do
@@ -12,4 +51,43 @@ describe "%x" do
ip = 'world'
%x(echo disc #{ip}).should == "disc world\n"
end
+
+ it "can be redefined and receive a frozen string as argument" do
+ called = false
+ runner = Object.new
+
+ runner.singleton_class.define_method(:`) do |str|
+ called = true
+
+ str.should == "test command"
+ str.frozen?.should == true
+ end
+
+ runner.instance_exec do
+ %x{test command}
+ end
+
+ called.should == true
+ end
+
+ it "the argument isn't frozen if it contains interpolation" do
+ called = false
+ runner = Object.new
+
+ runner.singleton_class.define_method(:`) do |str|
+ called = true
+
+ str.should == "test command"
+ str.frozen?.should == false
+ str << "mutated"
+ end
+
+ 2.times do
+ runner.instance_exec do
+ %x{test #{:command}}
+ end
+ end
+
+ called.should == true
+ end
end
diff --git a/spec/ruby/language/file_spec.rb b/spec/ruby/language/file_spec.rb
index 729dee1008..59563d9642 100644
--- a/spec/ruby/language/file_spec.rb
+++ b/spec/ruby/language/file_spec.rb
@@ -7,23 +7,23 @@ describe "The __FILE__ pseudo-variable" do
-> { eval("__FILE__ = 1") }.should raise_error(SyntaxError)
end
- it "equals (eval) inside an eval" do
- eval("__FILE__").should == "(eval)"
+ ruby_version_is ""..."3.3" do
+ it "equals (eval) inside an eval" do
+ eval("__FILE__").should == "(eval)"
+ end
end
-end
-describe "The __FILE__ pseudo-variable" do
- it_behaves_like :language___FILE__, :require, CodeLoadingSpecs::Method.new
+ ruby_version_is "3.3" do
+ it "equals (eval at __FILE__:__LINE__) inside an eval" do
+ eval("__FILE__").should == "(eval at #{__FILE__}:#{__LINE__})"
+ end
+ end
end
-describe "The __FILE__ pseudo-variable" do
+describe "The __FILE__ pseudo-variable with require" do
it_behaves_like :language___FILE__, :require, Kernel
end
-describe "The __FILE__ pseudo-variable" do
- it_behaves_like :language___FILE__, :load, CodeLoadingSpecs::Method.new
-end
-
-describe "The __FILE__ pseudo-variable" do
+describe "The __FILE__ pseudo-variable with load" do
it_behaves_like :language___FILE__, :load, Kernel
end
diff --git a/spec/ruby/language/fixtures/defined.rb b/spec/ruby/language/fixtures/defined.rb
index 8b6004c19f..a9552619bf 100644
--- a/spec/ruby/language/fixtures/defined.rb
+++ b/spec/ruby/language/fixtures/defined.rb
@@ -19,6 +19,9 @@ module DefinedSpecs
DefinedSpecs
end
+ def self.any_args(*)
+ end
+
class Basic
A = 42
diff --git a/spec/ruby/language/fixtures/freeze_magic_comment_required_diff_enc.rb b/spec/ruby/language/fixtures/freeze_magic_comment_required_diff_enc.rb
index d0558a2251..f72a32e879 100644
--- a/spec/ruby/language/fixtures/freeze_magic_comment_required_diff_enc.rb
+++ b/spec/ruby/language/fixtures/freeze_magic_comment_required_diff_enc.rb
Binary files differ
diff --git a/spec/ruby/language/fixtures/freeze_magic_comment_two_literals.rb b/spec/ruby/language/fixtures/freeze_magic_comment_two_literals.rb
index a4d655ad02..cccc5969bd 100644
--- a/spec/ruby/language/fixtures/freeze_magic_comment_two_literals.rb
+++ b/spec/ruby/language/fixtures/freeze_magic_comment_two_literals.rb
@@ -1,3 +1,3 @@
# frozen_string_literal: true
-p "abc".object_id == "abc".object_id
+p "abc".equal?("abc")
diff --git a/spec/ruby/language/fixtures/rescue/top_level.rb b/spec/ruby/language/fixtures/rescue/top_level.rb
new file mode 100644
index 0000000000..59e78ef1d6
--- /dev/null
+++ b/spec/ruby/language/fixtures/rescue/top_level.rb
@@ -0,0 +1,7 @@
+# capturing in local variable at top-level
+
+begin
+ raise "message"
+rescue => e
+ ScratchPad << e.message
+end
diff --git a/spec/ruby/language/fixtures/super.rb b/spec/ruby/language/fixtures/super.rb
index 218f1e4970..c5bdcf0e40 100644
--- a/spec/ruby/language/fixtures/super.rb
+++ b/spec/ruby/language/fixtures/super.rb
@@ -539,6 +539,30 @@ module SuperSpecs
args
end
+ def m3(*args)
+ args
+ end
+
+ def m4(*args)
+ args
+ end
+
+ def m_default(*args)
+ args
+ end
+
+ def m_rest(*args)
+ args
+ end
+
+ def m_pre_default_rest_post(*args)
+ args
+ end
+
+ def m_kwrest(**kw)
+ kw
+ end
+
def m_modified(*args)
args
end
@@ -549,6 +573,30 @@ module SuperSpecs
super
end
+ def m3(_, _, _)
+ super
+ end
+
+ def m4(_, _, _, _)
+ super
+ end
+
+ def m_default(_ = 0)
+ super
+ end
+
+ def m_rest(*_)
+ super
+ end
+
+ def m_pre_default_rest_post(_, _, _=:a, _=:b, *_, _, _)
+ super
+ end
+
+ def m_kwrest(**_)
+ super
+ end
+
def m_modified(_, _)
_ = 14
super
@@ -556,6 +604,20 @@ module SuperSpecs
end
end
+ module ZSuperInBlock
+ class A
+ def m(arg:)
+ arg
+ end
+ end
+
+ class B < A
+ def m(arg:)
+ proc { super }.call
+ end
+ end
+ end
+
module Keywords
class Arguments
def foo(**args)
diff --git a/spec/ruby/language/fixtures/variables.rb b/spec/ruby/language/fixtures/variables.rb
index 07265dbb2b..527caa7a78 100644
--- a/spec/ruby/language/fixtures/variables.rb
+++ b/spec/ruby/language/fixtures/variables.rb
@@ -82,4 +82,76 @@ module VariablesSpecs
def self.false
false
end
+
+ class EvalOrder
+ attr_reader :order
+
+ def initialize
+ @order = []
+ end
+
+ def reset
+ @order = []
+ end
+
+ def foo
+ self << "foo"
+ FooClass.new(self)
+ end
+
+ def bar
+ self << "bar"
+ BarClass.new(self)
+ end
+
+ def a
+ self << "a"
+ end
+
+ def b
+ self << "b"
+ end
+
+ def node
+ self << "node"
+
+ node = Node.new
+ node.left = Node.new
+ node.left.right = Node.new
+
+ node
+ end
+
+ def <<(value)
+ order << value
+ end
+
+ class FooClass
+ attr_reader :evaluator
+
+ def initialize(evaluator)
+ @evaluator = evaluator
+ end
+
+ def []=(_index, _value)
+ evaluator << "foo[]="
+ end
+ end
+
+ class BarClass
+ attr_reader :evaluator
+
+ def initialize(evaluator)
+ @evaluator = evaluator
+ end
+
+ def baz=(_value)
+ evaluator << "bar.baz="
+ end
+ end
+
+ class Node
+ attr_accessor :left, :right
+ end
+ end
end
diff --git a/spec/ruby/language/hash_spec.rb b/spec/ruby/language/hash_spec.rb
index 2f8b97199a..a7631fb0d6 100644
--- a/spec/ruby/language/hash_spec.rb
+++ b/spec/ruby/language/hash_spec.rb
@@ -33,7 +33,7 @@ describe "Hash literal" do
end
it "freezes string keys on initialization" do
- key = "foo"
+ key = +"foo"
h = {key => "bar"}
key.reverse!
h["foo"].should == "bar"
@@ -127,11 +127,24 @@ describe "Hash literal" do
{a: 1, **h, c: 4}.should == {a: 1, b: 2, c: 4}
end
- it "expands an '**{}' element with the last key/value pair taking precedence" do
+ it "expands an '**{}' or '**obj' element with the last key/value pair taking precedence" do
-> {
@h = eval "{a: 1, **{a: 2, b: 3, c: 1}, c: 3}"
}.should complain(/key :a is duplicated|duplicated key/)
@h.should == {a: 2, b: 3, c: 3}
+
+ -> {
+ h = {a: 2, b: 3, c: 1}
+ @h = eval "{a: 1, **h, c: 3}"
+ }.should_not complain
+ @h.should == {a: 2, b: 3, c: 3}
+ end
+
+ it "expands an '**{}' and warns when finding an additional duplicate key afterwards" do
+ -> {
+ @h = eval "{d: 1, **{a: 2, b: 3, c: 1}, c: 3}"
+ }.should complain(/key :c is duplicated|duplicated key/)
+ @h.should == {a: 2, b: 3, c: 3, d: 1}
end
it "merges multiple nested '**obj' in Hash literals" do
@@ -148,18 +161,9 @@ describe "Hash literal" do
{a: 1, **obj, c: 3}.should == {a:1, b: 2, c: 3, d: 4}
end
- ruby_version_is ""..."2.7" do
- it "raises a TypeError if any splatted elements keys are not symbols" do
- h = {1 => 2, b: 3}
- -> { {a: 1, **h} }.should raise_error(TypeError)
- end
- end
-
- ruby_version_is "2.7" do
- it "allows splatted elements keys that are not symbols" do
- h = {1 => 2, b: 3}
- {a: 1, **h}.should == {a: 1, 1 => 2, b: 3}
- end
+ it "allows splatted elements keys that are not symbols" do
+ h = {1 => 2, b: 3}
+ {a: 1, **h}.should == {a: 1, 1 => 2, b: 3}
end
it "raises a TypeError if #to_hash does not return a Hash" do
@@ -186,6 +190,24 @@ describe "Hash literal" do
utf8_hash.keys.first.should == usascii_hash.keys.first
usascii_hash.keys.first.encoding.should == Encoding::US_ASCII
end
+
+ ruby_bug "#20280", ""..."3.4" do
+ it "raises a SyntaxError at parse time when Symbol key with invalid bytes" do
+ ScratchPad.record []
+ -> {
+ eval 'ScratchPad << 1; {:"\xC3" => 1}'
+ }.should raise_error(SyntaxError, /invalid symbol/)
+ ScratchPad.recorded.should == []
+ end
+
+ it "raises a SyntaxError at parse time when Symbol key with invalid bytes and 'key: value' syntax used" do
+ ScratchPad.record []
+ -> {
+ eval 'ScratchPad << 1; {"\xC3": 1}'
+ }.should raise_error(SyntaxError, /invalid symbol/)
+ ScratchPad.recorded.should == []
+ end
+ end
end
describe "The ** operator" do
@@ -200,8 +222,8 @@ describe "The ** operator" do
h.should == { one: 1, two: 2 }
end
- ruby_version_is ""..."3.0" do
- it "makes a caller-side copy when calling a method taking a positional Hash" do
+ ruby_bug "#20012", ""..."3.3" do
+ it "makes a copy when calling a method taking a positional Hash" do
def m(h)
h.delete(:one); h
end
@@ -213,19 +235,6 @@ describe "The ** operator" do
end
end
- ruby_version_is "3.0" do
- it "does not copy when calling a method taking a positional Hash" do
- def m(h)
- h.delete(:one); h
- end
-
- h = { one: 1, two: 2 }
- m(**h).should == { two: 2 }
- m(**h).should.equal?(h)
- h.should == { two: 2 }
- end
- end
-
ruby_version_is "3.1" do
describe "hash with omitted value" do
it "accepts short notation 'key' for 'key: value' syntax" do
diff --git a/spec/ruby/language/heredoc_spec.rb b/spec/ruby/language/heredoc_spec.rb
index 61a27ad8e0..b3b160fd11 100644
--- a/spec/ruby/language/heredoc_spec.rb
+++ b/spec/ruby/language/heredoc_spec.rb
@@ -59,20 +59,10 @@ HERE
s.encoding.should == Encoding::US_ASCII
end
- ruby_version_is "2.7" do
- it 'raises SyntaxError if quoted HEREDOC identifier is ending not on same line' do
- -> {
- eval %{<<"HERE\n"\nraises syntax error\nHERE}
- }.should raise_error(SyntaxError)
- end
- end
-
- ruby_version_is ""..."2.7" do
- it 'prints a warning if quoted HEREDOC identifier is ending not on same line' do
- -> {
- eval %{<<"HERE\n"\nit warns\nHERE}
- }.should complain(/here document identifier ends with a newline/)
- end
+ it 'raises SyntaxError if quoted HEREDOC identifier is ending not on same line' do
+ -> {
+ eval %{<<"HERE\n"\nraises syntax error\nHERE}
+ }.should raise_error(SyntaxError)
end
it "allows HEREDOC with <<~'identifier', allowing to indent identifier and content" do
diff --git a/spec/ruby/language/if_spec.rb b/spec/ruby/language/if_spec.rb
index d1d95c1607..2d1a89f081 100644
--- a/spec/ruby/language/if_spec.rb
+++ b/spec/ruby/language/if_spec.rb
@@ -305,6 +305,59 @@ describe "The if expression" do
6.times(&b)
ScratchPad.recorded.should == [4, 5, 4, 5]
end
+
+ it "warns when Integer literals are used instead of predicates" do
+ -> {
+ eval <<~RUBY
+ $. = 0
+ 10.times { |i| ScratchPad << i if 4..5 }
+ RUBY
+ }.should complain(/warning: integer literal in flip-flop/, verbose: true)
+ ScratchPad.recorded.should == []
+ end
+ end
+
+ describe "when a branch syntactically does not return a value" do
+ it "raises SyntaxError if both do not return a value" do
+ -> {
+ eval <<~RUBY
+ def m
+ a = if rand
+ return
+ else
+ return
+ end
+ a
+ end
+ RUBY
+ }.should raise_error(SyntaxError, /void value expression/)
+ end
+
+ it "does not raise SyntaxError if one branch returns a value" do
+ eval(<<~RUBY).should == 1
+ def m
+ a = if false # using false to make it clear that's not checked for
+ 42
+ else
+ return 1
+ end
+ a
+ end
+ m
+ RUBY
+
+ eval(<<~RUBY).should == 1
+ def m
+ a = if true # using true to make it clear that's not checked for
+ return 1
+ else
+ 42
+ end
+ a
+ end
+ m
+ RUBY
+ end
end
end
diff --git a/spec/ruby/language/keyword_arguments_spec.rb b/spec/ruby/language/keyword_arguments_spec.rb
new file mode 100644
index 0000000000..ffb5b1fab0
--- /dev/null
+++ b/spec/ruby/language/keyword_arguments_spec.rb
@@ -0,0 +1,398 @@
+require_relative '../spec_helper'
+
+describe "Keyword arguments" do
+ def target(*args, **kwargs)
+ [args, kwargs]
+ end
+
+ it "are separated from positional arguments" do
+ def m(*args, **kwargs)
+ [args, kwargs]
+ end
+
+ empty = {}
+ m(**empty).should == [[], {}]
+ m(empty).should == [[{}], {}]
+
+ m(a: 1).should == [[], {a: 1}]
+ m({a: 1}).should == [[{a: 1}], {}]
+ end
+
+ it "when the receiving method has not keyword parameters it treats kwargs as positional" do
+ def m(*a)
+ a
+ end
+
+ m(a: 1).should == [{a: 1}]
+ m({a: 1}).should == [{a: 1}]
+ end
+
+ context "empty kwargs are treated as if they were not passed" do
+ it "when calling a method" do
+ def m(*a)
+ a
+ end
+
+ empty = {}
+ m(**empty).should == []
+ m(empty).should == [{}]
+ end
+
+ it "when yielding to a block" do
+ def y(*args, **kwargs)
+ yield(*args, **kwargs)
+ end
+
+ empty = {}
+ y(**empty) { |*a| a }.should == []
+ y(empty) { |*a| a }.should == [{}]
+ end
+ end
+
+ it "extra keywords are not allowed without **kwrest" do
+ def m(*a, kw:)
+ a
+ end
+
+ m(kw: 1).should == []
+ -> { m(kw: 1, kw2: 2) }.should raise_error(ArgumentError, 'unknown keyword: :kw2')
+ -> { m(kw: 1, true => false) }.should raise_error(ArgumentError, 'unknown keyword: true')
+ -> { m(kw: 1, a: 1, b: 2, c: 3) }.should raise_error(ArgumentError, 'unknown keywords: :a, :b, :c')
+ end
+
+ it "raises ArgumentError exception when required keyword argument is not passed" do
+ def m(a:, b:, c:)
+ [a, b, c]
+ end
+
+ -> { m(a: 1, b: 2) }.should raise_error(ArgumentError, /missing keyword: :c/)
+ -> { m() }.should raise_error(ArgumentError, /missing keywords: :a, :b, :c/)
+ end
+
+ it "raises ArgumentError for missing keyword arguments even if there are extra ones" do
+ def m(a:)
+ a
+ end
+
+ -> { m(b: 1) }.should raise_error(ArgumentError, /missing keyword: :a/)
+ end
+
+ it "handle * and ** at the same call site" do
+ def m(*a)
+ a
+ end
+
+ m(*[], **{}).should == []
+ m(*[], 42, **{}).should == [42]
+ end
+
+ context "**" do
+ ruby_version_is "3.3" do
+ it "copies a non-empty Hash for a method taking (*args)" do
+ def m(*args)
+ args[0]
+ end
+
+ h = {a: 1}
+ m(**h).should_not.equal?(h)
+ h.should == {a: 1}
+ end
+ end
+
+ it "copies the given Hash for a method taking (**kwargs)" do
+ def m(**kw)
+ kw
+ end
+
+ empty = {}
+ m(**empty).should == empty
+ m(**empty).should_not.equal?(empty)
+
+ h = {a: 1}
+ m(**h).should == h
+ m(**h).should_not.equal?(h)
+ end
+ end
+
+ context "delegation" do
+ it "works with (*args, **kwargs)" do
+ def m(*args, **kwargs)
+ target(*args, **kwargs)
+ end
+
+ empty = {}
+ m(**empty).should == [[], {}]
+ m(empty).should == [[{}], {}]
+
+ m(a: 1).should == [[], {a: 1}]
+ m({a: 1}).should == [[{a: 1}], {}]
+ end
+
+ it "works with proc { |*args, **kwargs| }" do
+ m = proc do |*args, **kwargs|
+ target(*args, **kwargs)
+ end
+
+ empty = {}
+ m.(**empty).should == [[], {}]
+ m.(empty).should == [[{}], {}]
+
+ m.(a: 1).should == [[], {a: 1}]
+ m.({a: 1}).should == [[{a: 1}], {}]
+
+ # no autosplatting for |*args, **kwargs|
+ m.([1, 2]).should == [[[1, 2]], {}]
+ end
+
+ it "works with -> (*args, **kwargs) {}" do
+ m = -> *args, **kwargs do
+ target(*args, **kwargs)
+ end
+
+ empty = {}
+ m.(**empty).should == [[], {}]
+ m.(empty).should == [[{}], {}]
+
+ m.(a: 1).should == [[], {a: 1}]
+ m.({a: 1}).should == [[{a: 1}], {}]
+ end
+
+ it "works with (...)" do
+ instance_eval <<~DEF
+ def m(...)
+ target(...)
+ end
+ DEF
+
+ empty = {}
+ m(**empty).should == [[], {}]
+ m(empty).should == [[{}], {}]
+
+ m(a: 1).should == [[], {a: 1}]
+ m({a: 1}).should == [[{a: 1}], {}]
+ end
+
+ it "works with call(*ruby2_keyword_args)" do
+ class << self
+ ruby2_keywords def m(*args)
+ target(*args)
+ end
+ end
+
+ empty = {}
+ m(**empty).should == [[], {}]
+ Hash.ruby2_keywords_hash?(empty).should == false
+ m(empty).should == [[{}], {}]
+ Hash.ruby2_keywords_hash?(empty).should == false
+
+ m(a: 1).should == [[], {a: 1}]
+ m({a: 1}).should == [[{a: 1}], {}]
+
+ kw = {a: 1}
+
+ m(**kw).should == [[], {a: 1}]
+ m(**kw)[1].should == kw
+ m(**kw)[1].should_not.equal?(kw)
+ Hash.ruby2_keywords_hash?(kw).should == false
+ Hash.ruby2_keywords_hash?(m(**kw)[1]).should == false
+
+ m(kw).should == [[{a: 1}], {}]
+ m(kw)[0][0].should.equal?(kw)
+ Hash.ruby2_keywords_hash?(kw).should == false
+ end
+
+ it "works with super(*ruby2_keyword_args)" do
+ parent = Class.new do
+ def m(*args, **kwargs)
+ [args, kwargs]
+ end
+ end
+
+ child = Class.new(parent) do
+ ruby2_keywords def m(*args)
+ super(*args)
+ end
+ end
+
+ obj = child.new
+
+ empty = {}
+ obj.m(**empty).should == [[], {}]
+ Hash.ruby2_keywords_hash?(empty).should == false
+ obj.m(empty).should == [[{}], {}]
+ Hash.ruby2_keywords_hash?(empty).should == false
+
+ obj.m(a: 1).should == [[], {a: 1}]
+ obj.m({a: 1}).should == [[{a: 1}], {}]
+
+ kw = {a: 1}
+
+ obj.m(**kw).should == [[], {a: 1}]
+ obj.m(**kw)[1].should == kw
+ obj.m(**kw)[1].should_not.equal?(kw)
+ Hash.ruby2_keywords_hash?(kw).should == false
+ Hash.ruby2_keywords_hash?(obj.m(**kw)[1]).should == false
+
+ obj.m(kw).should == [[{a: 1}], {}]
+ obj.m(kw)[0][0].should.equal?(kw)
+ Hash.ruby2_keywords_hash?(kw).should == false
+ end
+
+ it "works with zsuper" do
+ parent = Class.new do
+ def m(*args, **kwargs)
+ [args, kwargs]
+ end
+ end
+
+ child = Class.new(parent) do
+ ruby2_keywords def m(*args)
+ super
+ end
+ end
+
+ obj = child.new
+
+ empty = {}
+ obj.m(**empty).should == [[], {}]
+ Hash.ruby2_keywords_hash?(empty).should == false
+ obj.m(empty).should == [[{}], {}]
+ Hash.ruby2_keywords_hash?(empty).should == false
+
+ obj.m(a: 1).should == [[], {a: 1}]
+ obj.m({a: 1}).should == [[{a: 1}], {}]
+
+ kw = {a: 1}
+
+ obj.m(**kw).should == [[], {a: 1}]
+ obj.m(**kw)[1].should == kw
+ obj.m(**kw)[1].should_not.equal?(kw)
+ Hash.ruby2_keywords_hash?(kw).should == false
+ Hash.ruby2_keywords_hash?(obj.m(**kw)[1]).should == false
+
+ obj.m(kw).should == [[{a: 1}], {}]
+ obj.m(kw)[0][0].should.equal?(kw)
+ Hash.ruby2_keywords_hash?(kw).should == false
+ end
+
+ it "works with yield(*ruby2_keyword_args)" do
+ class << self
+ def y(args)
+ yield(*args)
+ end
+
+ ruby2_keywords def m(*outer_args)
+ y(outer_args, &-> *args, **kwargs { target(*args, **kwargs) })
+ end
+ end
+
+ empty = {}
+ m(**empty).should == [[], {}]
+ Hash.ruby2_keywords_hash?(empty).should == false
+ m(empty).should == [[{}], {}]
+ Hash.ruby2_keywords_hash?(empty).should == false
+
+ m(a: 1).should == [[], {a: 1}]
+ m({a: 1}).should == [[{a: 1}], {}]
+
+ kw = {a: 1}
+
+ m(**kw).should == [[], {a: 1}]
+ m(**kw)[1].should == kw
+ m(**kw)[1].should_not.equal?(kw)
+ Hash.ruby2_keywords_hash?(kw).should == false
+ Hash.ruby2_keywords_hash?(m(**kw)[1]).should == false
+
+ m(kw).should == [[{a: 1}], {}]
+ m(kw)[0][0].should.equal?(kw)
+ Hash.ruby2_keywords_hash?(kw).should == false
+ end
+
+ it "does not work with (*args)" do
+ class << self
+ def m(*args)
+ target(*args)
+ end
+ end
+
+ empty = {}
+ m(**empty).should == [[], {}]
+ m(empty).should == [[{}], {}]
+
+ m(a: 1).should == [[{a: 1}], {}]
+ m({a: 1}).should == [[{a: 1}], {}]
+ end
+
+ ruby_version_is "3.1" do
+ describe "omitted values" do
+ it "accepts short notation 'key' for 'key: value' syntax" do
+ def m(a:, b:)
+ [a, b]
+ end
+
+ a = 1
+ b = 2
+
+ eval('m(a:, b:).should == [1, 2]')
+ end
+ end
+ end
+
+ ruby_version_is "3.2" do
+ it "does not work with call(*ruby2_keyword_args) with missing ruby2_keywords in between" do
+ class << self
+ def n(*args) # Note the missing ruby2_keywords here
+ target(*args)
+ end
+
+ ruby2_keywords def m(*args)
+ n(*args)
+ end
+ end
+
+ empty = {}
+ m(**empty).should == [[], {}]
+ m(empty).should == [[{}], {}]
+
+ m(a: 1).should == [[{a: 1}], {}]
+ m({a: 1}).should == [[{a: 1}], {}]
+ end
+ end
+
+ ruby_version_is ""..."3.2" do
+ # https://bugs.ruby-lang.org/issues/18625
+ it "works with call(*ruby2_keyword_args) with missing ruby2_keywords in between due to CRuby bug #18625" do
+ class << self
+ def n(*args) # Note the missing ruby2_keywords here
+ target(*args)
+ end
+
+ ruby2_keywords def m(*args)
+ n(*args)
+ end
+ end
+
+ empty = {}
+ m(**empty).should == [[], {}]
+ Hash.ruby2_keywords_hash?(empty).should == false
+ m(empty).should == [[{}], {}]
+ Hash.ruby2_keywords_hash?(empty).should == false
+
+ m(a: 1).should == [[], {a: 1}]
+ m({a: 1}).should == [[{a: 1}], {}]
+
+ kw = {a: 1}
+
+ m(**kw).should == [[], {a: 1}]
+ m(**kw)[1].should == kw
+ m(**kw)[1].should_not.equal?(kw)
+ Hash.ruby2_keywords_hash?(kw).should == false
+ Hash.ruby2_keywords_hash?(m(**kw)[1]).should == false
+
+ m(kw).should == [[{a: 1}], {}]
+ m(kw)[0][0].should.equal?(kw)
+ Hash.ruby2_keywords_hash?(kw).should == false
+ end
+ end
+ end
+end
diff --git a/spec/ruby/language/lambda_spec.rb b/spec/ruby/language/lambda_spec.rb
index 6393fb5c47..3ab3569ebe 100644
--- a/spec/ruby/language/lambda_spec.rb
+++ b/spec/ruby/language/lambda_spec.rb
@@ -177,34 +177,16 @@ describe "A lambda literal -> () { }" do
result.should == [1, 2, 3, [4, 5], 6, [7, 8], 9, 10, 11, 12]
end
- ruby_version_is ''...'3.0' do
- evaluate <<-ruby do
- @a = -> (*, **k) { k }
- ruby
-
- @a.().should == {}
- @a.(1, 2, 3, a: 4, b: 5).should == {a: 4, b: 5}
-
- suppress_keyword_warning do
- h = mock("keyword splat")
- h.should_receive(:to_hash).and_return({a: 1})
- @a.(h).should == {a: 1}
- end
- end
- end
-
- ruby_version_is '3.0' do
- evaluate <<-ruby do
- @a = -> (*, **k) { k }
- ruby
+ evaluate <<-ruby do
+ @a = -> (*, **k) { k }
+ ruby
- @a.().should == {}
- @a.(1, 2, 3, a: 4, b: 5).should == {a: 4, b: 5}
+ @a.().should == {}
+ @a.(1, 2, 3, a: 4, b: 5).should == {a: 4, b: 5}
- h = mock("keyword splat")
- h.should_not_receive(:to_hash)
- @a.(h).should == {}
- end
+ h = mock("keyword splat")
+ h.should_not_receive(:to_hash)
+ @a.(h).should == {}
end
evaluate <<-ruby do
@@ -281,38 +263,18 @@ describe "A lambda literal -> () { }" do
end
describe "with circular optional argument reference" do
- ruby_version_is ''...'2.7' do
- it "warns and uses a nil value when there is an existing local variable with same name" do
- a = 1
- -> {
- @proc = eval "-> (a=a) { a }"
- }.should complain(/circular argument reference/)
- @proc.call.should == nil
- end
-
- it "warns and uses a nil value when there is an existing method with same name" do
- def a; 1; end
- -> {
- @proc = eval "-> (a=a) { a }"
- }.should complain(/circular argument reference/)
- @proc.call.should == nil
- end
+ it "raises a SyntaxError if using an existing local with the same name as the argument" do
+ a = 1
+ -> {
+ @proc = eval "-> (a=a) { a }"
+ }.should raise_error(SyntaxError)
end
- ruby_version_is '2.7' do
- it "raises a SyntaxError if using an existing local with the same name as the argument" do
- a = 1
- -> {
- @proc = eval "-> (a=a) { a }"
- }.should raise_error(SyntaxError)
- end
-
- it "raises a SyntaxError if there is an existing method with the same name as the argument" do
- def a; 1; end
- -> {
- @proc = eval "-> (a=a) { a }"
- }.should raise_error(SyntaxError)
- end
+ it "raises a SyntaxError if there is an existing method with the same name as the argument" do
+ def a; 1; end
+ -> {
+ @proc = eval "-> (a=a) { a }"
+ }.should raise_error(SyntaxError)
end
it "calls an existing method with the same name as the argument if explicitly using ()" do
@@ -360,26 +322,12 @@ describe "A lambda expression 'lambda { ... }'" do
def meth; lambda; end
end
- ruby_version_is ""..."2.7" do
- it "can be created" do
- implicit_lambda = nil
+ it "raises ArgumentError" do
+ implicit_lambda = nil
+ suppress_warning do
-> {
- implicit_lambda = meth { 1 }
- }.should complain(/tried to create Proc object without a block/)
-
- implicit_lambda.lambda?.should be_true
- implicit_lambda.call.should == 1
- end
- end
-
- ruby_version_is "2.7" do
- it "raises ArgumentError" do
- implicit_lambda = nil
- suppress_warning do
- -> {
- meth { 1 }
- }.should raise_error(ArgumentError, /tried to create Proc object without a block/)
- end
+ meth { 1 }
+ }.should raise_error(ArgumentError, /tried to create Proc object without a block/)
end
end
end
@@ -548,34 +496,16 @@ describe "A lambda expression 'lambda { ... }'" do
result.should == [1, 2, 3, [4, 5], 6, [7, 8], 9, 10, 11, 12]
end
- ruby_version_is ''...'3.0' do
- evaluate <<-ruby do
- @a = lambda { |*, **k| k }
- ruby
-
- @a.().should == {}
- @a.(1, 2, 3, a: 4, b: 5).should == {a: 4, b: 5}
-
- suppress_keyword_warning do
- h = mock("keyword splat")
- h.should_receive(:to_hash).and_return({a: 1})
- @a.(h).should == {a: 1}
- end
- end
- end
-
- ruby_version_is '3.0' do
- evaluate <<-ruby do
- @a = lambda { |*, **k| k }
- ruby
+ evaluate <<-ruby do
+ @a = lambda { |*, **k| k }
+ ruby
- @a.().should == {}
- @a.(1, 2, 3, a: 4, b: 5).should == {a: 4, b: 5}
+ @a.().should == {}
+ @a.(1, 2, 3, a: 4, b: 5).should == {a: 4, b: 5}
- h = mock("keyword splat")
- h.should_not_receive(:to_hash)
- @a.(h).should == {}
- end
+ h = mock("keyword splat")
+ h.should_not_receive(:to_hash)
+ @a.(h).should == {}
end
evaluate <<-ruby do
diff --git a/spec/ruby/language/method_spec.rb b/spec/ruby/language/method_spec.rb
index 0a5bb99d0b..9abe4cde20 100644
--- a/spec/ruby/language/method_spec.rb
+++ b/spec/ruby/language/method_spec.rb
@@ -572,6 +572,13 @@ describe "A method" do
end
evaluate <<-ruby do
+ def m(a:, **kw) [a, kw] end
+ ruby
+
+ -> { m(b: 1) }.should raise_error(ArgumentError)
+ end
+
+ evaluate <<-ruby do
def m(a: 1) a end
ruby
@@ -602,13 +609,11 @@ describe "A method" do
-> { m(2) }.should raise_error(ArgumentError)
end
- ruby_version_is "2.7" do
- evaluate <<-ruby do
- def m(**k); k end;
- ruby
+ evaluate <<-ruby do
+ def m(**k); k end;
+ ruby
- m("a" => 1).should == { "a" => 1 }
- end
+ m("a" => 1).should == { "a" => 1 }
end
evaluate <<-ruby do
@@ -744,68 +749,31 @@ describe "A method" do
end
end
- ruby_version_is ""..."3.0" do
- evaluate <<-ruby do
- def m(a, b: 1) [a, b] end
- ruby
-
- m(2).should == [2, 1]
- m(1, b: 2).should == [1, 2]
- suppress_keyword_warning do
- m("a" => 1, b: 2).should == [{"a" => 1, b: 2}, 1]
- end
- end
-
- evaluate <<-ruby do
- def m(a, **) a end
- ruby
-
- m(1).should == 1
- m(1, a: 2, b: 3).should == 1
- suppress_keyword_warning do
- m("a" => 1, b: 2).should == {"a" => 1, b: 2}
- end
- end
-
- evaluate <<-ruby do
- def m(a, **k) [a, k] end
- ruby
+ evaluate <<-ruby do
+ def m(a, b: 1) [a, b] end
+ ruby
- m(1).should == [1, {}]
- m(1, a: 2, b: 3).should == [1, {a: 2, b: 3}]
- suppress_keyword_warning do
- m("a" => 1, b: 2).should == [{"a" => 1, b: 2}, {}]
- end
- end
+ m(2).should == [2, 1]
+ m(1, b: 2).should == [1, 2]
+ -> { m("a" => 1, b: 2) }.should raise_error(ArgumentError)
end
- ruby_version_is "3.0" do
- evaluate <<-ruby do
- def m(a, b: 1) [a, b] end
- ruby
-
- m(2).should == [2, 1]
- m(1, b: 2).should == [1, 2]
- -> { m("a" => 1, b: 2) }.should raise_error(ArgumentError)
- end
-
- evaluate <<-ruby do
- def m(a, **) a end
- ruby
+ evaluate <<-ruby do
+ def m(a, **) a end
+ ruby
- m(1).should == 1
- m(1, a: 2, b: 3).should == 1
- -> { m("a" => 1, b: 2) }.should raise_error(ArgumentError)
- end
+ m(1).should == 1
+ m(1, a: 2, b: 3).should == 1
+ -> { m("a" => 1, b: 2) }.should raise_error(ArgumentError)
+ end
- evaluate <<-ruby do
- def m(a, **k) [a, k] end
- ruby
+ evaluate <<-ruby do
+ def m(a, **k) [a, k] end
+ ruby
- m(1).should == [1, {}]
- m(1, a: 2, b: 3).should == [1, {a: 2, b: 3}]
- -> { m("a" => 1, b: 2) }.should raise_error(ArgumentError)
- end
+ m(1).should == [1, {}]
+ m(1, a: 2, b: 3).should == [1, {a: 2, b: 3}]
+ -> { m("a" => 1, b: 2) }.should raise_error(ArgumentError)
end
evaluate <<-ruby do
@@ -916,72 +884,32 @@ describe "A method" do
result.should == [[1, 2, 3], 4, [5, 6], 7, [], 8]
end
- ruby_version_is ""..."3.0" do
- evaluate <<-ruby do
- def m(a=1, b:) [a, b] end
- ruby
-
- m(b: 2).should == [1, 2]
- m(2, b: 1).should == [2, 1]
- suppress_keyword_warning do
- m("a" => 1, b: 2).should == [{"a" => 1}, 2]
- end
- end
-
- evaluate <<-ruby do
- def m(a=1, b: 2) [a, b] end
- ruby
-
- m().should == [1, 2]
- m(2).should == [2, 2]
- m(b: 3).should == [1, 3]
- suppress_keyword_warning do
- m("a" => 1, b: 2).should == [{"a" => 1}, 2]
- end
- end
- end
-
- ruby_version_is "3.0" do
- evaluate <<-ruby do
- def m(a=1, b:) [a, b] end
- ruby
-
- m(b: 2).should == [1, 2]
- m(2, b: 1).should == [2, 1]
- -> { m("a" => 1, b: 2) }.should raise_error(ArgumentError)
- end
-
- evaluate <<-ruby do
- def m(a=1, b: 2) [a, b] end
- ruby
+ evaluate <<-ruby do
+ def m(a=1, b:) [a, b] end
+ ruby
- m().should == [1, 2]
- m(2).should == [2, 2]
- m(b: 3).should == [1, 3]
- -> { m("a" => 1, b: 2) }.should raise_error(ArgumentError)
- end
+ m(b: 2).should == [1, 2]
+ m(2, b: 1).should == [2, 1]
+ -> { m("a" => 1, b: 2) }.should raise_error(ArgumentError)
end
- ruby_version_is ""..."2.7" do
- evaluate <<-ruby do
- def m(a=1, **) a end
- ruby
+ evaluate <<-ruby do
+ def m(a=1, b: 2) [a, b] end
+ ruby
- m().should == 1
- m(2, a: 1, b: 0).should == 2
- m("a" => 1, a: 2).should == {"a" => 1}
- end
+ m().should == [1, 2]
+ m(2).should == [2, 2]
+ m(b: 3).should == [1, 3]
+ -> { m("a" => 1, b: 2) }.should raise_error(ArgumentError)
end
- ruby_version_is "2.7" do
- evaluate <<-ruby do
- def m(a=1, **) a end
- ruby
+ evaluate <<-ruby do
+ def m(a=1, **) a end
+ ruby
- m().should == 1
- m(2, a: 1, b: 0).should == 2
- m("a" => 1, a: 2).should == 1
- end
+ m().should == 1
+ m(2, a: 1, b: 0).should == 2
+ m("a" => 1, a: 2).should == 1
end
evaluate <<-ruby do
@@ -1021,449 +949,6 @@ describe "A method" do
m(1, 2, 3).should == [[1, 2], 3]
end
- ruby_version_is ""..."2.7" do
- evaluate <<-ruby do
- def m(*, a:) a end
- ruby
-
- m(a: 1).should == 1
- m(1, 2, a: 3).should == 3
- suppress_keyword_warning do
- m("a" => 1, a: 2).should == 2
- end
- end
-
- evaluate <<-ruby do
- def m(*a, b:) [a, b] end
- ruby
-
- m(b: 1).should == [[], 1]
- m(1, 2, b: 3).should == [[1, 2], 3]
- suppress_keyword_warning do
- m("a" => 1, b: 2).should == [[{"a" => 1}], 2]
- end
- end
-
- evaluate <<-ruby do
- def m(*, a: 1) a end
- ruby
-
- m().should == 1
- m(1, 2).should == 1
- m(a: 2).should == 2
- m(1, a: 2).should == 2
- suppress_keyword_warning do
- m("a" => 1, a: 2).should == 2
- end
- end
-
- evaluate <<-ruby do
- def m(*a, b: 1) [a, b] end
- ruby
-
- m().should == [[], 1]
- m(1, 2, 3, b: 4).should == [[1, 2, 3], 4]
- suppress_keyword_warning do
- m("a" => 1, b: 2).should == [[{"a" => 1}], 2]
- end
-
- a = mock("splat")
- a.should_not_receive(:to_ary)
- m(*a).should == [[a], 1]
- end
-
- evaluate <<-ruby do
- def m(*, **) end
- ruby
-
- m().should be_nil
- m(a: 1, b: 2).should be_nil
- m(1, 2, 3, a: 4, b: 5).should be_nil
-
- h = mock("keyword splat")
- h.should_receive(:to_hash).and_return({a: 1})
- suppress_keyword_warning do
- m(h).should be_nil
- end
-
- h = mock("keyword splat")
- error = RuntimeError.new("error while converting to a hash")
- h.should_receive(:to_hash).and_raise(error)
- -> { m(h) }.should raise_error(error)
- end
-
- evaluate <<-ruby do
- def m(*a, **) a end
- ruby
-
- m().should == []
- m(1, 2, 3, a: 4, b: 5).should == [1, 2, 3]
- m("a" => 1, a: 1).should == [{"a" => 1}]
- m(1, **{a: 2}).should == [1]
-
- h = mock("keyword splat")
- h.should_receive(:to_hash)
- -> { m(**h) }.should raise_error(TypeError)
- end
-
- evaluate <<-ruby do
- def m(*, **k) k end
- ruby
-
- m().should == {}
- m(1, 2, 3, a: 4, b: 5).should == {a: 4, b: 5}
- m("a" => 1, a: 1).should == {a: 1}
-
- h = mock("keyword splat")
- h.should_receive(:to_hash).and_return({a: 1})
- m(h).should == {a: 1}
- end
-
- evaluate <<-ruby do
- def m(a = nil, **k) [a, k] end
- ruby
-
- m().should == [nil, {}]
- m("a" => 1).should == [{"a" => 1}, {}]
- m(a: 1).should == [nil, {a: 1}]
- m("a" => 1, a: 1).should == [{"a" => 1}, {a: 1}]
- m({ "a" => 1 }, a: 1).should == [{"a" => 1}, {a: 1}]
- m({a: 1}, {}).should == [{a: 1}, {}]
-
- h = {"a" => 1, b: 2}
- m(h).should == [{"a" => 1}, {b: 2}]
- h.should == {"a" => 1, b: 2}
-
- h = {"a" => 1}
- m(h).first.should == h
-
- h = {}
- r = m(h)
- r.first.should be_nil
- r.last.should == {}
-
- hh = {}
- h = mock("keyword splat empty hash")
- h.should_receive(:to_hash).and_return(hh)
- r = m(h)
- r.first.should be_nil
- r.last.should == {}
-
- h = mock("keyword splat")
- h.should_receive(:to_hash).and_return({"a" => 1, a: 2})
- m(h).should == [{"a" => 1}, {a: 2}]
- end
-
- evaluate <<-ruby do
- def m(*a, **k) [a, k] end
- ruby
-
- m().should == [[], {}]
- m(1).should == [[1], {}]
- m(a: 1, b: 2).should == [[], {a: 1, b: 2}]
- m(1, 2, 3, a: 2).should == [[1, 2, 3], {a: 2}]
-
- m("a" => 1).should == [[{"a" => 1}], {}]
- m(a: 1).should == [[], {a: 1}]
- m("a" => 1, a: 1).should == [[{"a" => 1}], {a: 1}]
- m({ "a" => 1 }, a: 1).should == [[{"a" => 1}], {a: 1}]
- m({a: 1}, {}).should == [[{a: 1}], {}]
- m({a: 1}, {"a" => 1}).should == [[{a: 1}, {"a" => 1}], {}]
-
- bo = BasicObject.new
- def bo.to_a; [1, 2, 3]; end
- def bo.to_hash; {:b => 2, :c => 3}; end
-
- m(*bo, **bo).should == [[1, 2, 3], {:b => 2, :c => 3}]
- end
- end
-
- ruby_version_is "2.7"...'3.0' do
- evaluate <<-ruby do
- def m(*, a:) a end
- ruby
-
- m(a: 1).should == 1
- m(1, 2, a: 3).should == 3
- suppress_keyword_warning do
- m("a" => 1, a: 2).should == 2
- end
- end
-
- evaluate <<-ruby do
- def m(*a, b:) [a, b] end
- ruby
-
- m(b: 1).should == [[], 1]
- m(1, 2, b: 3).should == [[1, 2], 3]
- suppress_keyword_warning do
- m("a" => 1, b: 2).should == [[{"a" => 1}], 2]
- end
- end
-
- evaluate <<-ruby do
- def m(*, a: 1) a end
- ruby
-
- m().should == 1
- m(1, 2).should == 1
- m(a: 2).should == 2
- m(1, a: 2).should == 2
- suppress_keyword_warning do
- m("a" => 1, a: 2).should == 2
- end
- end
-
- evaluate <<-ruby do
- def m(*a, b: 1) [a, b] end
- ruby
-
- m().should == [[], 1]
- m(1, 2, 3, b: 4).should == [[1, 2, 3], 4]
- suppress_keyword_warning do
- m("a" => 1, b: 2).should == [[{"a" => 1}], 2]
- end
-
- a = mock("splat")
- a.should_not_receive(:to_ary)
- m(*a).should == [[a], 1]
- end
-
- evaluate <<-ruby do
- def m(*a, **) a end
- ruby
-
- m().should == []
- m(1, 2, 3, a: 4, b: 5).should == [1, 2, 3]
- m("a" => 1, a: 1).should == []
- m(1, **{a: 2}).should == [1]
-
- h = mock("keyword splat")
- h.should_receive(:to_hash)
- -> { m(**h) }.should raise_error(TypeError)
- end
-
- evaluate <<-ruby do
- def m(*, **k) k end
- ruby
-
- m().should == {}
- m(1, 2, 3, a: 4, b: 5).should == {a: 4, b: 5}
- m("a" => 1, a: 1).should == {"a" => 1, a: 1}
-
- h = mock("keyword splat")
- h.should_receive(:to_hash).and_return({a: 1})
- suppress_warning do
- m(h).should == {a: 1}
- end
- end
-
- evaluate <<-ruby do
- def m(a = nil, **k) [a, k] end
- ruby
-
- m().should == [nil, {}]
- m("a" => 1).should == [nil, {"a" => 1}]
- m(a: 1).should == [nil, {a: 1}]
- m("a" => 1, a: 1).should == [nil, {"a" => 1, a: 1}]
- m({ "a" => 1 }, a: 1).should == [{"a" => 1}, {a: 1}]
- suppress_warning do
- m({a: 1}, {}).should == [{a: 1}, {}]
-
- h = {"a" => 1, b: 2}
- m(h).should == [{"a" => 1}, {b: 2}]
- h.should == {"a" => 1, b: 2}
-
- h = {"a" => 1}
- m(h).first.should == h
-
- h = {}
- r = m(h)
- r.first.should be_nil
- r.last.should == {}
-
- hh = {}
- h = mock("keyword splat empty hash")
- h.should_receive(:to_hash).and_return(hh)
- r = m(h)
- r.first.should be_nil
- r.last.should == {}
-
- h = mock("keyword splat")
- h.should_receive(:to_hash).and_return({"a" => 1, a: 2})
- m(h).should == [{"a" => 1}, {a: 2}]
- end
- end
-
- evaluate <<-ruby do
- def m(*a, **k) [a, k] end
- ruby
-
- m().should == [[], {}]
- m(1).should == [[1], {}]
- m(a: 1, b: 2).should == [[], {a: 1, b: 2}]
- m(1, 2, 3, a: 2).should == [[1, 2, 3], {a: 2}]
-
- m("a" => 1).should == [[], {"a" => 1}]
- m(a: 1).should == [[], {a: 1}]
- m("a" => 1, a: 1).should == [[], {"a" => 1, a: 1}]
- m({ "a" => 1 }, a: 1).should == [[{"a" => 1}], {a: 1}]
- suppress_warning do
- m({a: 1}, {}).should == [[{a: 1}], {}]
- end
- m({a: 1}, {"a" => 1}).should == [[{a: 1}, {"a" => 1}], {}]
-
- bo = BasicObject.new
- def bo.to_a; [1, 2, 3]; end
- def bo.to_hash; {:b => 2, :c => 3}; end
-
- m(*bo, **bo).should == [[1, 2, 3], {:b => 2, :c => 3}]
- end
-
- evaluate <<-ruby do
- def m(*, a:) a end
- ruby
-
- m(a: 1).should == 1
- m(1, 2, a: 3).should == 3
- suppress_keyword_warning do
- m("a" => 1, a: 2).should == 2
- end
- end
-
- evaluate <<-ruby do
- def m(*a, b:) [a, b] end
- ruby
-
- m(b: 1).should == [[], 1]
- m(1, 2, b: 3).should == [[1, 2], 3]
- suppress_keyword_warning do
- m("a" => 1, b: 2).should == [[{"a" => 1}], 2]
- end
- end
-
- evaluate <<-ruby do
- def m(*, a: 1) a end
- ruby
-
- m().should == 1
- m(1, 2).should == 1
- m(a: 2).should == 2
- m(1, a: 2).should == 2
- suppress_keyword_warning do
- m("a" => 1, a: 2).should == 2
- end
- end
-
- evaluate <<-ruby do
- def m(*a, b: 1) [a, b] end
- ruby
-
- m().should == [[], 1]
- m(1, 2, 3, b: 4).should == [[1, 2, 3], 4]
- suppress_keyword_warning do
- m("a" => 1, b: 2).should == [[{"a" => 1}], 2]
- end
-
- a = mock("splat")
- a.should_not_receive(:to_ary)
- m(*a).should == [[a], 1]
- end
-
- evaluate <<-ruby do
- def m(*a, **) a end
- ruby
-
- m().should == []
- m(1, 2, 3, a: 4, b: 5).should == [1, 2, 3]
- m("a" => 1, a: 1).should == []
- m(1, **{a: 2}).should == [1]
-
- h = mock("keyword splat")
- h.should_receive(:to_hash)
- -> { m(**h) }.should raise_error(TypeError)
- end
-
- evaluate <<-ruby do
- def m(*, **k) k end
- ruby
-
- m().should == {}
- m(1, 2, 3, a: 4, b: 5).should == {a: 4, b: 5}
- m("a" => 1, a: 1).should == {"a" => 1, a: 1}
-
- h = mock("keyword splat")
- h.should_receive(:to_hash).and_return({a: 1})
- suppress_keyword_warning do
- m(h).should == {a: 1}
- end
- end
-
- evaluate <<-ruby do
- def m(a = nil, **k) [a, k] end
- ruby
-
- m().should == [nil, {}]
- m("a" => 1).should == [nil, {"a" => 1}]
- m(a: 1).should == [nil, {a: 1}]
- m("a" => 1, a: 1).should == [nil, {"a" => 1, a: 1}]
- m({ "a" => 1 }, a: 1).should == [{"a" => 1}, {a: 1}]
- suppress_keyword_warning do
- m({a: 1}, {}).should == [{a: 1}, {}]
- end
-
- h = {"a" => 1, b: 2}
- suppress_keyword_warning do
- m(h).should == [{"a" => 1}, {b: 2}]
- end
- h.should == {"a" => 1, b: 2}
-
- h = {"a" => 1}
- m(h).first.should == h
-
- h = {}
- suppress_keyword_warning do
- m(h).should == [nil, {}]
- end
-
- hh = {}
- h = mock("keyword splat empty hash")
- h.should_receive(:to_hash).and_return({a: 1})
- suppress_keyword_warning do
- m(h).should == [nil, {a: 1}]
- end
-
- h = mock("keyword splat")
- h.should_receive(:to_hash).and_return({"a" => 1})
- m(h).should == [h, {}]
- end
-
- evaluate <<-ruby do
- def m(*a, **k) [a, k] end
- ruby
-
- m().should == [[], {}]
- m(1).should == [[1], {}]
- m(a: 1, b: 2).should == [[], {a: 1, b: 2}]
- m(1, 2, 3, a: 2).should == [[1, 2, 3], {a: 2}]
-
- m("a" => 1).should == [[], {"a" => 1}]
- m(a: 1).should == [[], {a: 1}]
- m("a" => 1, a: 1).should == [[], {"a" => 1, a: 1}]
- m({ "a" => 1 }, a: 1).should == [[{"a" => 1}], {a: 1}]
- suppress_keyword_warning do
- m({a: 1}, {}).should == [[{a: 1}], {}]
- end
- m({a: 1}, {"a" => 1}).should == [[{a: 1}, {"a" => 1}], {}]
-
- bo = BasicObject.new
- def bo.to_a; [1, 2, 3]; end
- def bo.to_hash; {:b => 2, :c => 3}; end
-
- m(*bo, **bo).should == [[1, 2, 3], {:b => 2, :c => 3}]
- end
- end
-
evaluate <<-ruby do
def m(*, &b) b end
ruby
@@ -1503,44 +988,22 @@ describe "A method" do
end
end
- ruby_version_is ''...'2.7' do
- evaluate <<-ruby do
- def m(a:, **) a end
- ruby
-
- m(a: 1).should == 1
- m(a: 1, b: 2).should == 1
- -> { m("a" => 1, a: 1, b: 2) }.should raise_error(ArgumentError)
- end
-
- evaluate <<-ruby do
- def m(a:, **k) [a, k] end
- ruby
+ evaluate <<-ruby do
+ def m(a:, **) a end
+ ruby
- m(a: 1).should == [1, {}]
- m(a: 1, b: 2, c: 3).should == [1, {b: 2, c: 3}]
- -> { m("a" => 1, a: 1, b: 2) }.should raise_error(ArgumentError)
- end
+ m(a: 1).should == 1
+ m(a: 1, b: 2).should == 1
+ m("a" => 1, a: 1, b: 2).should == 1
end
- ruby_version_is '2.7' do
- evaluate <<-ruby do
- def m(a:, **) a end
- ruby
-
- m(a: 1).should == 1
- m(a: 1, b: 2).should == 1
- m("a" => 1, a: 1, b: 2).should == 1
- end
-
- evaluate <<-ruby do
- def m(a:, **k) [a, k] end
- ruby
+ evaluate <<-ruby do
+ def m(a:, **k) [a, k] end
+ ruby
- m(a: 1).should == [1, {}]
- m(a: 1, b: 2, c: 3).should == [1, {b: 2, c: 3}]
- m("a" => 1, a: 1, b: 2).should == [1, {"a" => 1, b: 2}]
- end
+ m(a: 1).should == [1, {}]
+ m(a: 1, b: 2, c: 3).should == [1, {b: 2, c: 3}]
+ m("a" => 1, a: 1, b: 2).should == [1, {"a" => 1, b: 2}]
end
evaluate <<-ruby do
@@ -1637,125 +1100,66 @@ describe "A method" do
result.should == [1, 1, [], 2, 3, 2, 4, { h: 5, i: 6 }, l]
end
- ruby_version_is "2.7" do
- evaluate <<-ruby do
- def m(a, **nil); a end;
- ruby
+ evaluate <<-ruby do
+ def m(a, **nil); a end;
+ ruby
- m({a: 1}).should == {a: 1}
- m({"a" => 1}).should == {"a" => 1}
+ m({a: 1}).should == {a: 1}
+ m({"a" => 1}).should == {"a" => 1}
- -> { m(a: 1) }.should raise_error(ArgumentError)
- -> { m(**{a: 1}) }.should raise_error(ArgumentError)
- -> { m("a" => 1) }.should raise_error(ArgumentError)
- end
+ -> { m(a: 1) }.should raise_error(ArgumentError, 'no keywords accepted')
+ -> { m(**{a: 1}) }.should raise_error(ArgumentError, 'no keywords accepted')
+ -> { m("a" => 1) }.should raise_error(ArgumentError, 'no keywords accepted')
end
- ruby_version_is ''...'3.0' do
- evaluate <<-ruby do
- def m(a, b = nil, c = nil, d, e: nil, **f)
- [a, b, c, d, e, f]
- end
- ruby
-
- result = m(1, 2)
- result.should == [1, nil, nil, 2, nil, {}]
-
- suppress_warning do
- result = m(1, 2, {foo: :bar})
- result.should == [1, nil, nil, 2, nil, {foo: :bar}]
+ evaluate <<-ruby do
+ def m(a, b = nil, c = nil, d, e: nil, **f)
+ [a, b, c, d, e, f]
end
+ ruby
- result = m(1, {foo: :bar})
- result.should == [1, nil, nil, {foo: :bar}, nil, {}]
- end
- end
-
- ruby_version_is '3.0' do
- evaluate <<-ruby do
- def m(a, b = nil, c = nil, d, e: nil, **f)
- [a, b, c, d, e, f]
- end
- ruby
-
- result = m(1, 2)
- result.should == [1, nil, nil, 2, nil, {}]
+ result = m(1, 2)
+ result.should == [1, nil, nil, 2, nil, {}]
- result = m(1, 2, {foo: :bar})
- result.should == [1, 2, nil, {foo: :bar}, nil, {}]
+ result = m(1, 2, {foo: :bar})
+ result.should == [1, 2, nil, {foo: :bar}, nil, {}]
- result = m(1, {foo: :bar})
- result.should == [1, nil, nil, {foo: :bar}, nil, {}]
- end
+ result = m(1, {foo: :bar})
+ result.should == [1, nil, nil, {foo: :bar}, nil, {}]
end
end
- ruby_version_is '2.7' do
- context 'when passing an empty keyword splat to a method that does not accept keywords' do
- evaluate <<-ruby do
- def m(*a); a; end
- ruby
-
- h = {}
- m(**h).should == []
- end
- end
- end
-
- ruby_version_is '2.7'...'3.0' do
- context 'when passing an empty keyword splat to a method that does not accept keywords' do
- evaluate <<-ruby do
- def m(a); a; end
- ruby
- h = {}
+ context 'when passing an empty keyword splat to a method that does not accept keywords' do
+ evaluate <<-ruby do
+ def m(*a); a; end
+ ruby
- -> do
- m(**h).should == {}
- end.should complain(/warning: Passing the keyword argument as the last hash parameter is deprecated/)
- end
+ h = {}
+ m(**h).should == []
end
end
- ruby_version_is ''...'3.0' do
- context "assigns keyword arguments from a passed Hash without modifying it" do
- evaluate <<-ruby do
- def m(a: nil); a; end
- ruby
+ context 'when passing an empty keyword splat to a method that does not accept keywords' do
+ evaluate <<-ruby do
+ def m(a); a; end
+ ruby
+ h = {}
- options = {a: 1}.freeze
- -> do
- suppress_warning do
- m(options).should == 1
- end
- end.should_not raise_error
- options.should == {a: 1}
- end
+ -> do
+ m(**h).should == {}
+ end.should raise_error(ArgumentError)
end
end
- ruby_version_is '3.0' do
- context 'when passing an empty keyword splat to a method that does not accept keywords' do
- evaluate <<-ruby do
- def m(a); a; end
- ruby
- h = {}
-
- -> do
- m(**h).should == {}
- end.should raise_error(ArgumentError)
- end
- end
-
- context "raises ArgumentError if passing hash as keyword arguments" do
- evaluate <<-ruby do
- def m(a: nil); a; end
- ruby
+ context "raises ArgumentError if passing hash as keyword arguments" do
+ evaluate <<-ruby do
+ def m(a: nil); a; end
+ ruby
- options = {a: 1}.freeze
- -> do
- m(options)
- end.should raise_error(ArgumentError)
- end
+ options = {a: 1}.freeze
+ -> do
+ m(options)
+ end.should raise_error(ArgumentError)
end
end
@@ -1789,14 +1193,42 @@ describe "A method call with a space between method name and parentheses" do
end
end
- context "when a single argument provided" do
- it "assigns it" do
+ context "when a single argument is provided" do
+ it "assigns a simple expression" do
+ args = m (1)
+ args.should == [1]
+ end
+
+ it "assigns an expression consisting of multiple statements" do
+ args = m ((0; 1))
+ args.should == [1]
+ end
+
+ it "assigns one single statement, without the need of parentheses" do
args = m (1 == 1 ? true : false)
args.should == [true]
end
+
+ ruby_version_is "3.3" do
+ it "supports multiple statements" do
+ eval("m (1; 2)").should == [2]
+ end
+ end
+ end
+
+ context "when multiple arguments are provided" do
+ it "assigns simple expressions" do
+ args = m (1), (2)
+ args.should == [1, 2]
+ end
+
+ it "assigns expressions consisting of multiple statements" do
+ args = m ((0; 1)), ((2; 3))
+ args.should == [1, 3]
+ end
end
- context "when 2+ arguments provided" do
+ context "when the argument looks like an argument list" do
it "raises a syntax error" do
-> {
eval("m (1, 2)")
@@ -1861,86 +1293,108 @@ describe "An array-dereference method ([])" do
end
end
-ruby_version_is "3.0" do
- describe "An endless method definition" do
- context "without arguments" do
- evaluate <<-ruby do
- def m() = 42
- ruby
+describe "An endless method definition" do
+ context "without arguments" do
+ evaluate <<-ruby do
+ def m() = 42
+ ruby
- m.should == 42
- end
+ m.should == 42
end
- context "with arguments" do
+ context "without parenthesis" do
evaluate <<-ruby do
- def m(a, b) = a + b
- ruby
+ def m = 42
+ ruby
- m(1, 4).should == 5
+ m.should == 42
end
end
+ end
- context "with multiline body" do
- evaluate <<-ruby do
- def m(n) =
- if n > 2
- m(n - 2) + m(n - 1)
- else
- 1
- end
- ruby
+ context "with arguments" do
+ evaluate <<-ruby do
+ def m(a, b) = a + b
+ ruby
- m(6).should == 8
- end
+ m(1, 4).should == 5
end
+ end
- context "with args forwarding" do
- evaluate <<-ruby do
- def mm(word, num:)
- word * num
+ context "with multiline body" do
+ evaluate <<-ruby do
+ def m(n) =
+ if n > 2
+ m(n - 2) + m(n - 1)
+ else
+ 1
end
+ ruby
- def m(...) = mm(...) + mm(...)
- ruby
-
- m("meow", num: 2).should == "meow" * 4
- end
+ m(6).should == 8
end
end
- describe "Keyword arguments are now separated from positional arguments" do
- context "when the method has only positional parameters" do
- it "treats incoming keyword arguments as positional for compatibility" do
- def foo(a, b, c, hsh)
- hsh[:key]
+ # tested more thoroughly in language/delegation_spec.rb
+ context "with args forwarding" do
+ evaluate <<-ruby do
+ def mm(word, num:)
+ word * num
end
- foo(1, 2, 3, key: 42).should == 42
+ def m(...) = mm(...) + mm(...)
+ ruby
+
+ m("meow", num: 2).should == "meow" * 4
+ end
+ end
+end
+
+describe "Keyword arguments are now separated from positional arguments" do
+ context "when the method has only positional parameters" do
+ it "treats incoming keyword arguments as positional for compatibility" do
+ def foo(a, b, c, hsh)
+ hsh[:key]
end
+
+ foo(1, 2, 3, key: 42).should == 42
end
+ end
- context "when the method takes a ** parameter" do
- it "captures the passed literal keyword arguments" do
- def foo(a, b, c, **hsh)
- hsh[:key]
- end
+ context "when the method takes a ** parameter" do
+ it "captures the passed literal keyword arguments" do
+ def foo(a, b, c, **hsh)
+ hsh[:key]
+ end
+
+ foo(1, 2, 3, key: 42).should == 42
+ end
- foo(1, 2, 3, key: 42).should == 42
+ it "captures the passed ** keyword arguments" do
+ def foo(a, b, c, **hsh)
+ hsh[:key]
end
- it "captures the passed ** keyword arguments" do
- def foo(a, b, c, **hsh)
- hsh[:key]
- end
+ h = { key: 42 }
+ foo(1, 2, 3, **h).should == 42
+ end
- h = { key: 42 }
- foo(1, 2, 3, **h).should == 42
+ it "does not convert a positional Hash to keyword arguments" do
+ def foo(a, b, c, **hsh)
+ hsh[:key]
end
- it "does not convert a positional Hash to keyword arguments" do
- def foo(a, b, c, **hsh)
- hsh[:key]
+ -> {
+ foo(1, 2, 3, { key: 42 })
+ }.should raise_error(ArgumentError, 'wrong number of arguments (given 4, expected 3)')
+ end
+ end
+
+ context "when the method takes a key: parameter" do
+ context "when it's called with a positional Hash and no **" do
+ it "raises ArgumentError" do
+ def foo(a, b, c, key: 1)
+ key
end
-> {
@@ -1949,28 +1403,14 @@ ruby_version_is "3.0" do
end
end
- context "when the method takes a key: parameter" do
- context "when it's called with a positional Hash and no **" do
- it "raises ArgumentError" do
- def foo(a, b, c, key: 1)
- key
- end
-
- -> {
- foo(1, 2, 3, { key: 42 })
- }.should raise_error(ArgumentError, 'wrong number of arguments (given 4, expected 3)')
+ context "when it's called with **" do
+ it "captures the passed keyword arguments" do
+ def foo(a, b, c, key: 1)
+ key
end
- end
-
- context "when it's called with **" do
- it "captures the passed keyword arguments" do
- def foo(a, b, c, key: 1)
- key
- end
- h = { key: 42 }
- foo(1, 2, 3, **h).should == 42
- end
+ h = { key: 42 }
+ foo(1, 2, 3, **h).should == 42
end
end
end
@@ -2015,4 +1455,14 @@ ruby_version_is "3.1" do
end
end
end
+
+ describe "Inside 'endless' method definitions" do
+ it "allows method calls without parenthesis" do
+ eval <<-ruby
+ def greet(person) = "Hi, ".dup.concat person
+ ruby
+
+ greet("Homer").should == "Hi, Homer"
+ end
+ end
end
diff --git a/spec/ruby/language/module_spec.rb b/spec/ruby/language/module_spec.rb
index 1a5fcaf46f..fffcf9c90d 100644
--- a/spec/ruby/language/module_spec.rb
+++ b/spec/ruby/language/module_spec.rb
@@ -28,9 +28,18 @@ describe "The module keyword" do
ModuleSpecs::Reopened.should be_true
end
- it "reopens a module included in Object" do
- module IncludedModuleSpecs; Reopened = true; end
- ModuleSpecs::IncludedInObject::IncludedModuleSpecs::Reopened.should be_true
+ ruby_version_is '3.2' do
+ it "does not reopen a module included in Object" do
+ module IncludedModuleSpecs; Reopened = true; end
+ ModuleSpecs::IncludedInObject::IncludedModuleSpecs.should_not == Object::IncludedModuleSpecs
+ end
+ end
+
+ ruby_version_is ''...'3.2' do
+ it "reopens a module included in Object" do
+ module IncludedModuleSpecs; Reopened = true; end
+ ModuleSpecs::IncludedInObject::IncludedModuleSpecs::Reopened.should be_true
+ end
end
it "raises a TypeError if the constant is a Class" do
@@ -69,20 +78,10 @@ describe "Assigning an anonymous module to a constant" do
mod.name.should == "ModuleSpecs_CS1"
end
- ruby_version_is ""..."3.0" do
- it "does not set the name of a module scoped by an anonymous module" do
- a, b = Module.new, Module.new
- a::B = b
- b.name.should be_nil
- end
- end
-
- ruby_version_is "3.0" do
- it "sets the name of a module scoped by an anonymous module" do
- a, b = Module.new, Module.new
- a::B = b
- b.name.should.end_with? '::B'
- end
+ it "sets the name of a module scoped by an anonymous module" do
+ a, b = Module.new, Module.new
+ a::B = b
+ b.name.should.end_with? '::B'
end
it "sets the name of contained modules when assigning a toplevel anonymous module" do
diff --git a/spec/ruby/language/numbered_parameters_spec.rb b/spec/ruby/language/numbered_parameters_spec.rb
index 838822b2d6..06f9948c58 100644
--- a/spec/ruby/language/numbered_parameters_spec.rb
+++ b/spec/ruby/language/numbered_parameters_spec.rb
@@ -1,120 +1,104 @@
require_relative '../spec_helper'
-ruby_version_is "2.7" do
- describe "Numbered parameters" do
- it "provides default parameters _1, _2, ... in a block" do
- -> { _1 }.call("a").should == "a"
- proc { _1 }.call("a").should == "a"
- lambda { _1 }.call("a").should == "a"
- ["a"].map { _1 }.should == ["a"]
- end
+describe "Numbered parameters" do
+ it "provides default parameters _1, _2, ... in a block" do
+ -> { _1 }.call("a").should == "a"
+ proc { _1 }.call("a").should == "a"
+ lambda { _1 }.call("a").should == "a"
+ ["a"].map { _1 }.should == ["a"]
+ end
- it "assigns nil to not passed parameters" do
- proc { [_1, _2] }.call("a").should == ["a", nil]
- proc { [_1, _2] }.call("a", "b").should == ["a", "b"]
- end
+ it "assigns nil to not passed parameters" do
+ proc { [_1, _2] }.call("a").should == ["a", nil]
+ proc { [_1, _2] }.call("a", "b").should == ["a", "b"]
+ end
- it "supports variables _1-_9 only for the first 9 passed parameters" do
- block = proc { [_1, _2, _3, _4, _5, _6, _7, _8, _9] }
- result = block.call(1, 2, 3, 4, 5, 6, 7, 8, 9)
- result.should == [1, 2, 3, 4, 5, 6, 7, 8, 9]
- end
+ it "supports variables _1-_9 only for the first 9 passed parameters" do
+ block = proc { [_1, _2, _3, _4, _5, _6, _7, _8, _9] }
+ result = block.call(1, 2, 3, 4, 5, 6, 7, 8, 9)
+ result.should == [1, 2, 3, 4, 5, 6, 7, 8, 9]
+ end
- it "does not support more than 9 parameters" do
- -> {
- proc { [_10] }.call(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
- }.should raise_error(NameError, /undefined local variable or method `_10'/)
- end
+ it "does not support more than 9 parameters" do
+ -> {
+ proc { [_10] }.call(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
+ }.should raise_error(NameError, /undefined local variable or method [`']_10'/)
+ end
- it "can not be used in both outer and nested blocks at the same time" do
- -> {
- eval("-> { _1; -> { _2 } }")
- }.should raise_error(SyntaxError, /numbered parameter is already used in/m)
- end
+ it "can not be used in both outer and nested blocks at the same time" do
+ -> {
+ eval("-> { _1; -> { _2 } }")
+ }.should raise_error(SyntaxError, /numbered parameter is already used in/m)
+ end
- ruby_version_is '2.7'...'3.0' do
- it "can be overwritten with local variable" do
- suppress_warning do
- eval <<~CODE
- _1 = 0
- proc { _1 }.call("a").should == 0
- CODE
- end
- end
-
- it "warns when numbered parameter is overwritten with local variable" do
- -> {
- eval("_1 = 0")
- }.should complain(/warning: `_1' is reserved for numbered parameter; consider another name/)
- end
- end
+ it "cannot be overwritten with local variable" do
+ -> {
+ eval <<~CODE
+ _1 = 0
+ proc { _1 }.call("a").should == 0
+ CODE
+ }.should raise_error(SyntaxError, /_1 is reserved for numbered parameter/)
+ end
- ruby_version_is '3.0' do
- it "cannot be overwritten with local variable" do
- -> {
- eval <<~CODE
- _1 = 0
- proc { _1 }.call("a").should == 0
- CODE
- }.should raise_error(SyntaxError, /_1 is reserved for numbered parameter/)
- end
-
- it "errors when numbered parameter is overwritten with local variable" do
- -> {
- eval("_1 = 0")
- }.should raise_error(SyntaxError, /_1 is reserved for numbered parameter/)
- end
- end
+ it "errors when numbered parameter is overwritten with local variable" do
+ -> {
+ eval("_1 = 0")
+ }.should raise_error(SyntaxError, /_1 is reserved for numbered parameter/)
+ end
- it "raises SyntaxError when block parameters are specified explicitly" do
- -> { eval("-> () { _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/)
- -> { eval("-> (x) { _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/)
+ it "raises SyntaxError when block parameters are specified explicitly" do
+ -> { eval("-> () { _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/)
+ -> { eval("-> (x) { _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/)
- -> { eval("proc { || _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/)
- -> { eval("proc { |x| _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/)
+ -> { eval("proc { || _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/)
+ -> { eval("proc { |x| _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/)
- -> { eval("lambda { || _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/)
- -> { eval("lambda { |x| _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/)
+ -> { eval("lambda { || _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/)
+ -> { eval("lambda { |x| _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/)
- -> { eval("['a'].map { || _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/)
- -> { eval("['a'].map { |x| _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/)
- end
+ -> { eval("['a'].map { || _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/)
+ -> { eval("['a'].map { |x| _1 }") }.should raise_error(SyntaxError, /ordinary parameter is defined/)
+ end
- describe "assigning to a numbered parameter" do
- ruby_version_is '2.7'...'3.0' do
- it "warns" do
- -> { eval("proc { _1 = 0 }") }.should complain(/warning: `_1' is reserved for numbered parameter; consider another name/)
- end
- end
-
- ruby_version_is '3.0' do
- it "raises SyntaxError" do
- -> { eval("proc { _1 = 0 }") }.should raise_error(SyntaxError, /_1 is reserved for numbered parameter/)
- end
- end
+ describe "assigning to a numbered parameter" do
+ it "raises SyntaxError" do
+ -> { eval("proc { _1 = 0 }") }.should raise_error(SyntaxError, /_1 is reserved for numbered parameter/)
end
+ end
- it "affects block arity" do
- -> { _1 }.arity.should == 1
- -> { _2 }.arity.should == 2
- -> { _3 }.arity.should == 3
- -> { _4 }.arity.should == 4
- -> { _5 }.arity.should == 5
- -> { _6 }.arity.should == 6
- -> { _7 }.arity.should == 7
- -> { _8 }.arity.should == 8
- -> { _9 }.arity.should == 9
-
- -> { _9 }.arity.should == 9
- proc { _9 }.arity.should == 9
- lambda { _9 }.arity.should == 9
- end
+ it "affects block arity" do
+ -> { _1 }.arity.should == 1
+ -> { _2 }.arity.should == 2
+ -> { _3 }.arity.should == 3
+ -> { _4 }.arity.should == 4
+ -> { _5 }.arity.should == 5
+ -> { _6 }.arity.should == 6
+ -> { _7 }.arity.should == 7
+ -> { _8 }.arity.should == 8
+ -> { _9 }.arity.should == 9
+
+ -> { _9 }.arity.should == 9
+ proc { _9 }.arity.should == 9
+ lambda { _9 }.arity.should == 9
+ end
- it "does not work in methods" do
- obj = Object.new
- def obj.foo; _1 end
+ it "affects block parameters" do
+ -> { _1 }.parameters.should == [[:req, :_1]]
+ -> { _2 }.parameters.should == [[:req, :_1], [:req, :_2]]
- -> { obj.foo("a") }.should raise_error(ArgumentError, /wrong number of arguments/)
- end
+ proc { _1 }.parameters.should == [[:opt, :_1]]
+ proc { _2 }.parameters.should == [[:opt, :_1], [:opt, :_2]]
+ end
+
+ it "affects binding local variables" do
+ -> { _1; binding.local_variables }.call("a").should == [:_1]
+ -> { _2; binding.local_variables }.call("a", "b").should == [:_1, :_2]
+ end
+
+ it "does not work in methods" do
+ obj = Object.new
+ def obj.foo; _1 end
+
+ -> { obj.foo("a") }.should raise_error(ArgumentError, /wrong number of arguments/)
end
end
diff --git a/spec/ruby/language/optional_assignments_spec.rb b/spec/ruby/language/optional_assignments_spec.rb
index 217dcab74b..2443cc6b79 100644
--- a/spec/ruby/language/optional_assignments_spec.rb
+++ b/spec/ruby/language/optional_assignments_spec.rb
@@ -57,7 +57,7 @@ describe 'Optional variable assignments' do
end
end
- describe 'using a accessor' do
+ describe 'using an accessor' do
before do
klass = Class.new { attr_accessor :b }
@a = klass.new
@@ -103,6 +103,16 @@ describe 'Optional variable assignments' do
@a.b.should == 10
end
+ it 'does evaluate receiver only once when assigns' do
+ ScratchPad.record []
+ @a.b = nil
+
+ (ScratchPad << :evaluated; @a).b ||= 10
+
+ ScratchPad.recorded.should == [:evaluated]
+ @a.b.should == 10
+ end
+
it 'returns the new value if set to false' do
def @a.b=(x)
:v
@@ -122,29 +132,148 @@ describe 'Optional variable assignments' do
(@a.b ||= 20).should == 10
end
- it 'works when writer is private' do
+ it 'ignores method visibility when receiver is self' do
+ klass_with_private_methods = Class.new do
+ def initialize(v) @a = v end
+ def public_method(v); self.a ||= v end
+ private
+ def a; @a end
+ def a=(v) @a = v; 42 end
+ end
+
+ a = klass_with_private_methods.new(false)
+ a.public_method(10).should == 10
+ end
+ end
+
+ describe 'using a #[]' do
+ before do
+ @a = {}
klass = Class.new do
- def t
- self.b = false
- (self.b ||= 10).should == 10
- (self.b ||= 20).should == 10
+ def [](k)
+ @hash ||= {}
+ @hash[k]
end
- def b
- @b
+ def []=(k, v)
+ @hash ||= {}
+ @hash[k] = v
+ 7
end
+ end
+ @b = klass.new
+ end
+
+ it 'returns the assigned value, not the result of the []= method with ||=' do
+ (@b[:k] ||= 12).should == 12
+ end
- def b=(x)
- @b = x
- :v
+ it "evaluates the index precisely once" do
+ ary = [:x, :y]
+ @a[:x] = 15
+ @a[ary.pop] ||= 25
+ ary.should == [:x]
+ @a.should == { x: 15, y: 25 }
+ end
+
+ it "evaluates the index arguments in the correct order" do
+ ary = Class.new(Array) do
+ def [](x, y)
+ super(x + 3 * y)
+ end
+
+ def []=(x, y, value)
+ super(x + 3 * y, value)
end
+ end.new
+ ary[0, 0] = 1
+ ary[1, 0] = 1
+ ary[2, 0] = nil
+ ary[3, 0] = 1
+ ary[4, 0] = 1
+ ary[5, 0] = 1
+ ary[6, 0] = nil
+
+ foo = [0, 2]
+
+ ary[foo.pop, foo.pop] ||= 2 # expected `ary[2, 0] ||= 2`
+
+ ary[2, 0].should == 2
+ ary[6, 0].should == nil # returns the same element as `ary[0, 2]`
+ end
+
+ it 'evaluates receiver only once when assigns' do
+ ScratchPad.record []
+ @a[:k] = nil
+
+ (ScratchPad << :evaluated; @a)[:k] ||= 2
- private :b=
+ ScratchPad.recorded.should == [:evaluated]
+ @a[:k].should == 2
+ end
+
+ it 'ignores method visibility when receiver is self' do
+ klass_with_private_methods = Class.new do
+ def initialize(h) @a = h end
+ def public_method(k, v); self[k] ||= v end
+ private
+ def [](k) @a[k] end
+ def []=(k, v) @a[k] = v; 42 end
end
- klass.new.t
+ a = klass_with_private_methods.new(k: false)
+ a.public_method(:k, 10).should == 10
end
+ context 'splatted argument' do
+ it 'correctly handles it' do
+ (@b[*[:m]] ||= 10).should == 10
+ @b[:m].should == 10
+
+ (@b[*(1; [:n])] ||= 10).should == 10
+ @b[:n].should == 10
+
+ (@b[*begin 1; [:k] end] ||= 10).should == 10
+ @b[:k].should == 10
+ end
+
+ it 'calls #to_a only once' do
+ k = Object.new
+ def k.to_a
+ ScratchPad << :to_a
+ [:k]
+ end
+
+ ScratchPad.record []
+ (@b[*k] ||= 20).should == 20
+ @b[:k].should == 20
+ ScratchPad.recorded.should == [:to_a]
+ end
+
+ it 'correctly handles a nested splatted argument' do
+ (@b[*[*[:k]]] ||= 20).should == 20
+ @b[:k].should == 20
+ end
+
+ it 'correctly handles multiple nested splatted arguments' do
+ klass_with_multiple_parameters = Class.new do
+ def [](k1, k2, k3)
+ @hash ||= {}
+ @hash[:"#{k1}#{k2}#{k3}"]
+ end
+
+ def []=(k1, k2, k3, v)
+ @hash ||= {}
+ @hash[:"#{k1}#{k2}#{k3}"] = v
+ 7
+ end
+ end
+ a = klass_with_multiple_parameters.new
+
+ (a[*[:a], *[:b], *[:c]] ||= 20).should == 20
+ a[:a, :b, :c].should == 20
+ end
+ end
end
end
@@ -191,7 +320,7 @@ describe 'Optional variable assignments' do
end
end
- describe 'using a single variable' do
+ describe 'using an accessor' do
before do
klass = Class.new { attr_accessor :b }
@a = klass.new
@@ -236,6 +365,29 @@ describe 'Optional variable assignments' do
@a.b.should == 20
end
+
+ it 'does evaluate receiver only once when assigns' do
+ ScratchPad.record []
+ @a.b = 10
+
+ (ScratchPad << :evaluated; @a).b &&= 20
+
+ ScratchPad.recorded.should == [:evaluated]
+ @a.b.should == 20
+ end
+
+ it 'ignores method visibility when receiver is self' do
+ klass_with_private_methods = Class.new do
+ def initialize(v) @a = v end
+ def public_method(v); self.a &&= v end
+ private
+ def a; @a end
+ def a=(v) @a = v; 42 end
+ end
+
+ a = klass_with_private_methods.new(true)
+ a.public_method(10).should == 10
+ end
end
describe 'using a #[]' do
@@ -297,13 +449,128 @@ describe 'Optional variable assignments' do
end
it 'returns the assigned value, not the result of the []= method with ||=' do
- (@b[:k] ||= 12).should == 12
+ @b[:k] = 10
+ (@b[:k] &&= 12).should == 12
+ end
+
+ it "evaluates the index precisely once" do
+ ary = [:x, :y]
+ @a[:x] = 15
+ @a[:y] = 20
+ @a[ary.pop] &&= 25
+ ary.should == [:x]
+ @a.should == { x: 15, y: 25 }
+ end
+
+ it "evaluates the index arguments in the correct order" do
+ ary = Class.new(Array) do
+ def [](x, y)
+ super(x + 3 * y)
+ end
+
+ def []=(x, y, value)
+ super(x + 3 * y, value)
+ end
+ end.new
+ ary[0, 0] = 1
+ ary[1, 0] = 1
+ ary[2, 0] = 1
+ ary[3, 0] = 1
+ ary[4, 0] = 1
+ ary[5, 0] = 1
+ ary[6, 0] = 1
+
+ foo = [0, 2]
+
+ ary[foo.pop, foo.pop] &&= 2 # expected `ary[2, 0] &&= 2`
+
+ ary[2, 0].should == 2
+ ary[6, 0].should == 1 # returns the same element as `ary[0, 2]`
+ end
+
+ it 'evaluates receiver only once when assigns' do
+ ScratchPad.record []
+ @a[:k] = 1
+
+ (ScratchPad << :evaluated; @a)[:k] &&= 2
+
+ ScratchPad.recorded.should == [:evaluated]
+ @a[:k].should == 2
end
it 'returns the assigned value, not the result of the []= method with +=' do
@b[:k] = 17
(@b[:k] += 12).should == 29
end
+
+ it 'ignores method visibility when receiver is self' do
+ klass_with_private_methods = Class.new do
+ def initialize(h) @a = h end
+ def public_method(k, v); self[k] &&= v end
+ private
+ def [](k) @a[k] end
+ def []=(k, v) @a[k] = v; 42 end
+ end
+
+ a = klass_with_private_methods.new(k: true)
+ a.public_method(:k, 10).should == 10
+ end
+
+ context 'splatted argument' do
+ it 'correctly handles it' do
+ @b[:m] = 0
+ (@b[*[:m]] &&= 10).should == 10
+ @b[:m].should == 10
+
+ @b[:n] = 0
+ (@b[*(1; [:n])] &&= 10).should == 10
+ @b[:n].should == 10
+
+ @b[:k] = 0
+ (@b[*begin 1; [:k] end] &&= 10).should == 10
+ @b[:k].should == 10
+ end
+
+ it 'calls #to_a only once' do
+ k = Object.new
+ def k.to_a
+ ScratchPad << :to_a
+ [:k]
+ end
+
+ ScratchPad.record []
+ @b[:k] = 10
+ (@b[*k] &&= 20).should == 20
+ @b[:k].should == 20
+ ScratchPad.recorded.should == [:to_a]
+ end
+
+ it 'correctly handles a nested splatted argument' do
+ @b[:k] = 10
+ (@b[*[*[:k]]] &&= 20).should == 20
+ @b[:k].should == 20
+ end
+
+ it 'correctly handles multiple nested splatted arguments' do
+ klass_with_multiple_parameters = Class.new do
+ def [](k1, k2, k3)
+ @hash ||= {}
+ @hash[:"#{k1}#{k2}#{k3}"]
+ end
+
+ def []=(k1, k2, k3, v)
+ @hash ||= {}
+ @hash[:"#{k1}#{k2}#{k3}"] = v
+ 7
+ end
+ end
+ a = klass_with_multiple_parameters.new
+
+ a[:a, :b, :c] = 10
+ (a[*[:a], *[:b], *[:c]] &&= 20).should == 20
+ a[:a, :b, :c].should == 20
+ end
+ end
end
end
@@ -396,7 +663,7 @@ describe 'Optional constant assignment' do
ConstantSpecs::ClassA::OR_ASSIGNED_CONSTANT2.should == :assigned
end
- it 'causes side-effects of the module part to be applied (for nil constant)' do
+ it 'causes side-effects of the module part to be applied only once (for nil constant)' do
suppress_warning do # already initialized constant
ConstantSpecs::ClassA::NIL_OR_ASSIGNED_CONSTANT2 = nil
x = 0
@@ -454,5 +721,20 @@ describe 'Optional constant assignment' do
ConstantSpecs::OpAssignFalse.should == false
ConstantSpecs.send :remove_const, :OpAssignFalse
end
+
+ it 'causes side-effects of the module part to be applied only once (when assigns)' do
+ module ConstantSpecs
+ OpAssignTrue = true
+ end
+
+ suppress_warning do # already initialized constant
+ x = 0
+ (x += 1; ConstantSpecs)::OpAssignTrue &&= :assigned
+ x.should == 1
+ ConstantSpecs::OpAssignTrue.should == :assigned
+ end
+
+ ConstantSpecs.send :remove_const, :OpAssignTrue
+ end
end
end
diff --git a/spec/ruby/language/pattern_matching_spec.rb b/spec/ruby/language/pattern_matching_spec.rb
index 5f5e2f4902..a8ec078cd0 100644
--- a/spec/ruby/language/pattern_matching_spec.rb
+++ b/spec/ruby/language/pattern_matching_spec.rb
@@ -1,196 +1,370 @@
require_relative '../spec_helper'
-ruby_version_is "2.7" do
- describe "Pattern matching" do
- # TODO: Remove excessive eval calls when support of previous version
- # Ruby 2.6 will be dropped
+describe "Pattern matching" do
+ # TODO: Remove excessive eval calls when Ruby 3 is the minimum version.
+ # It is best to keep the eval's longer if other Ruby impls cannot parse pattern matching yet.
- before :each do
- ScratchPad.record []
+ before :each do
+ ScratchPad.record []
+ end
+
+ describe "can be standalone assoc operator that" do
+ it "deconstructs value" do
+ suppress_warning do
+ eval(<<-RUBY).should == [0, 1]
+ [0, 1] => [a, b]
+ [a, b]
+ RUBY
+ end
end
- ruby_version_is "3.0" do
- it "can be standalone assoc operator that deconstructs value" do
- suppress_warning do
- eval(<<-RUBY).should == [0, 1]
+ it "deconstructs value and properly scopes variables" do
+ suppress_warning do
+ eval(<<-RUBY).should == [0, nil]
+ a = nil
+ eval(<<-PATTERN)
[0, 1] => [a, b]
- [a, b]
- RUBY
- end
+ PATTERN
+ [a, defined?(b)]
+ RUBY
end
+ end
+ end
- describe "find pattern" do
- it "captures preceding elements to the pattern" do
- eval(<<~RUBY).should == [0, 1]
- case [0, 1, 2, 3]
- in [*pre, 2, 3]
- pre
- else
- false
- end
- RUBY
+ describe "find pattern" do
+ it "captures preceding elements to the pattern" do
+ eval(<<~RUBY).should == [0, 1]
+ case [0, 1, 2, 3]
+ in [*pre, 2, 3]
+ pre
+ else
+ false
end
+ RUBY
+ end
- it "captures following elements to the pattern" do
- eval(<<~RUBY).should == [2, 3]
- case [0, 1, 2, 3]
- in [0, 1, *post]
- post
- else
- false
- end
- RUBY
+ it "captures following elements to the pattern" do
+ eval(<<~RUBY).should == [2, 3]
+ case [0, 1, 2, 3]
+ in [0, 1, *post]
+ post
+ else
+ false
end
+ RUBY
+ end
- it "captures both preceding and following elements to the pattern" do
- eval(<<~RUBY).should == [[0, 1], [3, 4]]
- case [0, 1, 2, 3, 4]
- in [*pre, 2, *post]
- [pre, post]
- else
- false
- end
- RUBY
+ it "captures both preceding and following elements to the pattern" do
+ eval(<<~RUBY).should == [[0, 1], [3, 4]]
+ case [0, 1, 2, 3, 4]
+ in [*pre, 2, *post]
+ [pre, post]
+ else
+ false
end
+ RUBY
+ end
- it "can capture the entirety of the pattern" do
- eval(<<~RUBY).should == [0, 1, 2, 3, 4]
- case [0, 1, 2, 3, 4]
- in [*everything]
- everything
- else
- false
- end
- RUBY
+ it "can capture the entirety of the pattern" do
+ eval(<<~RUBY).should == [0, 1, 2, 3, 4]
+ case [0, 1, 2, 3, 4]
+ in [*everything]
+ everything
+ else
+ false
end
+ RUBY
+ end
- it "will match an empty Array-like structure" do
- eval(<<~RUBY).should == []
- case []
- in [*everything]
- everything
- else
- false
- end
- RUBY
+ it "will match an empty Array-like structure" do
+ eval(<<~RUBY).should == []
+ case []
+ in [*everything]
+ everything
+ else
+ false
end
- end
+ RUBY
end
- it "extends case expression with case/in construction" do
- eval(<<~RUBY).should == :bar
- case [0, 1]
- in [0]
- :foo
- in [0, 1]
- :bar
+ it "can be nested" do
+ eval(<<~RUBY).should == [[0, [2, 4, 6]], [[4, 16, 64]], 27]
+ case [0, [2, 4, 6], [3, 9, 27], [4, 16, 64]]
+ in [*pre, [*, 9, a], *post]
+ [pre, post, a]
+ else
+ false
end
RUBY
end
- it "allows using then operator" do
- eval(<<~RUBY).should == :bar
- case [0, 1]
- in [0] then :foo
- in [0, 1] then :bar
+ it "can be nested with an array pattern" do
+ eval(<<~RUBY).should == [[4, 16, 64]]
+ case [0, [2, 4, 6], [3, 9, 27], [4, 16, 64]]
+ in [_, _, [*, 9, *], *post]
+ post
+ else
+ false
end
RUBY
end
- describe "warning" do
+ it "can be nested within a hash pattern" do
+ eval(<<~RUBY).should == [27]
+ case {a: [3, 9, 27]}
+ in {a: [*, 9, *post]}
+ post
+ else
+ false
+ end
+ RUBY
+ end
+
+ it "can nest hash and array patterns" do
+ eval(<<~RUBY).should == [42, 2]
+ case [0, {a: 42, b: [0, 1]}, {a: 42, b: [1, 2]}]
+ in [*, {a:, b: [1, c]}, *]
+ [a, c]
+ else
+ false
+ end
+ RUBY
+ end
+ end
+
+ it "extends case expression with case/in construction" do
+ eval(<<~RUBY).should == :bar
+ case [0, 1]
+ in [0]
+ :foo
+ in [0, 1]
+ :bar
+ end
+ RUBY
+ end
+
+ it "allows using then operator" do
+ eval(<<~RUBY).should == :bar
+ case [0, 1]
+ in [0] then :foo
+ in [0, 1] then :bar
+ end
+ RUBY
+ end
+
+ describe "warning" do
+ before :each do
+ @experimental, Warning[:experimental] = Warning[:experimental], true
+ end
+
+ after :each do
+ Warning[:experimental] = @experimental
+ end
+
+ context 'when regular form' do
before :each do
- @experimental, Warning[:experimental] = Warning[:experimental], true
+ @src = 'case [0, 1]; in [a, b]; end'
end
- after :each do
- Warning[:experimental] = @experimental
+ it "does not warn about pattern matching is experimental feature" do
+ -> { eval @src }.should_not complain
end
+ end
- context 'when regular form' do
- before :each do
- @src = 'case [0, 1]; in [a, b]; end'
+ context 'when one-line form' do
+ before :each do
+ @src = '[0, 1] => [a, b]'
+ end
+
+ ruby_version_is ""..."3.1" do
+ it "warns about pattern matching is experimental feature" do
+ -> { eval @src }.should complain(/pattern matching is experimental, and the behavior may change in future versions of Ruby!/i)
end
+ end
- ruby_version_is ""..."3.0" do
- it "warns about pattern matching is experimental feature" do
- -> { eval @src }.should complain(/pattern matching is experimental, and the behavior may change in future versions of Ruby!/i)
- end
+ ruby_version_is "3.1" do
+ it "does not warn about pattern matching is experimental feature" do
+ -> { eval @src }.should_not complain
+ end
+ end
+ end
+ end
+
+ it "binds variables" do
+ eval(<<~RUBY).should == 1
+ case [0, 1]
+ in [0, a]
+ a
+ end
+ RUBY
+ end
+
+ it "cannot mix in and when operators" do
+ -> {
+ eval <<~RUBY
+ case []
+ when 1 == 1
+ in []
end
+ RUBY
+ }.should raise_error(SyntaxError, /syntax error, unexpected `in'|\(eval\):3: syntax error, unexpected keyword_in|unexpected 'in'/)
- ruby_version_is "3.0" do
- it "does not warn about pattern matching is experimental feature" do
- -> { eval @src }.should_not complain
- end
+ -> {
+ eval <<~RUBY
+ case []
+ in []
+ when 1 == 1
end
+ RUBY
+ }.should raise_error(SyntaxError, /syntax error, unexpected `when'|\(eval\):3: syntax error, unexpected keyword_when|unexpected 'when'/)
+ end
+
+ it "checks patterns until the first matching" do
+ eval(<<~RUBY).should == :bar
+ case [0, 1]
+ in [0]
+ :foo
+ in [0, 1]
+ :bar
+ in [0, 1]
+ :baz
+ end
+ RUBY
+ end
+
+ it "executes else clause if no pattern matches" do
+ eval(<<~RUBY).should == false
+ case [0, 1]
+ in [0]
+ true
+ else
+ false
end
+ RUBY
+ end
- context 'when one-line form' do
- ruby_version_is '3.0' do
- before :each do
- @src = '[0, 1] => [a, b]'
- end
+ it "raises NoMatchingPatternError if no pattern matches and no else clause" do
+ -> {
+ eval <<~RUBY
+ case [0, 1]
+ in [0]
+ end
+ RUBY
+ }.should raise_error(NoMatchingPatternError, /\[0, 1\]/)
+ end
- ruby_version_is ""..."3.1" do
- it "warns about pattern matching is experimental feature" do
- -> { eval @src }.should complain(/pattern matching is experimental, and the behavior may change in future versions of Ruby!/i)
- end
- end
+ it "raises NoMatchingPatternError if no pattern matches and evaluates the expression only once" do
+ evals = 0
+ -> {
+ eval <<~RUBY
+ case (evals += 1; [0, 1])
+ in [0]
+ end
+ RUBY
+ }.should raise_error(NoMatchingPatternError, /\[0, 1\]/)
+ evals.should == 1
+ end
- ruby_version_is "3.1" do
- it "does not warn about pattern matching is experimental feature" do
- -> { eval @src }.should_not complain
- end
- end
+ it "does not allow calculation or method calls in a pattern" do
+ -> {
+ eval <<~RUBY
+ case 0
+ in 1 + 1
+ true
end
+ RUBY
+ }.should raise_error(SyntaxError, /unexpected|expected a delimiter after the predicates of a `when` clause/)
+ end
+
+ it "evaluates the case expression once for multiple patterns, caching the result" do
+ eval(<<~RUBY).should == true
+ case (ScratchPad << :foo; 1)
+ in 0
+ false
+ in 1
+ true
end
+ RUBY
+
+ ScratchPad.recorded.should == [:foo]
+ end
+
+ describe "guards" do
+ it "supports if guard" do
+ eval(<<~RUBY).should == false
+ case 0
+ in 0 if false
+ true
+ else
+ false
+ end
+ RUBY
+
+ eval(<<~RUBY).should == true
+ case 0
+ in 0 if true
+ true
+ else
+ false
+ end
+ RUBY
end
- it "binds variables" do
- eval(<<~RUBY).should == 1
+ it "supports unless guard" do
+ eval(<<~RUBY).should == false
+ case 0
+ in 0 unless true
+ true
+ else
+ false
+ end
+ RUBY
+
+ eval(<<~RUBY).should == true
+ case 0
+ in 0 unless false
+ true
+ else
+ false
+ end
+ RUBY
+ end
+
+ it "makes bound variables visible in guard" do
+ eval(<<~RUBY).should == true
case [0, 1]
- in [0, a]
- a
+ in [a, 1] if a >= 0
+ true
end
RUBY
end
- it "cannot mix in and when operators" do
- -> {
- eval <<~RUBY
- case []
- when 1 == 1
- in []
- end
- RUBY
- }.should raise_error(SyntaxError, /syntax error, unexpected `in'/)
+ it "does not evaluate guard if pattern does not match" do
+ eval <<~RUBY
+ case 0
+ in 1 if (ScratchPad << :foo) || true
+ else
+ end
+ RUBY
- -> {
- eval <<~RUBY
- case []
- in []
- when 1 == 1
- end
- RUBY
- }.should raise_error(SyntaxError, /syntax error, unexpected `when'/)
+ ScratchPad.recorded.should == []
end
- it "checks patterns until the first matching" do
+ it "takes guards into account when there are several matching patterns" do
eval(<<~RUBY).should == :bar
- case [0, 1]
- in [0]
+ case 0
+ in 0 if false
:foo
- in [0, 1]
+ in 0 if true
:bar
- in [0, 1]
- :baz
end
RUBY
end
- it "executes else clause if no pattern matches" do
+ it "executes else clause if no guarded pattern matches" do
eval(<<~RUBY).should == false
- case [0, 1]
- in [0]
+ case 0
+ in 0 if false
true
else
false
@@ -198,1093 +372,1030 @@ ruby_version_is "2.7" do
RUBY
end
- it "raises NoMatchingPatternError if no pattern matches and no else clause" do
+ it "raises NoMatchingPatternError if no guarded pattern matches and no else clause" do
-> {
eval <<~RUBY
case [0, 1]
- in [0]
+ in [0, 1] if false
end
RUBY
}.should raise_error(NoMatchingPatternError, /\[0, 1\]/)
end
+ end
- it "does not allow calculation or method calls in a pattern" do
- -> {
- eval <<~RUBY
- case 0
- in 1 + 1
- true
- end
- RUBY
- }.should raise_error(SyntaxError, /unexpected/)
- end
-
- it "evaluates the case expression once for multiple patterns, caching the result" do
+ describe "value pattern" do
+ it "matches an object such that pattern === object" do
eval(<<~RUBY).should == true
- case (ScratchPad << :foo; 1)
+ case 0
in 0
- false
- in 1
true
end
RUBY
- ScratchPad.recorded.should == [:foo]
- end
-
- describe "guards" do
- it "supports if guard" do
- eval(<<~RUBY).should == false
- case 0
- in 0 if false
- true
- else
- false
- end
- RUBY
-
- eval(<<~RUBY).should == true
- case 0
- in 0 if true
- true
- else
- false
- end
- RUBY
- end
-
- it "supports unless guard" do
- eval(<<~RUBY).should == false
- case 0
- in 0 unless true
- true
- else
- false
- end
- RUBY
-
- eval(<<~RUBY).should == true
- case 0
- in 0 unless false
- true
- else
- false
- end
- RUBY
- end
-
- it "makes bound variables visible in guard" do
- eval(<<~RUBY).should == true
- case [0, 1]
- in [a, 1] if a >= 0
- true
- end
- RUBY
- end
-
- it "does not evaluate guard if pattern does not match" do
- eval <<~RUBY
- case 0
- in 1 if (ScratchPad << :foo) || true
- else
- end
- RUBY
-
- ScratchPad.recorded.should == []
- end
+ eval(<<~RUBY).should == true
+ case 0
+ in (-1..1)
+ true
+ end
+ RUBY
- it "takes guards into account when there are several matching patterns" do
- eval(<<~RUBY).should == :bar
- case 0
- in 0 if false
- :foo
- in 0 if true
- :bar
- end
- RUBY
- end
+ eval(<<~RUBY).should == true
+ case 0
+ in Integer
+ true
+ end
+ RUBY
- it "executes else clause if no guarded pattern matches" do
- eval(<<~RUBY).should == false
- case 0
- in 0 if false
- true
- else
- false
- end
- RUBY
- end
+ eval(<<~RUBY).should == true
+ case "0"
+ in /0/
+ true
+ end
+ RUBY
- it "raises NoMatchingPatternError if no guarded pattern matches and no else clause" do
- -> {
- eval <<~RUBY
- case [0, 1]
- in [0, 1] if false
- end
- RUBY
- }.should raise_error(NoMatchingPatternError, /\[0, 1\]/)
- end
+ eval(<<~RUBY).should == true
+ case "0"
+ in ->(s) { s == "0" }
+ true
+ end
+ RUBY
end
- describe "value pattern" do
- it "matches an object such that pattern === object" do
- eval(<<~RUBY).should == true
- case 0
- in 0
- true
- end
- RUBY
-
- eval(<<~RUBY).should == true
- case 0
- in (-1..1)
- true
- end
- RUBY
+ it "allows string literal with interpolation" do
+ x = "x"
- eval(<<~RUBY).should == true
- case 0
- in Integer
- true
- end
- RUBY
-
- eval(<<~RUBY).should == true
- case "0"
- in /0/
- true
- end
- RUBY
+ eval(<<~RUBY).should == true
+ case "x"
+ in "#{x + ""}"
+ true
+ end
+ RUBY
+ end
+ end
- eval(<<~RUBY).should == true
- case "0"
- in ->(s) { s == "0" }
- true
- end
- RUBY
- end
+ describe "variable pattern" do
+ it "matches a value and binds variable name to this value" do
+ eval(<<~RUBY).should == 0
+ case 0
+ in a
+ a
+ end
+ RUBY
+ end
- it "allows string literal with interpolation" do
- x = "x"
+ it "makes bounded variable visible outside a case statement scope" do
+ eval(<<~RUBY).should == 0
+ case 0
+ in a
+ end
- eval(<<~RUBY).should == true
- case "x"
- in "#{x + ""}"
- true
- end
- RUBY
- end
+ a
+ RUBY
end
- describe "variable pattern" do
- it "matches a value and binds variable name to this value" do
- eval(<<~RUBY).should == 0
- case 0
- in a
- a
- end
- RUBY
- end
+ it "create local variables even if a pattern doesn't match" do
+ eval(<<~RUBY).should == [0, nil, nil]
+ case 0
+ in a
+ in b
+ in c
+ end
- it "makes bounded variable visible outside a case statement scope" do
- eval(<<~RUBY).should == 0
- case 0
- in a
- end
+ [a, b, c]
+ RUBY
+ end
+ it "allow using _ name to drop values" do
+ eval(<<~RUBY).should == 0
+ case [0, 1]
+ in [a, _]
a
- RUBY
- end
-
- it "create local variables even if a pattern doesn't match" do
- eval(<<~RUBY).should == [0, nil, nil]
- case 0
- in a
- in b
- in c
- end
-
- [a, b, c]
- RUBY
- end
+ end
+ RUBY
+ end
- it "allow using _ name to drop values" do
- eval(<<~RUBY).should == 0
- case [0, 1]
- in [a, _]
- a
- end
- RUBY
- end
+ it "supports using _ in a pattern several times" do
+ eval(<<~RUBY).should == true
+ case [0, 1, 2]
+ in [0, _, _]
+ true
+ end
+ RUBY
+ end
- it "supports using _ in a pattern several times" do
- eval(<<~RUBY).should == true
- case [0, 1, 2]
- in [0, _, _]
- true
- end
- RUBY
- end
+ it "supports using any name with _ at the beginning in a pattern several times" do
+ eval(<<~RUBY).should == true
+ case [0, 1, 2]
+ in [0, _x, _x]
+ true
+ end
+ RUBY
- it "supports using any name with _ at the beginning in a pattern several times" do
- eval(<<~RUBY).should == true
- case [0, 1, 2]
- in [0, _x, _x]
- true
- end
- RUBY
+ eval(<<~RUBY).should == true
+ case {a: 0, b: 1, c: 2}
+ in {a: 0, b: _x, c: _x}
+ true
+ end
+ RUBY
+ end
- eval(<<~RUBY).should == true
- case {a: 0, b: 1, c: 2}
- in {a: 0, b: _x, c: _x}
- true
+ it "does not support using variable name (except _) several times" do
+ -> {
+ eval <<~RUBY
+ case [0]
+ in [a, a]
end
RUBY
- end
+ }.should raise_error(SyntaxError, /duplicated variable name/)
+ end
- it "does not support using variable name (except _) several times" do
- -> {
- eval <<~RUBY
- case [0]
- in [a, a]
- end
- RUBY
- }.should raise_error(SyntaxError, /duplicated variable name/)
- end
+ it "supports existing variables in a pattern specified with ^ operator" do
+ a = 0
- it "supports existing variables in a pattern specified with ^ operator" do
- a = 0
+ eval(<<~RUBY).should == true
+ case 0
+ in ^a
+ true
+ end
+ RUBY
+ end
- eval(<<~RUBY).should == true
- case 0
- in ^a
- true
- end
- RUBY
- end
+ it "allows applying ^ operator to bound variables" do
+ eval(<<~RUBY).should == 1
+ case [1, 1]
+ in [n, ^n]
+ n
+ end
+ RUBY
- it "allows applying ^ operator to bound variables" do
- eval(<<~RUBY).should == 1
- case [1, 1]
- in [n, ^n]
- n
- end
- RUBY
+ eval(<<~RUBY).should == false
+ case [1, 2]
+ in [n, ^n]
+ true
+ else
+ false
+ end
+ RUBY
+ end
- eval(<<~RUBY).should == false
+ it "requires bound variable to be specified in a pattern before ^ operator when it relies on a bound variable" do
+ -> {
+ eval <<~RUBY
case [1, 2]
- in [n, ^n]
+ in [^n, n]
true
else
false
end
RUBY
- end
+ }.should raise_error(SyntaxError, /n: no such local variable/)
+ end
+ end
- it "requires bound variable to be specified in a pattern before ^ operator when it relies on a bound variable" do
- -> {
- eval <<~RUBY
- case [1, 2]
- in [^n, n]
- true
- else
- false
- end
- RUBY
- }.should raise_error(SyntaxError, /n: no such local variable/)
- end
+ describe "alternative pattern" do
+ it "matches if any of patterns matches" do
+ eval(<<~RUBY).should == true
+ case 0
+ in 0 | 1 | 2
+ true
+ end
+ RUBY
end
- describe "alternative pattern" do
- it "matches if any of patterns matches" do
- eval(<<~RUBY).should == true
- case 0
- in 0 | 1 | 2
- true
+ it "does not support variable binding" do
+ -> {
+ eval <<~RUBY
+ case [0, 1]
+ in [0, 0] | [0, a]
end
RUBY
- end
+ }.should raise_error(SyntaxError, /illegal variable in alternative pattern/)
+ end
- it "does not support variable binding" do
- -> {
- eval <<~RUBY
- case [0, 1]
- in [0, 0] | [0, a]
- end
- RUBY
- }.should raise_error(SyntaxError, /illegal variable in alternative pattern/)
- end
+ it "support underscore prefixed variables in alternation" do
+ eval(<<~RUBY).should == true
+ case [0, 1]
+ in [1, _]
+ false
+ in [0, 0] | [0, _a]
+ true
+ end
+ RUBY
+ end
- it "support underscore prefixed variables in alternation" do
- eval(<<~RUBY).should == true
- case [0, 1]
- in [1, _]
+ it "can be used as a nested pattern" do
+ eval(<<~RUBY).should == true
+ case [[1], ["2"]]
+ in [[0] | nil, _]
false
- in [0, 0] | [0, _a]
+ in [[1], [1]]
+ false
+ in [[1], [2 | "2"]]
true
- end
- RUBY
- end
+ end
+ RUBY
- it "can be used as a nested pattern" do
- eval(<<~RUBY).should == true
- case [[1], ["2"]]
- in [[0] | nil, _]
- false
- in [[1], [1]]
- false
- in [[1], [2 | "2"]]
- true
- end
- RUBY
+ eval(<<~RUBY).should == true
+ case [1, 2]
+ in [0, _] | {a: 0}
+ false
+ in {a: 1, b: 2} | [1, 2]
+ true
+ end
+ RUBY
+ end
+ end
- eval(<<~RUBY).should == true
- case [1, 2]
- in [0, _] | {a: 0}
- false
- in {a: 1, b: 2} | [1, 2]
- true
- end
- RUBY
- end
+ describe "AS pattern" do
+ it "binds a variable to a value if pattern matches" do
+ eval(<<~RUBY).should == 0
+ case 0
+ in Integer => n
+ n
+ end
+ RUBY
end
- describe "AS pattern" do
- it "binds a variable to a value if pattern matches" do
- eval(<<~RUBY).should == 0
- case 0
- in Integer => n
- n
- end
- RUBY
- end
+ it "can be used as a nested pattern" do
+ eval(<<~RUBY).should == [2, 3]
+ case [1, [2, 3]]
+ in [1, Array => ary]
+ ary
+ end
+ RUBY
+ end
+ end
- it "can be used as a nested pattern" do
- eval(<<~RUBY).should == [2, 3]
- case [1, [2, 3]]
- in [1, Array => ary]
- ary
- end
- RUBY
- end
+ describe "Array pattern" do
+ it "supports form Constant(pat, pat, ...)" do
+ eval(<<~RUBY).should == true
+ case [0, 1, 2]
+ in Array(0, 1, 2)
+ true
+ end
+ RUBY
end
- describe "Array pattern" do
- it "supports form Constant(pat, pat, ...)" do
- eval(<<~RUBY).should == true
- case [0, 1, 2]
- in Array(0, 1, 2)
- true
- end
- RUBY
- end
+ it "supports form Constant[pat, pat, ...]" do
+ eval(<<~RUBY).should == true
+ case [0, 1, 2]
+ in Array[0, 1, 2]
+ true
+ end
+ RUBY
+ end
- it "supports form Constant[pat, pat, ...]" do
- eval(<<~RUBY).should == true
- case [0, 1, 2]
- in Array[0, 1, 2]
- true
- end
- RUBY
- end
+ it "supports form [pat, pat, ...]" do
+ eval(<<~RUBY).should == true
+ case [0, 1, 2]
+ in [0, 1, 2]
+ true
+ end
+ RUBY
+ end
- it "supports form [pat, pat, ...]" do
- eval(<<~RUBY).should == true
- case [0, 1, 2]
- in [0, 1, 2]
- true
- end
- RUBY
- end
+ it "supports form pat, pat, ..." do
+ eval(<<~RUBY).should == true
+ case [0, 1, 2]
+ in 0, 1, 2
+ true
+ end
+ RUBY
- it "supports form pat, pat, ..." do
- eval(<<~RUBY).should == true
- case [0, 1, 2]
- in 0, 1, 2
- true
- end
- RUBY
+ eval(<<~RUBY).should == 1
+ case [0, 1, 2]
+ in 0, a, 2
+ a
+ end
+ RUBY
- eval(<<~RUBY).should == 1
- case [0, 1, 2]
- in 0, a, 2
- a
- end
- RUBY
+ eval(<<~RUBY).should == [1, 2]
+ case [0, 1, 2]
+ in 0, *rest
+ rest
+ end
+ RUBY
+ end
- eval(<<~RUBY).should == [1, 2]
- case [0, 1, 2]
- in 0, *rest
- rest
- end
- RUBY
- end
+ it "matches an object with #deconstruct method which returns an array and each element in array matches element in pattern" do
+ obj = Object.new
+ def obj.deconstruct; [0, 1] end
+
+ eval(<<~RUBY).should == true
+ case obj
+ in [Integer, Integer]
+ true
+ end
+ RUBY
+ end
- it "matches an object with #deconstruct method which returns an array and each element in array matches element in pattern" do
- obj = Object.new
- def obj.deconstruct; [0, 1] end
+ it "calls #deconstruct once for multiple patterns, caching the result" do
+ obj = Object.new
- eval(<<~RUBY).should == true
- case obj
- in [Integer, Integer]
- true
- end
- RUBY
+ def obj.deconstruct
+ ScratchPad << :deconstruct
+ [0, 1]
end
- ruby_version_is "3.0" do
- it "calls #deconstruct once for multiple patterns, caching the result" do
- obj = Object.new
+ eval(<<~RUBY).should == true
+ case obj
+ in [1, 2]
+ false
+ in [0, 1]
+ true
+ end
+ RUBY
- def obj.deconstruct
- ScratchPad << :deconstruct
- [0, 1]
- end
+ ScratchPad.recorded.should == [:deconstruct]
+ end
- eval(<<~RUBY).should == true
- case obj
- in [1, 2]
- false
- in [0, 1]
- true
- end
- RUBY
+ it "calls #deconstruct even on objects that are already an array" do
+ obj = [1, 2]
+ def obj.deconstruct
+ ScratchPad << :deconstruct
+ [3, 4]
+ end
- ScratchPad.recorded.should == [:deconstruct]
+ eval(<<~RUBY).should == true
+ case obj
+ in [3, 4]
+ true
+ else
+ false
end
- end
+ RUBY
- it "calls #deconstruct even on objects that are already an array" do
- obj = [1, 2]
- def obj.deconstruct
- ScratchPad << :deconstruct
- [3, 4]
+ ScratchPad.recorded.should == [:deconstruct]
+ end
+
+ it "does not match object if Constant === object returns false" do
+ eval(<<~RUBY).should == false
+ case [0, 1, 2]
+ in String[0, 1, 2]
+ true
+ else
+ false
end
+ RUBY
+ end
- eval(<<~RUBY).should == true
- case obj
- in [3, 4]
- true
- else
- false
- end
- RUBY
+ it "checks Constant === object before calling #deconstruct" do
+ c1 = Class.new
+ obj = c1.new
+ obj.should_not_receive(:deconstruct)
+ eval(<<~RUBY).should == false
+ case obj
+ in String[1]
+ true
+ else
+ false
+ end
+ RUBY
+ end
- ScratchPad.recorded.should == [:deconstruct]
- end
+ it "does not match object without #deconstruct method" do
+ obj = Object.new
+ obj.should_receive(:respond_to?).with(:deconstruct)
- it "does not match object if Constant === object returns false" do
- eval(<<~RUBY).should == false
- case [0, 1, 2]
- in String[0, 1, 2]
- true
- else
- false
- end
- RUBY
- end
+ eval(<<~RUBY).should == false
+ case obj
+ in Object[]
+ true
+ else
+ false
+ end
+ RUBY
+ end
- it "does not match object without #deconstruct method" do
- obj = Object.new
- obj.should_receive(:respond_to?).with(:deconstruct)
+ it "raises TypeError if #deconstruct method does not return array" do
+ obj = Object.new
+ def obj.deconstruct; "" end
- eval(<<~RUBY).should == false
+ -> {
+ eval <<~RUBY
case obj
in Object[]
- true
else
- false
end
RUBY
+ }.should raise_error(TypeError, /deconstruct must return Array/)
+ end
+
+ it "accepts a subclass of Array from #deconstruct" do
+ obj = Object.new
+ def obj.deconstruct
+ Class.new(Array).new([0, 1])
end
- it "raises TypeError if #deconstruct method does not return array" do
- obj = Object.new
- def obj.deconstruct; "" end
+ eval(<<~RUBY).should == true
+ case obj
+ in [1, 2]
+ false
+ in [0, 1]
+ true
+ end
+ RUBY
+ end
- -> {
- eval <<~RUBY
- case obj
- in Object[]
- else
- end
- RUBY
- }.should raise_error(TypeError, /deconstruct must return Array/)
- end
+ it "does not match object if elements of array returned by #deconstruct method does not match elements in pattern" do
+ obj = Object.new
+ def obj.deconstruct; [1] end
- it "accepts a subclass of Array from #deconstruct" do
- obj = Object.new
- def obj.deconstruct
- subarray = Class.new(Array).new(2)
- def subarray.[](n)
- n
- end
- subarray
+ eval(<<~RUBY).should == false
+ case obj
+ in Object[0]
+ true
+ else
+ false
end
+ RUBY
+ end
- eval(<<~RUBY).should == true
- case obj
- in [1, 2]
- false
- in [0, 1]
- true
- end
- RUBY
- end
+ it "binds variables" do
+ eval(<<~RUBY).should == [0, 1, 2]
+ case [0, 1, 2]
+ in [a, b, c]
+ [a, b, c]
+ end
+ RUBY
+ end
- it "does not match object if elements of array returned by #deconstruct method does not match elements in pattern" do
- obj = Object.new
- def obj.deconstruct; [1] end
+ it "supports splat operator *rest" do
+ eval(<<~RUBY).should == [1, 2]
+ case [0, 1, 2]
+ in [0, *rest]
+ rest
+ end
+ RUBY
+ end
- eval(<<~RUBY).should == false
- case obj
- in Object[0]
- true
- else
- false
- end
- RUBY
- end
+ it "does not match partially by default" do
+ eval(<<~RUBY).should == false
+ case [0, 1, 2, 3]
+ in [1, 2]
+ true
+ else
+ false
+ end
+ RUBY
+ end
- it "binds variables" do
- eval(<<~RUBY).should == [0, 1, 2]
- case [0, 1, 2]
- in [a, b, c]
- [a, b, c]
- end
- RUBY
- end
+ it "does match partially from the array beginning if list + , syntax used" do
+ eval(<<~RUBY).should == true
+ case [0, 1, 2, 3]
+ in [0, 1,]
+ true
+ end
+ RUBY
- it "supports splat operator *rest" do
- eval(<<~RUBY).should == [1, 2]
- case [0, 1, 2]
- in [0, *rest]
- rest
- end
- RUBY
- end
+ eval(<<~RUBY).should == true
+ case [0, 1, 2, 3]
+ in 0, 1,;
+ true
+ end
+ RUBY
+ end
- it "does not match partially by default" do
- eval(<<~RUBY).should == false
- case [0, 1, 2, 3]
- in [1, 2]
- true
- else
- false
- end
- RUBY
- end
+ it "matches [] with []" do
+ eval(<<~RUBY).should == true
+ case []
+ in []
+ true
+ end
+ RUBY
+ end
- it "does match partially from the array beginning if list + , syntax used" do
- eval(<<~RUBY).should == true
- case [0, 1, 2, 3]
- in [0, 1,]
- true
- end
- RUBY
+ it "matches anything with *" do
+ eval(<<~RUBY).should == true
+ case [0, 1]
+ in *;
+ true
+ end
+ RUBY
+ end
- eval(<<~RUBY).should == true
- case [0, 1, 2, 3]
- in 0, 1,;
+ it "can be used as a nested pattern" do
+ eval(<<~RUBY).should == true
+ case [[1], ["2"]]
+ in [[0] | nil, _]
+ false
+ in [[1], [1]]
+ false
+ in [[1], [2 | "2"]]
true
- end
- RUBY
- end
+ end
+ RUBY
- it "matches [] with []" do
- eval(<<~RUBY).should == true
- case []
- in []
+ eval(<<~RUBY).should == true
+ case [1, 2]
+ in [0, _] | {a: 0}
+ false
+ in {a: 1, b: 2} | [1, 2]
true
- end
- RUBY
- end
+ end
+ RUBY
+ end
+ end
- it "matches anything with *" do
- eval(<<~RUBY).should == true
- case [0, 1]
- in *;
- true
- end
- RUBY
- end
+ describe "Hash pattern" do
+ it "supports form Constant(id: pat, id: pat, ...)" do
+ eval(<<~RUBY).should == true
+ case {a: 0, b: 1}
+ in Hash(a: 0, b: 1)
+ true
+ end
+ RUBY
+ end
- it "can be used as a nested pattern" do
- eval(<<~RUBY).should == true
- case [[1], ["2"]]
- in [[0] | nil, _]
- false
- in [[1], [1]]
- false
- in [[1], [2 | "2"]]
- true
- end
- RUBY
+ it "supports form Constant[id: pat, id: pat, ...]" do
+ eval(<<~RUBY).should == true
+ case {a: 0, b: 1}
+ in Hash[a: 0, b: 1]
+ true
+ end
+ RUBY
+ end
- eval(<<~RUBY).should == true
- case [1, 2]
- in [0, _] | {a: 0}
- false
- in {a: 1, b: 2} | [1, 2]
- true
- end
- RUBY
- end
+ it "supports form {id: pat, id: pat, ...}" do
+ eval(<<~RUBY).should == true
+ case {a: 0, b: 1}
+ in {a: 0, b: 1}
+ true
+ end
+ RUBY
end
- describe "Hash pattern" do
- it "supports form Constant(id: pat, id: pat, ...)" do
- eval(<<~RUBY).should == true
- case {a: 0, b: 1}
- in Hash(a: 0, b: 1)
- true
- end
- RUBY
- end
+ it "supports form id: pat, id: pat, ..." do
+ eval(<<~RUBY).should == true
+ case {a: 0, b: 1}
+ in a: 0, b: 1
+ true
+ end
+ RUBY
- it "supports form Constant[id: pat, id: pat, ...]" do
- eval(<<~RUBY).should == true
- case {a: 0, b: 1}
- in Hash[a: 0, b: 1]
- true
- end
- RUBY
- end
+ eval(<<~RUBY).should == [0, 1]
+ case {a: 0, b: 1}
+ in a: a, b: b
+ [a, b]
+ end
+ RUBY
- it "supports form {id: pat, id: pat, ...}" do
- eval(<<~RUBY).should == true
- case {a: 0, b: 1}
- in {a: 0, b: 1}
- true
- end
- RUBY
- end
+ eval(<<~RUBY).should == { b: 1, c: 2 }
+ case {a: 0, b: 1, c: 2}
+ in a: 0, **rest
+ rest
+ end
+ RUBY
+ end
- it "supports form id: pat, id: pat, ..." do
- eval(<<~RUBY).should == true
- case {a: 0, b: 1}
- in a: 0, b: 1
- true
- end
- RUBY
+ it "supports a: which means a: a" do
+ eval(<<~RUBY).should == [0, 1]
+ case {a: 0, b: 1}
+ in Hash(a:, b:)
+ [a, b]
+ end
+ RUBY
- eval(<<~RUBY).should == [0, 1]
- case {a: 0, b: 1}
- in a: a, b: b
- [a, b]
- end
- RUBY
+ a = b = nil
+ eval(<<~RUBY).should == [0, 1]
+ case {a: 0, b: 1}
+ in Hash[a:, b:]
+ [a, b]
+ end
+ RUBY
- eval(<<~RUBY).should == { b: 1, c: 2 }
- case {a: 0, b: 1, c: 2}
- in a: 0, **rest
- rest
- end
- RUBY
- end
+ a = b = nil
+ eval(<<~RUBY).should == [0, 1]
+ case {a: 0, b: 1}
+ in {a:, b:}
+ [a, b]
+ end
+ RUBY
- it "supports a: which means a: a" do
- eval(<<~RUBY).should == [0, 1]
- case {a: 0, b: 1}
- in Hash(a:, b:)
- [a, b]
- end
- RUBY
+ a = nil
+ eval(<<~RUBY).should == [0, {b: 1, c: 2}]
+ case {a: 0, b: 1, c: 2}
+ in {a:, **rest}
+ [a, rest]
+ end
+ RUBY
- a = b = nil
- eval(<<~RUBY).should == [0, 1]
- case {a: 0, b: 1}
- in Hash[a:, b:]
- [a, b]
- end
- RUBY
+ a = b = nil
+ eval(<<~RUBY).should == [0, 1]
+ case {a: 0, b: 1}
+ in a:, b:
+ [a, b]
+ end
+ RUBY
+ end
- a = b = nil
- eval(<<~RUBY).should == [0, 1]
- case {a: 0, b: 1}
- in {a:, b:}
- [a, b]
- end
- RUBY
+ it "can mix key (a:) and key-value (a: b) declarations" do
+ eval(<<~RUBY).should == [0, 1]
+ case {a: 0, b: 1}
+ in Hash(a:, b: x)
+ [a, x]
+ end
+ RUBY
+ end
- a = nil
- eval(<<~RUBY).should == [0, {b: 1, c: 2}]
- case {a: 0, b: 1, c: 2}
- in {a:, **rest}
- [a, rest]
- end
- RUBY
+ it "supports 'string': key literal" do
+ eval(<<~RUBY).should == true
+ case {a: 0}
+ in {"a": 0}
+ true
+ end
+ RUBY
+ end
- a = b = nil
- eval(<<~RUBY).should == [0, 1]
- case {a: 0, b: 1}
- in a:, b:
- [a, b]
+ it "does not support non-symbol keys" do
+ -> {
+ eval <<~RUBY
+ case {a: 1}
+ in {"a" => 1}
end
RUBY
- end
+ }.should raise_error(SyntaxError, /unexpected|expected a label as the key in the hash pattern/)
+ end
+
+ it "does not support string interpolation in keys" do
+ x = "a"
- it "can mix key (a:) and key-value (a: b) declarations" do
- eval(<<~RUBY).should == [0, 1]
- case {a: 0, b: 1}
- in Hash(a:, b: x)
- [a, x]
+ -> {
+ eval <<~'RUBY'
+ case {a: 1}
+ in {"#{x}": 1}
end
RUBY
- end
+ }.should raise_error(SyntaxError, /symbol literal with interpolation is not allowed|expected a label as the key in the hash pattern/)
+ end
- it "supports 'string': key literal" do
- eval(<<~RUBY).should == true
- case {a: 0}
- in {"a": 0}
- true
+ it "raise SyntaxError when keys duplicate in pattern" do
+ -> {
+ eval <<~RUBY
+ case {a: 1}
+ in {a: 1, b: 2, a: 3}
end
RUBY
- end
+ }.should raise_error(SyntaxError, /duplicated key name/)
+ end
- it "does not support non-symbol keys" do
- -> {
- eval <<~RUBY
- case {a: 1}
- in {"a" => 1}
- end
- RUBY
- }.should raise_error(SyntaxError, /unexpected/)
- end
+ it "matches an object with #deconstruct_keys method which returns a Hash with equal keys and each value in Hash matches value in pattern" do
+ obj = Object.new
+ def obj.deconstruct_keys(*); {a: 1} end
- it "does not support string interpolation in keys" do
- x = "a"
+ eval(<<~RUBY).should == true
+ case obj
+ in {a: 1}
+ true
+ end
+ RUBY
+ end
- -> {
- eval <<~'RUBY'
- case {a: 1}
- in {"#{x}": 1}
- end
- RUBY
- }.should raise_error(SyntaxError, /symbol literal with interpolation is not allowed/)
- end
+ it "calls #deconstruct_keys per pattern" do
+ obj = Object.new
- it "raise SyntaxError when keys duplicate in pattern" do
- -> {
- eval <<~RUBY
- case {a: 1}
- in {a: 1, b: 2, a: 3}
- end
- RUBY
- }.should raise_error(SyntaxError, /duplicated key name/)
+ def obj.deconstruct_keys(*)
+ ScratchPad << :deconstruct_keys
+ {a: 1}
end
- it "matches an object with #deconstruct_keys method which returns a Hash with equal keys and each value in Hash matches value in pattern" do
- obj = Object.new
- def obj.deconstruct_keys(*); {a: 1} end
-
- eval(<<~RUBY).should == true
- case obj
- in {a: 1}
- true
- end
- RUBY
- end
+ eval(<<~RUBY).should == true
+ case obj
+ in {b: 1}
+ false
+ in {a: 1}
+ true
+ end
+ RUBY
- it "calls #deconstruct_keys per pattern" do
- obj = Object.new
+ ScratchPad.recorded.should == [:deconstruct_keys, :deconstruct_keys]
+ end
- def obj.deconstruct_keys(*)
- ScratchPad << :deconstruct_keys
- {a: 1}
+ it "does not match object if Constant === object returns false" do
+ eval(<<~RUBY).should == false
+ case {a: 1}
+ in String[a: 1]
+ true
+ else
+ false
end
+ RUBY
+ end
- eval(<<~RUBY).should == true
- case obj
- in {b: 1}
- false
- in {a: 1}
- true
- end
- RUBY
+ it "checks Constant === object before calling #deconstruct_keys" do
+ c1 = Class.new
+ obj = c1.new
+ obj.should_not_receive(:deconstruct_keys)
+ eval(<<~RUBY).should == false
+ case obj
+ in String(a: 1)
+ true
+ else
+ false
+ end
+ RUBY
+ end
- ScratchPad.recorded.should == [:deconstruct_keys, :deconstruct_keys]
- end
+ it "does not match object without #deconstruct_keys method" do
+ obj = Object.new
+ obj.should_receive(:respond_to?).with(:deconstruct_keys)
- it "does not match object if Constant === object returns false" do
- eval(<<~RUBY).should == false
- case {a: 1}
- in String[a: 1]
- true
- else
- false
- end
- RUBY
- end
+ eval(<<~RUBY).should == false
+ case obj
+ in Object[a: 1]
+ true
+ else
+ false
+ end
+ RUBY
+ end
- it "does not match object without #deconstruct_keys method" do
- obj = Object.new
- obj.should_receive(:respond_to?).with(:deconstruct_keys)
+ it "does not match object if #deconstruct_keys method does not return Hash" do
+ obj = Object.new
+ def obj.deconstruct_keys(*); "" end
- eval(<<~RUBY).should == false
+ -> {
+ eval <<~RUBY
case obj
in Object[a: 1]
- true
- else
- false
end
RUBY
- end
+ }.should raise_error(TypeError, /deconstruct_keys must return Hash/)
+ end
- it "does not match object if #deconstruct_keys method does not return Hash" do
- obj = Object.new
- def obj.deconstruct_keys(*); "" end
+ it "does not match object if #deconstruct_keys method returns Hash with non-symbol keys" do
+ obj = Object.new
+ def obj.deconstruct_keys(*); {"a" => 1} end
- -> {
- eval <<~RUBY
- case obj
- in Object[a: 1]
- end
- RUBY
- }.should raise_error(TypeError, /deconstruct_keys must return Hash/)
- end
+ eval(<<~RUBY).should == false
+ case obj
+ in Object[a: 1]
+ true
+ else
+ false
+ end
+ RUBY
+ end
- it "does not match object if #deconstruct_keys method returns Hash with non-symbol keys" do
- obj = Object.new
- def obj.deconstruct_keys(*); {"a" => 1} end
+ it "does not match object if elements of Hash returned by #deconstruct_keys method does not match values in pattern" do
+ obj = Object.new
+ def obj.deconstruct_keys(*); {a: 1} end
- eval(<<~RUBY).should == false
- case obj
- in Object[a: 1]
- true
- else
- false
- end
- RUBY
- end
+ eval(<<~RUBY).should == false
+ case obj
+ in Object[a: 2]
+ true
+ else
+ false
+ end
+ RUBY
+ end
- it "does not match object if elements of Hash returned by #deconstruct_keys method does not match values in pattern" do
- obj = Object.new
- def obj.deconstruct_keys(*); {a: 1} end
+ it "passes keys specified in pattern as arguments to #deconstruct_keys method" do
+ obj = Object.new
- eval(<<~RUBY).should == false
- case obj
- in Object[a: 2]
- true
- else
- false
- end
- RUBY
+ def obj.deconstruct_keys(*args)
+ ScratchPad << args
+ {a: 1, b: 2, c: 3}
end
- it "passes keys specified in pattern as arguments to #deconstruct_keys method" do
- obj = Object.new
+ eval <<~RUBY
+ case obj
+ in Object[a: 1, b: 2, c: 3]
+ end
+ RUBY
+
+ ScratchPad.recorded.sort.should == [[[:a, :b, :c]]]
+ end
- def obj.deconstruct_keys(*args)
- ScratchPad << args
- {a: 1, b: 2, c: 3}
+ it "passes keys specified in pattern to #deconstruct_keys method if pattern contains double splat operator **" do
+ obj = Object.new
+
+ def obj.deconstruct_keys(*args)
+ ScratchPad << args
+ {a: 1, b: 2, c: 3}
+ end
+
+ eval <<~RUBY
+ case obj
+ in Object[a: 1, b: 2, **]
end
+ RUBY
- eval <<~RUBY
- case obj
- in Object[a: 1, b: 2, c: 3]
- end
- RUBY
+ ScratchPad.recorded.sort.should == [[[:a, :b]]]
+ end
+
+ it "passes nil to #deconstruct_keys method if pattern contains double splat operator **rest" do
+ obj = Object.new
- ScratchPad.recorded.sort.should == [[[:a, :b, :c]]]
+ def obj.deconstruct_keys(*args)
+ ScratchPad << args
+ {a: 1, b: 2}
end
- it "passes keys specified in pattern to #deconstruct_keys method if pattern contains double splat operator **" do
- obj = Object.new
+ eval <<~RUBY
+ case obj
+ in Object[a: 1, **rest]
+ end
+ RUBY
- def obj.deconstruct_keys(*args)
- ScratchPad << args
- {a: 1, b: 2, c: 3}
+ ScratchPad.recorded.should == [[nil]]
+ end
+
+ it "binds variables" do
+ eval(<<~RUBY).should == [0, 1, 2]
+ case {a: 0, b: 1, c: 2}
+ in {a: x, b: y, c: z}
+ [x, y, z]
end
+ RUBY
+ end
- eval <<~RUBY
- case obj
- in Object[a: 1, b: 2, **]
- end
- RUBY
+ it "supports double splat operator **rest" do
+ eval(<<~RUBY).should == {b: 1, c: 2}
+ case {a: 0, b: 1, c: 2}
+ in {a: 0, **rest}
+ rest
+ end
+ RUBY
+ end
- ScratchPad.recorded.sort.should == [[[:a, :b]]]
- end
+ it "treats **nil like there should not be any other keys in a matched Hash" do
+ eval(<<~RUBY).should == true
+ case {a: 1, b: 2}
+ in {a: 1, b: 2, **nil}
+ true
+ end
+ RUBY
- it "passes nil to #deconstruct_keys method if pattern contains double splat operator **rest" do
- obj = Object.new
+ eval(<<~RUBY).should == false
+ case {a: 1, b: 2}
+ in {a: 1, **nil}
+ true
+ else
+ false
+ end
+ RUBY
+ end
- def obj.deconstruct_keys(*args)
- ScratchPad << args
- {a: 1, b: 2}
+ it "can match partially" do
+ eval(<<~RUBY).should == true
+ case {a: 1, b: 2}
+ in {a: 1}
+ true
end
+ RUBY
+ end
- eval <<~RUBY
- case obj
- in Object[a: 1, **rest]
- end
- RUBY
+ it "matches {} with {}" do
+ eval(<<~RUBY).should == true
+ case {}
+ in {}
+ true
+ end
+ RUBY
+ end
- ScratchPad.recorded.should == [[nil]]
- end
+ it "in {} only matches empty hashes" do
+ eval(<<~RUBY).should == false
+ case {a: 1}
+ in {}
+ true
+ else
+ false
+ end
+ RUBY
+ end
- it "binds variables" do
- eval(<<~RUBY).should == [0, 1, 2]
- case {a: 0, b: 1, c: 2}
- in {a: x, b: y, c: z}
- [x, y, z]
- end
- RUBY
- end
+ it "in {**nil} only matches empty hashes" do
+ eval(<<~RUBY).should == true
+ case {}
+ in {**nil}
+ true
+ else
+ false
+ end
+ RUBY
- it "supports double splat operator **rest" do
- eval(<<~RUBY).should == {b: 1, c: 2}
- case {a: 0, b: 1, c: 2}
- in {a: 0, **rest}
- rest
- end
- RUBY
- end
+ eval(<<~RUBY).should == false
+ case {a: 1}
+ in {**nil}
+ true
+ else
+ false
+ end
+ RUBY
+ end
- it "treats **nil like there should not be any other keys in a matched Hash" do
- eval(<<~RUBY).should == true
- case {a: 1, b: 2}
- in {a: 1, b: 2, **nil}
- true
- end
- RUBY
+ it "matches anything with **" do
+ eval(<<~RUBY).should == true
+ case {a: 1}
+ in **;
+ true
+ end
+ RUBY
+ end
- eval(<<~RUBY).should == false
- case {a: 1, b: 2}
- in {a: 1, **nil}
- true
- else
+ it "can be used as a nested pattern" do
+ eval(<<~RUBY).should == true
+ case {a: {a: 1, b: 1}, b: {a: 1, b: 2}}
+ in {a: {a: 0}}
false
- end
- RUBY
- end
+ in {a: {a: 1}, b: {b: 1}}
+ false
+ in {a: {a: 1}, b: {b: 2}}
+ true
+ end
+ RUBY
- it "can match partially" do
- eval(<<~RUBY).should == true
- case {a: 1, b: 2}
- in {a: 1}
+ eval(<<~RUBY).should == true
+ case [{a: 1, b: [1]}, {a: 1, c: ["2"]}]
+ in [{a:, c:},]
+ false
+ in [{a: 1, b:}, {a: 1, c: [Integer]}]
+ false
+ in [_, {a: 1, c: [String]}]
true
+ end
+ RUBY
+ end
+ end
+
+ describe "refinements" do
+ it "are used for #deconstruct" do
+ refinery = Module.new do
+ refine Array do
+ def deconstruct
+ [0]
end
- RUBY
+ end
end
- it "matches {} with {}" do
- eval(<<~RUBY).should == true
- case {}
- in {}
+ result = nil
+ Module.new do
+ using refinery
+
+ result = eval(<<~RUBY)
+ case []
+ in [0]
true
end
RUBY
end
- it "matches anything with **" do
- eval(<<~RUBY).should == true
- case {a: 1}
- in **;
- true
+ result.should == true
+ end
+
+ it "are used for #deconstruct_keys" do
+ refinery = Module.new do
+ refine Hash do
+ def deconstruct_keys(_)
+ {a: 0}
end
- RUBY
+ end
end
- it "can be used as a nested pattern" do
- eval(<<~RUBY).should == true
- case {a: {a: 1, b: 1}, b: {a: 1, b: 2}}
- in {a: {a: 0}}
- false
- in {a: {a: 1}, b: {b: 1}}
- false
- in {a: {a: 1}, b: {b: 2}}
- true
- end
- RUBY
+ result = nil
+ Module.new do
+ using refinery
- eval(<<~RUBY).should == true
- case [{a: 1, b: [1]}, {a: 1, c: ["2"]}]
- in [{a:, c:},]
- false
- in [{a: 1, b:}, {a: 1, c: [Integer]}]
- false
- in [_, {a: 1, c: [String]}]
- true
+ result = eval(<<~RUBY)
+ case {}
+ in a: 0
+ true
end
RUBY
end
+
+ result.should == true
end
- describe "refinements" do
- it "are used for #deconstruct" do
- refinery = Module.new do
- refine Array do
- def deconstruct
- [0]
- end
+ it "are used for #=== in constant pattern" do
+ refinery = Module.new do
+ refine Array.singleton_class do
+ def ===(obj)
+ obj.is_a?(Hash)
end
end
-
- result = nil
- Module.new do
- using refinery
-
- result = eval(<<~RUBY)
- case []
- in [0]
- true
- end
- RUBY
- end
-
- result.should == true
end
- it "are used for #deconstruct_keys" do
- refinery = Module.new do
- refine Hash do
- def deconstruct_keys(_)
- {a: 0}
- end
- end
- end
-
- result = nil
- Module.new do
- using refinery
-
- result = eval(<<~RUBY)
- case {}
- in a: 0
- true
- end
- RUBY
- end
+ result = nil
+ Module.new do
+ using refinery
- result.should == true
- end
-
- it "are used for #=== in constant pattern" do
- refinery = Module.new do
- refine Array.singleton_class do
- def ===(obj)
- obj.is_a?(Hash)
- end
+ result = eval(<<~RUBY)
+ case {}
+ in Array
+ true
end
- end
-
- result = nil
- Module.new do
- using refinery
-
- result = eval(<<~RUBY)
- case {}
- in Array
- true
- end
- RUBY
- end
-
- result.should == true
+ RUBY
end
+
+ result.should == true
end
+ end
+ describe "Ruby 3.1 improvements" do
ruby_version_is "3.1" do
it "can omit parentheses in one line pattern matching" do
eval(<<~RUBY).should == [1, 2]
@@ -1343,19 +1454,56 @@ ruby_version_is "2.7" do
RUBY
eval(<<~RUBY).should == true
- case {name: '2.6', released_at: Time.new(2018, 12, 25)}
- in {released_at: ^(Time.new(2010)..Time.new(2020))}
+ case 0
+ in ^(0+0)
true
end
RUBY
+ end
+ it "supports pinning expressions in array pattern" do
eval(<<~RUBY).should == true
- case 0
- in ^(0+0)
+ case [3]
+ in [^(1+2)]
+ true
+ end
+ RUBY
+ end
+
+ it "supports pinning expressions in hash pattern" do
+ eval(<<~RUBY).should == true
+ case {name: '2.6', released_at: Time.new(2018, 12, 25)}
+ in {released_at: ^(Time.new(2010)..Time.new(2020))}
true
end
RUBY
end
end
end
+
+ describe "value in pattern" do
+ it "returns true if the pattern matches" do
+ eval("1 in 1").should == true
+
+ eval("1 in Integer").should == true
+
+ e = nil
+ eval("[1, 2] in [1, e]").should == true
+ e.should == 2
+
+ k = nil
+ eval("{k: 1} in {k:}").should == true
+ k.should == 1
+ end
+
+ it "returns false if the pattern does not match" do
+ eval("1 in 2").should == false
+
+ eval("1 in Float").should == false
+
+ eval("[1, 2] in [2, e]").should == false
+
+ eval("{k: 1} in {k: 2}").should == false
+ end
+ end
end
diff --git a/spec/ruby/language/precedence_spec.rb b/spec/ruby/language/precedence_spec.rb
index 5a3c2861ce..c5adcca2c0 100644
--- a/spec/ruby/language/precedence_spec.rb
+++ b/spec/ruby/language/precedence_spec.rb
@@ -14,46 +14,44 @@ require_relative 'fixtures/precedence'
# the level below (as well as showing associativity within
# the precedence level).
-=begin
-Excerpted from 'Programming Ruby: The Pragmatic Programmer's Guide'
-Second Edition by Dave Thomas, Chad Fowler, and Andy Hunt, page 324
-
-Table 22.4. Ruby operators (high to low precedence)
-Method Operator Description
------------------------------------------------------------------------
- :: .
- x* [ ] [ ]= Element reference, element set
- x ** Exponentiation
- x ! ~ + - Not, complement, unary plus and minus
- (method names for the last two are +@ and -@)
- x * / % Multiply, divide, and modulo
- x + - Plus and minus
- x >> << Right and left shift
- x & “And” (bitwise for integers)
- x ^ | Exclusive “or” and regular “or” (bitwise for integers)
- x <= < > >= Comparison operators
- x <=> == === != =~ !~ Equality and pattern match operators (!=
- and !~ may not be defined as methods)
- && Logical “and”
- || Logical “or”
- .. ... Range (inclusive and exclusive)
- ? : Ternary if-then-else
- = %= /= -= += |= &= Assignment
- >>= <<= *= &&= ||= **=
- defined? Check if symbol defined
- not Logical negation
- or and Logical composition
- if unless while until Expression modifiers
- begin/end Block expression
------------------------------------------------------------------------
-
-* Operators marked with 'x' in the Method column are implemented as methods
-and can be overridden (except != and !~ as noted). (But see the specs
-below for implementations that define != and !~ as methods.)
-
-** These are not included in the excerpted table but are shown here for
-completeness.
-=end
+# Excerpted from 'Programming Ruby: The Pragmatic Programmer's Guide'
+# Second Edition by Dave Thomas, Chad Fowler, and Andy Hunt, page 324
+#
+# Table 22.4. Ruby operators (high to low precedence)
+# Method Operator Description
+# -----------------------------------------------------------------------
+# :: .
+# x* [ ] [ ]= Element reference, element set
+# x ** Exponentiation
+# x ! ~ + - Not, complement, unary plus and minus
+# (method names for the last two are +@ and -@)
+# x * / % Multiply, divide, and modulo
+# x + - Plus and minus
+# x >> << Right and left shift
+# x & “And” (bitwise for integers)
+# x ^ | Exclusive “or” and regular “or” (bitwise for integers)
+# x <= < > >= Comparison operators
+# x <=> == === != =~ !~ Equality and pattern match operators (!=
+# and !~ may not be defined as methods)
+# && Logical “and”
+# || Logical “or”
+# .. ... Range (inclusive and exclusive)
+# ? : Ternary if-then-else
+# = %= /= -= += |= &= Assignment
+# >>= <<= *= &&= ||= **=
+# defined? Check if symbol defined
+# not Logical negation
+# or and Logical composition
+# if unless while until Expression modifiers
+# begin/end Block expression
+# -----------------------------------------------------------------------
+#
+# * Operators marked with 'x' in the Method column are implemented as methods
+# and can be overridden (except != and !~ as noted). (But see the specs
+# below for implementations that define != and !~ as methods.)
+#
+# ** These are not included in the excerpted table but are shown here for
+# completeness.
# -----------------------------------------------------------------------
# It seems that this table is not correct anymore
diff --git a/spec/ruby/language/predefined_spec.rb b/spec/ruby/language/predefined_spec.rb
index d311750200..ac28f1e8a0 100644
--- a/spec/ruby/language/predefined_spec.rb
+++ b/spec/ruby/language/predefined_spec.rb
@@ -7,37 +7,33 @@ require 'stringio'
# Entries marked [r/o] are read-only and an error will be raised of the program attempts to
# modify them. Entries marked [thread] are thread local.
-=begin
-Exception Information
----------------------------------------------------------------------------------------------------
-
-$! Exception The exception object passed to raise. [thread]
-$@ Array The stack backtrace generated by the last exception. [thread]
-=end
-
-=begin
-Pattern Matching Variables
----------------------------------------------------------------------------------------------------
-
-These variables are set to nil after an unsuccessful pattern match.
-
-$& String The string matched (following a successful pattern match). This variable is
- local to the current scope. [r/o, thread]
-$+ String The contents of the highest-numbered group matched following a successful
- pattern match. Thus, in "cat" =~/(c|a)(t|z)/, $+ will be set to “t”. This
- variable is local to the current scope. [r/o, thread]
-$` String The string preceding the match in a successful pattern match. This variable
- is local to the current scope. [r/o, thread]
-$' String The string following the match in a successful pattern match. This variable
- is local to the current scope. [r/o, thread]
-$1 to $<N> String The contents of successive groups matched in a successful pattern match. In
- "cat" =~/(c|a)(t|z)/, $1 will be set to “a” and $2 to “t”. This variable
- is local to the current scope. [r/o, thread]
-$~ MatchData An object that encapsulates the results of a successful pattern match. The
- variables $&, $`, $', and $1 to $<N> are all derived from $~. Assigning to $~
- changes the values of these derived variables. This variable is local to the
- current scope. [thread]
-=end
+# Exception Information
+# ---------------------------------------------------------------------------------------------------
+#
+# $! Exception The exception object passed to raise. [thread]
+# $@ Array The stack backtrace generated by the last exception. [thread]
+
+# Pattern Matching Variables
+# ---------------------------------------------------------------------------------------------------
+#
+# These variables are set to nil after an unsuccessful pattern match.
+#
+# $& String The string matched (following a successful pattern match). This variable is
+# local to the current scope. [r/o, thread]
+# $+ String The contents of the highest-numbered group matched following a successful
+# pattern match. Thus, in "cat" =~/(c|a)(t|z)/, $+ will be set to “t”. This
+# variable is local to the current scope. [r/o, thread]
+# $` String The string preceding the match in a successful pattern match. This variable
+# is local to the current scope. [r/o, thread]
+# $' String The string following the match in a successful pattern match. This variable
+# is local to the current scope. [r/o, thread]
+# $1 to $<N> String The contents of successive groups matched in a successful pattern match. In
+# "cat" =~/(c|a)(t|z)/, $1 will be set to “a” and $2 to “t”. This variable
+# is local to the current scope. [r/o, thread]
+# $~ MatchData An object that encapsulates the results of a successful pattern match. The
+# variables $&, $`, $', and $1 to $<N> are all derived from $~. Assigning to $~
+# changes the values of these derived variables. This variable is local to the
+# current scope. [thread]
describe "Predefined global $~" do
@@ -137,7 +133,7 @@ describe "Predefined global $&" do
end
it "sets the encoding to the encoding of the source String" do
- "abc".force_encoding(Encoding::EUC_JP) =~ /b/
+ "abc".dup.force_encoding(Encoding::EUC_JP) =~ /b/
$&.encoding.should equal(Encoding::EUC_JP)
end
end
@@ -150,12 +146,12 @@ describe "Predefined global $`" do
end
it "sets the encoding to the encoding of the source String" do
- "abc".force_encoding(Encoding::EUC_JP) =~ /b/
+ "abc".dup.force_encoding(Encoding::EUC_JP) =~ /b/
$`.encoding.should equal(Encoding::EUC_JP)
end
it "sets an empty result to the encoding of the source String" do
- "abc".force_encoding(Encoding::ISO_8859_1) =~ /a/
+ "abc".dup.force_encoding(Encoding::ISO_8859_1) =~ /a/
$`.encoding.should equal(Encoding::ISO_8859_1)
end
end
@@ -168,12 +164,12 @@ describe "Predefined global $'" do
end
it "sets the encoding to the encoding of the source String" do
- "abc".force_encoding(Encoding::EUC_JP) =~ /b/
+ "abc".dup.force_encoding(Encoding::EUC_JP) =~ /b/
$'.encoding.should equal(Encoding::EUC_JP)
end
it "sets an empty result to the encoding of the source String" do
- "abc".force_encoding(Encoding::ISO_8859_1) =~ /c/
+ "abc".dup.force_encoding(Encoding::ISO_8859_1) =~ /c/
$'.encoding.should equal(Encoding::ISO_8859_1)
end
end
@@ -191,7 +187,7 @@ describe "Predefined global $+" do
end
it "sets the encoding to the encoding of the source String" do
- "abc".force_encoding(Encoding::EUC_JP) =~ /(b)/
+ "abc".dup.force_encoding(Encoding::EUC_JP) =~ /(b)/
$+.encoding.should equal(Encoding::EUC_JP)
end
end
@@ -218,7 +214,7 @@ describe "Predefined globals $1..N" do
end
it "sets the encoding to the encoding of the source String" do
- "abc".force_encoding(Encoding::EUC_JP) =~ /(b)/
+ "abc".dup.force_encoding(Encoding::EUC_JP) =~ /(b)/
$1.encoding.should equal(Encoding::EUC_JP)
end
end
@@ -506,41 +502,39 @@ describe "Predefined global $!" do
end
end
-=begin
-Input/Output Variables
----------------------------------------------------------------------------------------------------
-
-$/ String The input record separator (newline by default). This is the value that rou-
- tines such as Kernel#gets use to determine record boundaries. If set to
- nil, gets will read the entire file.
-$-0 String Synonym for $/.
-$\ String The string appended to the output of every call to methods such as
- Kernel#print and IO#write. The default value is nil.
-$, String The separator string output between the parameters to methods such as
- Kernel#print and Array#join. Defaults to nil, which adds no text.
-$. Integer The number of the last line read from the current input file.
-$; String The default separator pattern used by String#split. May be set from the
- command line using the -F flag.
-$< Object An object that provides access to the concatenation of the contents of all
- the files given as command-line arguments or $stdin (in the case where
- there are no arguments). $< supports methods similar to a File object:
- binmode, close, closed?, each, each_byte, each_line, eof, eof?,
- file, filename, fileno, getc, gets, lineno, lineno=, path, pos, pos=,
- read, readchar, readline, readlines, rewind, seek, skip, tell, to_a,
- to_i, to_io, to_s, along with the methods in Enumerable. The method
- file returns a File object for the file currently being read. This may change
- as $< reads through the files on the command line. [r/o]
-$> IO The destination of output for Kernel#print and Kernel#printf. The
- default value is $stdout.
-$_ String The last line read by Kernel#gets or Kernel#readline. Many string-
- related functions in the Kernel module operate on $_ by default. The vari-
- able is local to the current scope. [thread]
-$-F String Synonym for $;.
-$stderr IO The current standard error output.
-$stdin IO The current standard input.
-$stdout IO The current standard output. Assignment to $stdout is deprecated: use
- $stdout.reopen instead.
-=end
+# Input/Output Variables
+# ---------------------------------------------------------------------------------------------------
+#
+# $/ String The input record separator (newline by default). This is the value that rou-
+# tines such as Kernel#gets use to determine record boundaries. If set to
+# nil, gets will read the entire file.
+# $-0 String Synonym for $/.
+# $\ String The string appended to the output of every call to methods such as
+# Kernel#print and IO#write. The default value is nil.
+# $, String The separator string output between the parameters to methods such as
+# Kernel#print and Array#join. Defaults to nil, which adds no text.
+# $. Integer The number of the last line read from the current input file.
+# $; String The default separator pattern used by String#split. May be set from the
+# command line using the -F flag.
+# $< Object An object that provides access to the concatenation of the contents of all
+# the files given as command-line arguments or $stdin (in the case where
+# there are no arguments). $< supports methods similar to a File object:
+# binmode, close, closed?, each, each_byte, each_line, eof, eof?,
+# file, filename, fileno, getc, gets, lineno, lineno=, path, pos, pos=,
+# read, readchar, readline, readlines, rewind, seek, skip, tell, to_a,
+# to_i, to_io, to_s, along with the methods in Enumerable. The method
+# file returns a File object for the file currently being read. This may change
+# as $< reads through the files on the command line. [r/o]
+# $> IO The destination of output for Kernel#print and Kernel#printf. The
+# default value is $stdout.
+# $_ String The last line read by Kernel#gets or Kernel#readline. Many string-
+# related functions in the Kernel module operate on $_ by default. The vari-
+# able is local to the current scope. [thread]
+# $-F String Synonym for $;.
+# $stderr IO The current standard error output.
+# $stdin IO The current standard input.
+# $stdout IO The current standard output. Assignment to $stdout is deprecated: use
+# $stdout.reopen instead.
describe "Predefined global $/" do
before :each do
@@ -570,7 +564,6 @@ describe "Predefined global $/" do
($/ = "xyz").should == "xyz"
end
-
it "changes $-0" do
$/ = "xyz"
$-0.should equal($/)
@@ -641,6 +634,45 @@ describe "Predefined global $-0" do
end
end
+describe "Predefined global $\\" do
+ before :each do
+ @verbose, $VERBOSE = $VERBOSE, nil
+ @dollar_backslash = $\
+ end
+
+ after :each do
+ $\ = @dollar_backslash
+ $VERBOSE = @verbose
+ end
+
+ it "can be assigned a String" do
+ str = "abc"
+ $\ = str
+ $\.should equal(str)
+ end
+
+ it "can be assigned nil" do
+ $\ = nil
+ $\.should be_nil
+ end
+
+ it "returns the value assigned" do
+ ($\ = "xyz").should == "xyz"
+ end
+
+ it "does not call #to_str to convert the object to a String" do
+ obj = mock("$\\ value")
+ obj.should_not_receive(:to_str)
+
+ -> { $\ = obj }.should raise_error(TypeError)
+ end
+
+ it "raises a TypeError if assigned not String" do
+ -> { $\ = 1 }.should raise_error(TypeError)
+ -> { $\ = true }.should raise_error(TypeError)
+ end
+end
+
describe "Predefined global $," do
after :each do
$, = nil
@@ -654,10 +686,8 @@ describe "Predefined global $," do
-> { $, = Object.new }.should raise_error(TypeError)
end
- ruby_version_is "2.7" do
- it "warns if assigned non-nil" do
- -> { $, = "_" }.should complain(/warning: `\$,' is deprecated/)
- end
+ it "warns if assigned non-nil" do
+ -> { $, = "_" }.should complain(/warning: [`']\$,' is deprecated/)
end
end
@@ -693,10 +723,8 @@ describe "Predefined global $;" do
$; = nil
end
- ruby_version_is "2.7" do
- it "warns if assigned non-nil" do
- -> { $; = "_" }.should complain(/warning: `\$;' is deprecated/)
- end
+ it "warns if assigned non-nil" do
+ -> { $; = "_" }.should complain(/warning: [`']\$;' is deprecated/)
end
end
@@ -769,54 +797,52 @@ describe "Predefined global $_" do
end
end
-=begin
-Execution Environment Variables
----------------------------------------------------------------------------------------------------
-
-$0 String The name of the top-level Ruby program being executed. Typically this will
- be the program’s filename. On some operating systems, assigning to this
- variable will change the name of the process reported (for example) by the
- ps(1) command.
-$* Array An array of strings containing the command-line options from the invoca-
- tion of the program. Options used by the Ruby interpreter will have been
- removed. [r/o]
-$" Array An array containing the filenames of modules loaded by require. [r/o]
-$$ Integer The process number of the program being executed. [r/o]
-$? Process::Status The exit status of the last child process to terminate. [r/o, thread]
-$: Array An array of strings, where each string specifies a directory to be searched for
- Ruby scripts and binary extensions used by the load and require methods.
- The initial value is the value of the arguments passed via the -I command-
- line option, followed by an installation-defined standard library location, fol-
- lowed by the current directory (“.”). This variable may be set from within a
- program to alter the default search path; typically, programs use $: << dir
- to append dir to the path. [r/o]
-$-a Object True if the -a option is specified on the command line. [r/o]
-$-d Object Synonym for $DEBUG.
-$DEBUG Object Set to true if the -d command-line option is specified.
-__FILE__ String The name of the current source file. [r/o]
-$F Array The array that receives the split input line if the -a command-line option is
- used.
-$FILENAME String The name of the current input file. Equivalent to $<.filename. [r/o]
-$-i String If in-place edit mode is enabled (perhaps using the -i command-line
- option), $-i holds the extension used when creating the backup file. If you
- set a value into $-i, enables in-place edit mode.
-$-I Array Synonym for $:. [r/o]
-$-K String Sets the multibyte coding system for strings and regular expressions. Equiv-
- alent to the -K command-line option.
-$-l Object Set to true if the -l option (which enables line-end processing) is present
- on the command line. [r/o]
-__LINE__ String The current line number in the source file. [r/o]
-$LOAD_PATH Array A synonym for $:. [r/o]
-$-p Object Set to true if the -p option (which puts an implicit while gets . . . end
- loop around your program) is present on the command line. [r/o]
-$VERBOSE Object Set to true if the -v, --version, -W, or -w option is specified on the com-
- mand line. Set to false if no option, or -W1 is given. Set to nil if -W0
- was specified. Setting this option to true causes the interpreter and some
- library routines to report additional information. Setting to nil suppresses
- all warnings (including the output of Kernel.warn).
-$-v Object Synonym for $VERBOSE.
-$-w Object Synonym for $VERBOSE.
-=end
+# Execution Environment Variables
+# ---------------------------------------------------------------------------------------------------
+#
+# $0 String The name of the top-level Ruby program being executed. Typically this will
+# be the program’s filename. On some operating systems, assigning to this
+# variable will change the name of the process reported (for example) by the
+# ps(1) command.
+# $* Array An array of strings containing the command-line options from the invoca-
+# tion of the program. Options used by the Ruby interpreter will have been
+# removed. [r/o]
+# $" Array An array containing the filenames of modules loaded by require. [r/o]
+# $$ Integer The process number of the program being executed. [r/o]
+# $? Process::Status The exit status of the last child process to terminate. [r/o, thread]
+# $: Array An array of strings, where each string specifies a directory to be searched for
+# Ruby scripts and binary extensions used by the load and require methods.
+# The initial value is the value of the arguments passed via the -I command-
+# line option, followed by an installation-defined standard library location, fol-
+# lowed by the current directory (“.”). This variable may be set from within a
+# program to alter the default search path; typically, programs use $: << dir
+# to append dir to the path. [r/o]
+# $-a Object True if the -a option is specified on the command line. [r/o]
+# $-d Object Synonym for $DEBUG.
+# $DEBUG Object Set to true if the -d command-line option is specified.
+# __FILE__ String The name of the current source file. [r/o]
+# $F Array The array that receives the split input line if the -a command-line option is
+# used.
+# $FILENAME String The name of the current input file. Equivalent to $<.filename. [r/o]
+# $-i String If in-place edit mode is enabled (perhaps using the -i command-line
+# option), $-i holds the extension used when creating the backup file. If you
+# set a value into $-i, enables in-place edit mode.
+# $-I Array Synonym for $:. [r/o]
+# $-K String Sets the multibyte coding system for strings and regular expressions. Equiv-
+# alent to the -K command-line option.
+# $-l Object Set to true if the -l option (which enables line-end processing) is present
+# on the command line. [r/o]
+# __LINE__ String The current line number in the source file. [r/o]
+# $LOAD_PATH Array A synonym for $:. [r/o]
+# $-p Object Set to true if the -p option (which puts an implicit while gets . . . end
+# loop around your program) is present on the command line. [r/o]
+# $VERBOSE Object Set to true if the -v, --version, -W, or -w option is specified on the com-
+# mand line. Set to false if no option, or -W1 is given. Set to nil if -W0
+# was specified. Setting this option to true causes the interpreter and some
+# library routines to report additional information. Setting to nil suppresses
+# all warnings (including the output of Kernel.warn).
+# $-v Object Synonym for $VERBOSE.
+# $-w Object Synonym for $VERBOSE.
describe "Execution variable $:" do
it "is initialized to an array of strings" do
$:.is_a?(Array).should == true
@@ -835,6 +861,8 @@ describe "Execution variable $:" do
it "can be changed via <<" do
$: << "foo"
$:.should include("foo")
+ ensure
+ $:.delete("foo")
end
it "is read-only" do
@@ -850,6 +878,16 @@ describe "Execution variable $:" do
$-I = []
}.should raise_error(NameError)
end
+
+ it "default $LOAD_PATH entries until sitelibdir included have @gem_prelude_index set" do
+ skip "no sense in ruby itself" if MSpecScript.instance_variable_defined?(:@testing_ruby)
+
+ $:.should.include?(RbConfig::CONFIG['sitelibdir'])
+ idx = $:.index(RbConfig::CONFIG['sitelibdir'])
+
+ $:[idx..-1].all? { |p| p.instance_variable_defined?(:@gem_prelude_index) }.should be_true
+ $:[0...idx].all? { |p| !p.instance_variable_defined?(:@gem_prelude_index) }.should be_true
+ end
end
describe "Global variable $\"" do
@@ -941,6 +979,10 @@ describe "Global variable $VERBOSE" do
$VERBOSE = @verbose
end
+ it "is false by default" do
+ $VERBOSE.should be_false
+ end
+
it "converts truthy values to true" do
[true, 1, 0, [], ""].each do |true_value|
$VERBOSE = true_value
@@ -995,7 +1037,7 @@ describe "Global variable $0" do
it "is the path given as the main script and the same as __FILE__" do
script = "fixtures/dollar_zero.rb"
- Dir.chdir(File.dirname(__FILE__)) do
+ Dir.chdir(__dir__) do
ruby_exe(script).should == "#{script}\n#{script}\nOK"
end
end
@@ -1022,22 +1064,20 @@ describe "Global variable $0" do
end
end
-=begin
-Standard Objects
----------------------------------------------------------------------------------------------------
-
-ARGF Object A synonym for $<.
-ARGV Array A synonym for $*.
-ENV Object A hash-like object containing the program’s environment variables. An
- instance of class Object, ENV implements the full set of Hash methods. Used
- to query and set the value of an environment variable, as in ENV["PATH"]
- and ENV["term"]="ansi".
-false FalseClass Singleton instance of class FalseClass. [r/o]
-nil NilClass The singleton instance of class NilClass. The value of uninitialized
- instance and global variables. [r/o]
-self Object The receiver (object) of the current method. [r/o]
-true TrueClass Singleton instance of class TrueClass. [r/o]
-=end
+# Standard Objects
+# ---------------------------------------------------------------------------------------------------
+#
+# ARGF Object A synonym for $<.
+# ARGV Array A synonym for $*.
+# ENV Object A hash-like object containing the program’s environment variables. An
+# instance of class Object, ENV implements the full set of Hash methods. Used
+# to query and set the value of an environment variable, as in ENV["PATH"]
+# and ENV["term"]="ansi".
+# false FalseClass Singleton instance of class FalseClass. [r/o]
+# nil NilClass The singleton instance of class NilClass. The value of uninitialized
+# instance and global variables. [r/o]
+# self Object The receiver (object) of the current method. [r/o]
+# true TrueClass Singleton instance of class TrueClass. [r/o]
describe "The predefined standard objects" do
it "includes ARGF" do
@@ -1090,80 +1130,51 @@ describe "The self pseudo-variable" do
end
end
-=begin
-Global Constants
----------------------------------------------------------------------------------------------------
-
-The following constants are defined by the Ruby interpreter.
-
-DATA IO If the main program file contains the directive __END__, then
- the constant DATA will be initialized so that reading from it will
- return lines following __END__ from the source file.
-FALSE FalseClass Synonym for false (deprecated, removed in Ruby 3).
-NIL NilClass Synonym for nil (deprecated, removed in Ruby 3).
-RUBY_PLATFORM String The identifier of the platform running this program. This string
- is in the same form as the platform identifier used by the GNU
- configure utility (which is not a coincidence).
-RUBY_RELEASE_DATE String The date of this release.
-RUBY_VERSION String The version number of the interpreter.
-STDERR IO The actual standard error stream for the program. The initial
- value of $stderr.
-STDIN IO The actual standard input stream for the program. The initial
- value of $stdin.
-STDOUT IO The actual standard output stream for the program. The initial
- value of $stdout.
-SCRIPT_LINES__ Hash If a constant SCRIPT_LINES__ is defined and references a Hash,
- Ruby will store an entry containing the contents of each file it
- parses, with the file’s name as the key and an array of strings as
- the value.
-TOPLEVEL_BINDING Binding A Binding object representing the binding at Ruby’s top level—
- the level where programs are initially executed.
-TRUE TrueClass Synonym for true (deprecated, removed in Ruby 3).
-=end
+# Global Constants
+# ---------------------------------------------------------------------------------------------------
+#
+# The following constants are defined by the Ruby interpreter.
+#
+# DATA IO If the main program file contains the directive __END__, then
+# the constant DATA will be initialized so that reading from it will
+# return lines following __END__ from the source file.
+# FALSE FalseClass Synonym for false (deprecated, removed in Ruby 3).
+# NIL NilClass Synonym for nil (deprecated, removed in Ruby 3).
+# RUBY_PLATFORM String The identifier of the platform running this program. This string
+# is in the same form as the platform identifier used by the GNU
+# configure utility (which is not a coincidence).
+# RUBY_RELEASE_DATE String The date of this release.
+# RUBY_VERSION String The version number of the interpreter.
+# STDERR IO The actual standard error stream for the program. The initial
+# value of $stderr.
+# STDIN IO The actual standard input stream for the program. The initial
+# value of $stdin.
+# STDOUT IO The actual standard output stream for the program. The initial
+# value of $stdout.
+# SCRIPT_LINES__ Hash If a constant SCRIPT_LINES__ is defined and references a Hash,
+# Ruby will store an entry containing the contents of each file it
+# parses, with the file’s name as the key and an array of strings as
+# the value.
+# TOPLEVEL_BINDING Binding A Binding object representing the binding at Ruby’s top level—
+# the level where programs are initially executed.
+# TRUE TrueClass Synonym for true (deprecated, removed in Ruby 3).
describe "The predefined global constants" do
describe "TRUE" do
- ruby_version_is "3.0" do
- it "is no longer defined" do
- Object.const_defined?(:TRUE).should == false
- end
- end
-
- ruby_version_is ""..."3.0" do
- it "includes TRUE" do
- Object.const_defined?(:TRUE).should == true
- -> { TRUE }.should complain(/constant ::TRUE is deprecated/)
- end
+ it "is no longer defined" do
+ Object.const_defined?(:TRUE).should == false
end
end
describe "FALSE" do
- ruby_version_is "3.0" do
- it "is no longer defined" do
- Object.const_defined?(:FALSE).should == false
- end
- end
-
- ruby_version_is ""..."3.0" do
- it "includes FALSE" do
- Object.const_defined?(:FALSE).should == true
- -> { FALSE }.should complain(/constant ::FALSE is deprecated/)
- end
+ it "is no longer defined" do
+ Object.const_defined?(:FALSE).should == false
end
end
describe "NIL" do
- ruby_version_is "3.0" do
- it "is no longer defined" do
- Object.const_defined?(:NIL).should == false
- end
- end
-
- ruby_version_is ""..."3.0" do
- it "includes NIL" do
- Object.const_defined?(:NIL).should == true
- -> { NIL }.should complain(/constant ::NIL is deprecated/)
- end
+ it "is no longer defined" do
+ Object.const_defined?(:NIL).should == false
end
end
@@ -1304,32 +1315,57 @@ describe "The predefined global constant" do
end
end
-ruby_version_is "2.7" do
- describe "$LOAD_PATH.resolve_feature_path" do
- it "returns what will be loaded without actual loading, .rb file" do
- extension, path = $LOAD_PATH.resolve_feature_path('set')
- extension.should == :rb
- path.should.end_with?('/set.rb')
- end
+describe "$LOAD_PATH.resolve_feature_path" do
+ it "returns what will be loaded without actual loading, .rb file" do
+ extension, path = $LOAD_PATH.resolve_feature_path('set')
+ extension.should == :rb
+ path.should.end_with?('/set.rb')
+ end
- it "returns what will be loaded without actual loading, .so file" do
- require 'rbconfig'
+ it "returns what will be loaded without actual loading, .so file" do
+ require 'rbconfig'
+ skip "no dynamically loadable standard extension" if RbConfig::CONFIG["EXTSTATIC"] == "static"
- extension, path = $LOAD_PATH.resolve_feature_path('etc')
- extension.should == :so
- path.should.end_with?("/etc.#{RbConfig::CONFIG['DLEXT']}")
- end
+ extension, path = $LOAD_PATH.resolve_feature_path('etc')
+ extension.should == :so
+ path.should.end_with?("/etc.#{RbConfig::CONFIG['DLEXT']}")
+ end
- ruby_version_is "2.7"..."3.1" do
- it "raises LoadError if feature cannot be found" do
- -> { $LOAD_PATH.resolve_feature_path('noop') }.should raise_error(LoadError)
- end
+ ruby_version_is ""..."3.1" do
+ it "raises LoadError if feature cannot be found" do
+ -> { $LOAD_PATH.resolve_feature_path('noop') }.should raise_error(LoadError)
end
+ end
- ruby_version_is "3.1" do
- it "return nil if feature cannot be found" do
- $LOAD_PATH.resolve_feature_path('noop').should be_nil
- end
+ ruby_version_is "3.1" do
+ it "return nil if feature cannot be found" do
+ $LOAD_PATH.resolve_feature_path('noop').should be_nil
end
end
end
+
+# Some other pre-defined global variables
+
+describe "Predefined global $=" do
+ before :each do
+ @verbose, $VERBOSE = $VERBOSE, nil
+ @dollar_assign = $=
+ end
+
+ after :each do
+ $= = @dollar_assign
+ $VERBOSE = @verbose
+ end
+
+ it "warns when accessed" do
+ -> { a = $= }.should complain(/is no longer effective/)
+ end
+
+ it "warns when assigned" do
+ -> { $= = "_" }.should complain(/is no longer effective/)
+ end
+
+ it "returns the value assigned" do
+ ($= = "xyz").should == "xyz"
+ end
+end
diff --git a/spec/ruby/language/proc_spec.rb b/spec/ruby/language/proc_spec.rb
index ef4a43bed6..cc69b7799c 100644
--- a/spec/ruby/language/proc_spec.rb
+++ b/spec/ruby/language/proc_spec.rb
@@ -161,6 +161,18 @@ describe "A Proc" do
end
end
+ describe "taking |*a, b| arguments" do
+ it "assigns [] to the argument when passed no values" do
+ proc { |*a, b| [a, b] }.call.should == [[], nil]
+ end
+ end
+
+ describe "taking |a, *b, c| arguments" do
+ it "assigns [] to the argument when passed no values" do
+ proc { |a, *b, c| [a, b, c] }.call.should == [nil, [], nil]
+ end
+ end
+
describe "taking |a, | arguments" do
before :each do
@l = lambda { |a, | a }
@@ -223,24 +235,15 @@ describe "A Proc" do
@p = proc { |*a, **kw| [a, kw] }
end
- ruby_version_is ""..."2.7" do
- it 'autosplats keyword arguments' do
- @p.call([1, {a: 1}]).should == [[1], {a: 1}]
- end
- end
-
- ruby_version_is "2.7"..."3.0" do
- it 'autosplats keyword arguments and warns' do
- -> {
- @p.call([1, {a: 1}]).should == [[1], {a: 1}]
- }.should complain(/warning: Using the last argument as keyword parameters is deprecated; maybe \*\* should be added to the call/)
- end
+ it 'does not autosplat keyword arguments' do
+ @p.call([1, {a: 1}]).should == [[[1, {a: 1}]], {}]
end
+ end
- ruby_version_is "3.0" do
- it 'does not autosplat keyword arguments' do
- @p.call([1, {a: 1}]).should == [[[1, {a: 1}]], {}]
- end
+ describe "taking |required keyword arguments, **kw| arguments" do
+ it "raises ArgumentError for missing required argument" do
+ p = proc { |a:, **kw| [a, kw] }
+ -> { p.call() }.should raise_error(ArgumentError)
end
end
end
diff --git a/spec/ruby/language/range_spec.rb b/spec/ruby/language/range_spec.rb
index 4cde7e9488..ccc9f55537 100644
--- a/spec/ruby/language/range_spec.rb
+++ b/spec/ruby/language/range_spec.rb
@@ -10,21 +10,21 @@ describe "Literal Ranges" do
(1...10).should == Range.new(1, 10, true)
end
+ it "creates a simple range as an object literal" do
+ ary = []
+ 2.times do
+ ary.push(1..3)
+ end
+ ary[0].should.equal?(ary[1])
+ end
+
it "creates endless ranges" do
(1..).should == Range.new(1, nil)
(1...).should == Range.new(1, nil, true)
end
- ruby_version_is "3.0" do
- it "is frozen" do
- (42..).should.frozen?
- end
- end
-
- ruby_version_is "2.7" do
- it "creates beginless ranges" do
- eval("(..1)").should == Range.new(nil, 1)
- eval("(...1)").should == Range.new(nil, 1, true)
- end
+ it "creates beginless ranges" do
+ (..1).should == Range.new(nil, 1)
+ (...1).should == Range.new(nil, 1, true)
end
end
diff --git a/spec/ruby/language/regexp/character_classes_spec.rb b/spec/ruby/language/regexp/character_classes_spec.rb
index 0cf1e9b6f4..98d431a817 100644
--- a/spec/ruby/language/regexp/character_classes_spec.rb
+++ b/spec/ruby/language/regexp/character_classes_spec.rb
@@ -609,10 +609,13 @@ describe "Regexp with character classes" do
"루비(Ruby)".match(/\p{Hangul}+/u).to_a.should == ["루비"]
end
- ruby_bug "#17340", ''...'3.0' do
- it "raises a RegexpError for an unterminated unicode property" do
- -> { Regexp.new('\p{') }.should raise_error(RegexpError)
- end
+ it "supports negated property condition" do
+ "a".match(eval("/\P{L}/")).should be_nil
+ "1".match(eval("/\P{N}/")).should be_nil
+ end
+
+ it "raises a RegexpError for an unterminated unicode property" do
+ -> { Regexp.new('\p{') }.should raise_error(RegexpError)
end
it "supports \\X (unicode 9.0 with UTR #51 workarounds)" do
diff --git a/spec/ruby/language/regexp/encoding_spec.rb b/spec/ruby/language/regexp/encoding_spec.rb
index febc3fdb37..0571b2d3cf 100644
--- a/spec/ruby/language/regexp/encoding_spec.rb
+++ b/spec/ruby/language/regexp/encoding_spec.rb
@@ -4,18 +4,18 @@ require_relative '../fixtures/classes'
describe "Regexps with encoding modifiers" do
it "supports /e (EUC encoding)" do
- match = /./e.match("\303\251".force_encoding(Encoding::EUC_JP))
- match.to_a.should == ["\303\251".force_encoding(Encoding::EUC_JP)]
+ match = /./e.match("\303\251".dup.force_encoding(Encoding::EUC_JP))
+ match.to_a.should == ["\303\251".dup.force_encoding(Encoding::EUC_JP)]
end
it "supports /e (EUC encoding) with interpolation" do
- match = /#{/./}/e.match("\303\251".force_encoding(Encoding::EUC_JP))
- match.to_a.should == ["\303\251".force_encoding(Encoding::EUC_JP)]
+ match = /#{/./}/e.match("\303\251".dup.force_encoding(Encoding::EUC_JP))
+ match.to_a.should == ["\303\251".dup.force_encoding(Encoding::EUC_JP)]
end
it "supports /e (EUC encoding) with interpolation /o" do
- match = /#{/./}/e.match("\303\251".force_encoding(Encoding::EUC_JP))
- match.to_a.should == ["\303\251".force_encoding(Encoding::EUC_JP)]
+ match = /#{/./}/e.match("\303\251".dup.force_encoding(Encoding::EUC_JP))
+ match.to_a.should == ["\303\251".dup.force_encoding(Encoding::EUC_JP)]
end
it 'uses EUC-JP as /e encoding' do
@@ -39,7 +39,7 @@ describe "Regexps with encoding modifiers" do
end
it "warns when using /n with a match string with non-ASCII characters and an encoding other than ASCII-8BIT" do
- -> { /./n.match("\303\251".force_encoding('utf-8')) }.should complain(%r{historical binary regexp match /.../n against UTF-8 string})
+ -> { /./n.match("\303\251".dup.force_encoding('utf-8')) }.should complain(%r{historical binary regexp match /.../n against UTF-8 string})
end
it 'uses US-ASCII as /n encoding if all chars are 7-bit' do
@@ -63,18 +63,18 @@ describe "Regexps with encoding modifiers" do
end
it "supports /s (Windows_31J encoding)" do
- match = /./s.match("\303\251".force_encoding(Encoding::Windows_31J))
- match.to_a.should == ["\303".force_encoding(Encoding::Windows_31J)]
+ match = /./s.match("\303\251".dup.force_encoding(Encoding::Windows_31J))
+ match.to_a.should == ["\303".dup.force_encoding(Encoding::Windows_31J)]
end
it "supports /s (Windows_31J encoding) with interpolation" do
- match = /#{/./}/s.match("\303\251".force_encoding(Encoding::Windows_31J))
- match.to_a.should == ["\303".force_encoding(Encoding::Windows_31J)]
+ match = /#{/./}/s.match("\303\251".dup.force_encoding(Encoding::Windows_31J))
+ match.to_a.should == ["\303".dup.force_encoding(Encoding::Windows_31J)]
end
it "supports /s (Windows_31J encoding) with interpolation and /o" do
- match = /#{/./}/s.match("\303\251".force_encoding(Encoding::Windows_31J))
- match.to_a.should == ["\303".force_encoding(Encoding::Windows_31J)]
+ match = /#{/./}/s.match("\303\251".dup.force_encoding(Encoding::Windows_31J))
+ match.to_a.should == ["\303".dup.force_encoding(Encoding::Windows_31J)]
end
it 'uses Windows-31J as /s encoding' do
@@ -86,15 +86,15 @@ describe "Regexps with encoding modifiers" do
end
it "supports /u (UTF8 encoding)" do
- /./u.match("\303\251".force_encoding('utf-8')).to_a.should == ["\u{e9}"]
+ /./u.match("\303\251".dup.force_encoding('utf-8')).to_a.should == ["\u{e9}"]
end
it "supports /u (UTF8 encoding) with interpolation" do
- /#{/./}/u.match("\303\251".force_encoding('utf-8')).to_a.should == ["\u{e9}"]
+ /#{/./}/u.match("\303\251".dup.force_encoding('utf-8')).to_a.should == ["\u{e9}"]
end
it "supports /u (UTF8 encoding) with interpolation and /o" do
- /#{/./}/u.match("\303\251".force_encoding('utf-8')).to_a.should == ["\u{e9}"]
+ /#{/./}/u.match("\303\251".dup.force_encoding('utf-8')).to_a.should == ["\u{e9}"]
end
it 'uses UTF-8 as /u encoding' do
@@ -122,26 +122,26 @@ describe "Regexps with encoding modifiers" do
end
it "raises Encoding::CompatibilityError when the regexp has a fixed, non-ASCII-compatible encoding" do
- -> { Regexp.new("".force_encoding("UTF-16LE"), Regexp::FIXEDENCODING) =~ " ".encode("UTF-8") }.should raise_error(Encoding::CompatibilityError)
+ -> { Regexp.new("".dup.force_encoding("UTF-16LE"), Regexp::FIXEDENCODING) =~ " ".encode("UTF-8") }.should raise_error(Encoding::CompatibilityError)
end
it "raises Encoding::CompatibilityError when the regexp has a fixed encoding and the match string has non-ASCII characters" do
- -> { Regexp.new("".force_encoding("US-ASCII"), Regexp::FIXEDENCODING) =~ "\303\251".force_encoding('UTF-8') }.should raise_error(Encoding::CompatibilityError)
+ -> { Regexp.new("".dup.force_encoding("US-ASCII"), Regexp::FIXEDENCODING) =~ "\303\251".dup.force_encoding('UTF-8') }.should raise_error(Encoding::CompatibilityError)
end
it "raises ArgumentError when trying to match a broken String" do
- s = "\x80".force_encoding('UTF-8')
+ s = "\x80".dup.force_encoding('UTF-8')
-> { s =~ /./ }.should raise_error(ArgumentError, "invalid byte sequence in UTF-8")
end
it "computes the Regexp Encoding for each interpolated Regexp instance" do
make_regexp = -> str { /#{str}/ }
- r = make_regexp.call("été".force_encoding(Encoding::UTF_8))
+ r = make_regexp.call("été".dup.force_encoding(Encoding::UTF_8))
r.should.fixed_encoding?
r.encoding.should == Encoding::UTF_8
- r = make_regexp.call("abc".force_encoding(Encoding::UTF_8))
+ r = make_regexp.call("abc".dup.force_encoding(Encoding::UTF_8))
r.should_not.fixed_encoding?
r.encoding.should == Encoding::US_ASCII
end
diff --git a/spec/ruby/language/regexp/escapes_spec.rb b/spec/ruby/language/regexp/escapes_spec.rb
index 2e5fe5ad2e..16a4d8c23b 100644
--- a/spec/ruby/language/regexp/escapes_spec.rb
+++ b/spec/ruby/language/regexp/escapes_spec.rb
@@ -2,8 +2,10 @@
require_relative '../../spec_helper'
require_relative '../fixtures/classes'
+# TODO: synchronize with spec/core/regexp/new_spec.rb -
+# escaping is also tested there
describe "Regexps with escape characters" do
- it "they're supported" do
+ it "supports escape sequences" do
/\t/.match("\t").to_a.should == ["\t"] # horizontal tab
/\v/.match("\v").to_a.should == ["\v"] # vertical tab
/\n/.match("\n").to_a.should == ["\n"] # newline
@@ -15,9 +17,7 @@ describe "Regexps with escape characters" do
# \nnn octal char (encoded byte value)
end
- it "support quoting meta-characters via escape sequence" do
- /\\/.match("\\").to_a.should == ["\\"]
- /\//.match("/").to_a.should == ["/"]
+ it "supports quoting meta-characters via escape sequence" do
# parenthesis, etc
/\(/.match("(").to_a.should == ["("]
/\)/.match(")").to_a.should == [")"]
@@ -25,6 +25,8 @@ describe "Regexps with escape characters" do
/\]/.match("]").to_a.should == ["]"]
/\{/.match("{").to_a.should == ["{"]
/\}/.match("}").to_a.should == ["}"]
+ /\</.match("<").to_a.should == ["<"]
+ /\>/.match(">").to_a.should == [">"]
# alternation separator
/\|/.match("|").to_a.should == ["|"]
# quantifiers
@@ -37,11 +39,81 @@ describe "Regexps with escape characters" do
/\$/.match("$").to_a.should == ["$"]
end
+ it "supports quoting meta-characters via escape sequence when used as a terminator" do
+ # parenthesis, etc
+ # %r[[, %r((, etc literals - are forbidden
+ %r(\().match("(").to_a.should == ["("]
+ %r(\)).match(")").to_a.should == [")"]
+ %r)\().match("(").to_a.should == ["("]
+ %r)\)).match(")").to_a.should == [")"]
+
+ %r[\[].match("[").to_a.should == ["["]
+ %r[\]].match("]").to_a.should == ["]"]
+ %r]\[].match("[").to_a.should == ["["]
+ %r]\]].match("]").to_a.should == ["]"]
+
+ %r{\{}.match("{").to_a.should == ["{"]
+ %r{\}}.match("}").to_a.should == ["}"]
+ %r}\{}.match("{").to_a.should == ["{"]
+ %r}\}}.match("}").to_a.should == ["}"]
+
+ %r<\<>.match("<").to_a.should == ["<"]
+ %r<\>>.match(">").to_a.should == [">"]
+ %r>\<>.match("<").to_a.should == ["<"]
+ %r>\>>.match(">").to_a.should == [">"]
+
+ # alternation separator
+ %r|\||.match("|").to_a.should == ["|"]
+ # quantifiers
+ %r?\??.match("?").to_a.should == ["?"]
+ %r.\...match(".").to_a.should == ["."]
+ %r*\**.match("*").to_a.should == ["*"]
+ %r+\++.match("+").to_a.should == ["+"]
+ # line anchors
+ %r^\^^.match("^").to_a.should == ["^"]
+ %r$\$$.match("$").to_a.should == ["$"]
+ end
+
+ it "supports quoting non-meta-characters via escape sequence when used as a terminator" do
+ non_meta_character_terminators = [
+ '!', '"', '#', '%', '&', "'", ',', '-', ':', ';', '@', '_', '`', '/', '=', '~'
+ ]
+
+ non_meta_character_terminators.each do |c|
+ pattern = eval("%r" + c + "\\" + c + c)
+ pattern.match(c).to_a.should == [c]
+ end
+ end
+
+ it "does not change semantics of escaped non-meta-character when used as a terminator" do
+ all_terminators = [*("!".."/"), *(":".."@"), *("[".."`"), *("{".."~")]
+ meta_character_terminators = ["$", "^", "*", "+", ".", "?", "|", "}", ")", ">", "]"]
+ special_cases = ['(', '{', '[', '<', '\\']
+
+ # it should be equivalent to
+ # [ '!', '"', '#', '%', '&', "'", ',', '-', ':', ';', '@', '_', '`', '/', '=', '~' ]
+ non_meta_character_terminators = all_terminators - meta_character_terminators - special_cases
+
+ non_meta_character_terminators.each do |c|
+ pattern = eval("%r" + c + "\\" + c + c)
+ pattern.should == /#{c}/
+ end
+ end
+
+ it "does not change semantics of escaped meta-character when used as a terminator" do
+ meta_character_terminators = ["$", "^", "*", "+", ".", "?", "|", "}", ")", ">", "]"]
+
+ meta_character_terminators.each do |c|
+ pattern = eval("%r" + c + "\\" + c + c)
+ pattern.should == eval("/\\#{c}/")
+ end
+ end
+
it "allows any character to be escaped" do
/\y/.match("y").to_a.should == ["y"]
end
- it "support \\x (hex characters)" do
+ it "supports \\x (hex characters)" do
/\xA/.match("\nxyz").to_a.should == ["\n"]
/\x0A/.match("\n").to_a.should == ["\n"]
/\xAA/.match("\nA").should be_nil
@@ -53,7 +125,7 @@ describe "Regexps with escape characters" do
# \x{7HHHHHHH} wide hexadecimal char (character code point value)
end
- it "support \\c (control characters)" do
+ it "supports \\c (control characters)" do
#/\c \c@\c`/.match("\00\00\00").to_a.should == ["\00\00\00"]
/\c#\cc\cC/.match("\03\03\03").to_a.should == ["\03\03\03"]
/\c'\cG\cg/.match("\a\a\a").to_a.should == ["\a\a\a"]
diff --git a/spec/ruby/language/regexp/repetition_spec.rb b/spec/ruby/language/regexp/repetition_spec.rb
index 9a191d74e2..d76619688f 100644
--- a/spec/ruby/language/regexp/repetition_spec.rb
+++ b/spec/ruby/language/regexp/repetition_spec.rb
@@ -87,9 +87,7 @@ describe "Regexps with repetition" do
/a+?*/.match("a")[0].should == "a"
/(a+?)*/.match("a")[0].should == "a"
- ruby_bug '#17341', ''...'3.0' do
- /a+?*/.match("aa")[0].should == "aa"
- end
+ /a+?*/.match("aa")[0].should == "aa"
/(a+?)*/.match("aa")[0].should == "aa"
# a+?+ should not be reduced, it should be equivalent to (a+?)+
@@ -100,9 +98,7 @@ describe "Regexps with repetition" do
/a+?+/.match("a")[0].should == "a"
/(a+?)+/.match("a")[0].should == "a"
- ruby_bug '#17341', ''...'3.0' do
- /a+?+/.match("aa")[0].should == "aa"
- end
+ /a+?+/.match("aa")[0].should == "aa"
/(a+?)+/.match("aa")[0].should == "aa"
# both a**? and a+*? should be equivalent to (a+)??
diff --git a/spec/ruby/language/regexp_spec.rb b/spec/ruby/language/regexp_spec.rb
index 8fc4dc4f0a..89d0914807 100644
--- a/spec/ruby/language/regexp_spec.rb
+++ b/spec/ruby/language/regexp_spec.rb
@@ -18,10 +18,8 @@ describe "Literal Regexps" do
/Hello/.should be_kind_of(Regexp)
end
- ruby_version_is "3.0" do
- it "is frozen" do
- /Hello/.should.frozen?
- end
+ it "is frozen" do
+ /Hello/.should.frozen?
end
it "caches the Regexp object" do
@@ -96,7 +94,6 @@ describe "Literal Regexps" do
/./.match("\0").to_a.should == ["\0"]
end
-
it "supports | (alternations)" do
/a|b/.match("a").to_a.should == ["a"]
end
@@ -115,7 +112,7 @@ describe "Literal Regexps" do
/foo.(?<=\d)/.match("fooA foo1").to_a.should == ["foo1"]
end
- ruby_bug "#13671", ""..."3.3" do # https://bugs.ruby-lang.org/issues/13671
+ ruby_bug "#13671", ""..."3.5" do # https://bugs.ruby-lang.org/issues/13671
it "handles a lookbehind with ss characters" do
r = Regexp.new("(?<!dss)", Regexp::IGNORECASE)
r.should =~ "✨"
@@ -161,26 +158,6 @@ describe "Literal Regexps" do
pattern.should_not =~ 'T'
end
- escapable_terminators = ['!', '"', '#', '%', '&', "'", ',', '-', ':', ';', '@', '_', '`']
-
- it "supports escaping characters when used as a terminator" do
- escapable_terminators.each do |c|
- ref = "(?-mix:#{c})"
- pattern = eval("%r" + c + "\\" + c + c)
- pattern.to_s.should == ref
- end
- end
-
- it "treats an escaped non-escapable character normally when used as a terminator" do
- all_terminators = [*("!".."/"), *(":".."@"), *("[".."`"), *("{".."~")]
- special_cases = ['(', '{', '[', '<', '\\', '=', '~']
- (all_terminators - special_cases - escapable_terminators).each do |c|
- ref = "(?-mix:\\#{c})"
- pattern = eval("%r" + c + "\\" + c + c)
- pattern.to_s.should == ref
- end
- end
-
it "support handling unicode 9.0 characters with POSIX bracket expressions" do
char_lowercase = "\u{104D8}" # OSAGE SMALL LETTER A
/[[:lower:]]/.match(char_lowercase).to_s.should == char_lowercase
diff --git a/spec/ruby/language/rescue_spec.rb b/spec/ruby/language/rescue_spec.rb
index 4d164b38c6..a3ee4807ac 100644
--- a/spec/ruby/language/rescue_spec.rb
+++ b/spec/ruby/language/rescue_spec.rb
@@ -61,6 +61,78 @@ describe "The rescue keyword" do
end
end
+ describe 'capturing in a local variable (that defines it)' do
+ it 'captures successfully in a method' do
+ ScratchPad.record []
+
+ def a
+ raise "message"
+ rescue => e
+ ScratchPad << e.message
+ end
+
+ a
+ ScratchPad.recorded.should == ["message"]
+ end
+
+ it 'captures successfully in a block' do
+ ScratchPad.record []
+
+ p = proc do
+ raise "message"
+ rescue => e
+ ScratchPad << e.message
+ end
+
+ p.call
+ ScratchPad.recorded.should == ["message"]
+ end
+
+ it 'captures successfully in a class' do
+ ScratchPad.record []
+
+ class RescueSpecs::C
+ raise "message"
+ rescue => e
+ ScratchPad << e.message
+ end
+
+ ScratchPad.recorded.should == ["message"]
+ end
+
+ it 'captures successfully in a module' do
+ ScratchPad.record []
+
+ module RescueSpecs::M
+ raise "message"
+ rescue => e
+ ScratchPad << e.message
+ end
+
+ ScratchPad.recorded.should == ["message"]
+ end
+
+ it 'captures sucpcessfully in a singleton class' do
+ ScratchPad.record []
+
+ class << Object.new
+ raise "message"
+ rescue => e
+ ScratchPad << e.message
+ end
+
+ ScratchPad.recorded.should == ["message"]
+ end
+
+ it 'captures successfully at the top-level' do
+ ScratchPad.record []
+
+ require_relative 'fixtures/rescue/top_level'
+
+ ScratchPad.recorded.should == ["message"]
+ end
+ end
+
it "returns value from `rescue` if an exception was raised" do
begin
raise
@@ -115,6 +187,18 @@ describe "The rescue keyword" do
end
end
+ it "converts the splatted list of exceptions using #to_a" do
+ exceptions = mock("to_a")
+ exceptions.should_receive(:to_a).and_return(exception_list)
+ caught_it = false
+ begin
+ raise SpecificExampleException, "not important"
+ rescue *exceptions
+ caught_it = true
+ end
+ caught_it.should be_true
+ end
+
it "can combine a splatted list of exceptions with a literal list of exceptions" do
caught_it = false
begin
@@ -179,7 +263,7 @@ describe "The rescue keyword" do
rescue ArgumentError
end
rescue StandardError => e
- e.backtrace.first.should include ":in `raise_standard_error'"
+ e.backtrace.first.should =~ /:in [`'](?:RescueSpecs\.)?raise_standard_error'/
else
fail("exception wasn't handled by the correct rescue block")
end
@@ -469,6 +553,23 @@ describe "The rescue keyword" do
eval('1.+((1 rescue 1))').should == 2
end
+ ruby_version_is "3.4" do
+ it "does not introduce extra backtrace entries" do
+ def foo
+ begin
+ raise "oops"
+ rescue
+ return caller(0, 2)
+ end
+ end
+ line = __LINE__
+ foo.should == [
+ "#{__FILE__}:#{line-3}:in 'foo'",
+ "#{__FILE__}:#{line+1}:in 'block (3 levels) in <top (required)>'"
+ ]
+ end
+ end
+
describe "inline form" do
it "can be inlined" do
a = 1/0 rescue 1
@@ -492,14 +593,12 @@ describe "The rescue keyword" do
}.should raise_error(Exception)
end
- ruby_version_is "2.7" do
- it "rescues with multiple assignment" do
+ it "rescues with multiple assignment" do
- a, b = raise rescue [1, 2]
+ a, b = raise rescue [1, 2]
- a.should == 1
- b.should == 2
- end
+ a.should == 1
+ b.should == 2
end
end
end
diff --git a/spec/ruby/language/return_spec.rb b/spec/ruby/language/return_spec.rb
index d8506834c8..a62ed1242d 100644
--- a/spec/ruby/language/return_spec.rb
+++ b/spec/ruby/language/return_spec.rb
@@ -422,18 +422,31 @@ describe "The return keyword" do
end
describe "within a block within a class" do
- ruby_version_is "2.7" do
- it "is not allowed" do
- File.write(@filename, <<-END_OF_CODE)
- class ReturnSpecs::A
- ScratchPad << "before return"
- 1.times { return }
- ScratchPad << "after return"
- end
- END_OF_CODE
-
- -> { load @filename }.should raise_error(LocalJumpError)
- end
+ it "is not allowed" do
+ File.write(@filename, <<-END_OF_CODE)
+ class ReturnSpecs::A
+ ScratchPad << "before return"
+ 1.times { return }
+ ScratchPad << "after return"
+ end
+ END_OF_CODE
+
+ -> { load @filename }.should raise_error(LocalJumpError)
+ end
+ end
+
+ describe "within BEGIN" do
+ it "is allowed" do
+ File.write(@filename, <<-END_OF_CODE)
+ BEGIN {
+ ScratchPad << "before call"
+ return
+ ScratchPad << "after call"
+ }
+ END_OF_CODE
+
+ load @filename
+ ScratchPad.recorded.should == ["before call"]
end
end
@@ -464,25 +477,13 @@ describe "The return keyword" do
end
describe "return with argument" do
- ruby_version_is ""..."2.7" do
- it "does not affect exit status" do
- ruby_exe(<<-END_OF_CODE).should == ""
- return 10
- END_OF_CODE
-
- $?.exitstatus.should == 0
- end
- end
-
- ruby_version_is "2.7" do
- it "warns but does not affect exit status" do
- err = ruby_exe(<<-END_OF_CODE, args: "2>&1")
- return 10
- END_OF_CODE
- $?.exitstatus.should == 0
+ it "warns but does not affect exit status" do
+ err = ruby_exe(<<-END_OF_CODE, args: "2>&1")
+ return 10
+ END_OF_CODE
+ $?.exitstatus.should == 0
- err.should =~ /warning: argument of top-level return is ignored/
- end
+ err.should =~ /warning: argument of top-level return is ignored/
end
end
end
diff --git a/spec/ruby/language/safe_navigator_spec.rb b/spec/ruby/language/safe_navigator_spec.rb
index c3aecff2dd..b1e28c3963 100644
--- a/spec/ruby/language/safe_navigator_spec.rb
+++ b/spec/ruby/language/safe_navigator_spec.rb
@@ -7,43 +7,43 @@ describe "Safe navigator" do
context "when context is nil" do
it "always returns nil" do
- eval("nil&.unknown").should == nil
- eval("[][10]&.unknown").should == nil
+ nil&.unknown.should == nil
+ [][10]&.unknown.should == nil
end
it "can be chained" do
- eval("nil&.one&.two&.three").should == nil
+ nil&.one&.two&.three.should == nil
end
it "doesn't evaluate arguments" do
obj = Object.new
obj.should_not_receive(:m)
- eval("nil&.unknown(obj.m) { obj.m }")
+ nil&.unknown(obj.m) { obj.m }
end
end
context "when context is false" do
it "calls the method" do
- eval("false&.to_s").should == "false"
+ false&.to_s.should == "false"
- -> { eval("false&.unknown") }.should raise_error(NoMethodError)
+ -> { false&.unknown }.should raise_error(NoMethodError)
end
end
context "when context is truthy" do
it "calls the method" do
- eval("1&.to_s").should == "1"
+ 1&.to_s.should == "1"
- -> { eval("1&.unknown") }.should raise_error(NoMethodError)
+ -> { 1&.unknown }.should raise_error(NoMethodError)
end
end
it "takes a list of arguments" do
- eval("[1,2,3]&.first(2)").should == [1,2]
+ [1,2,3]&.first(2).should == [1,2]
end
it "takes a block" do
- eval("[1,2]&.map { |i| i * 2 }").should == [2, 4]
+ [1,2]&.map { |i| i * 2 }.should == [2, 4]
end
it "allows assignment methods" do
@@ -56,29 +56,77 @@ describe "Safe navigator" do
end
obj = klass.new
- eval("obj&.foo = 3").should == 3
+ (obj&.foo = 3).should == 3
obj.foo.should == 3
obj = nil
- eval("obj&.foo = 3").should == nil
+ (obj&.foo = 3).should == nil
end
it "allows assignment operators" do
klass = Class.new do
- attr_accessor :m
+ attr_reader :m
def initialize
@m = 0
end
+
+ def m=(v)
+ @m = v
+ 42
+ end
end
obj = klass.new
- eval("obj&.m += 3")
+ obj&.m += 3
obj.m.should == 3
obj = nil
- eval("obj&.m += 3").should == nil
+ (obj&.m += 3).should == nil
+ end
+
+ it "allows ||= operator" do
+ klass = Class.new do
+ attr_reader :m
+
+ def initialize
+ @m = false
+ end
+
+ def m=(v)
+ @m = v
+ 42
+ end
+ end
+
+ obj = klass.new
+
+ (obj&.m ||= true).should == true
+ obj.m.should == true
+
+ obj = nil
+ (obj&.m ||= true).should == nil
+ obj.should == nil
+ end
+
+ it "allows &&= operator" do
+ klass = Class.new do
+ attr_accessor :m
+
+ def initialize
+ @m = true
+ end
+ end
+
+ obj = klass.new
+
+ (obj&.m &&= false).should == false
+ obj.m.should == false
+
+ obj = nil
+ (obj&.m &&= false).should == nil
+ obj.should == nil
end
it "does not call the operator method lazily with an assignment operator" do
@@ -91,7 +139,7 @@ describe "Safe navigator" do
obj = klass.new
-> {
- eval("obj&.foo += 3")
+ obj&.foo += 3
}.should raise_error(NoMethodError) { |e|
e.name.should == :+
}
diff --git a/spec/ruby/language/safe_spec.rb b/spec/ruby/language/safe_spec.rb
index 89830a2069..03ae96148e 100644
--- a/spec/ruby/language/safe_spec.rb
+++ b/spec/ruby/language/safe_spec.rb
@@ -1,119 +1,11 @@
require_relative '../spec_helper'
describe "The $SAFE variable" do
- ruby_version_is ""..."2.7" do
- after :each do
- $SAFE = 0
- end
-
- it "is 0 by default" do
- $SAFE.should == 0
- proc {
- $SAFE.should == 0
- }.call
- end
-
- it "can be set to 0" do
- proc {
- $SAFE = 0
- $SAFE.should == 0
- }.call
- end
-
- it "can be set to 1" do
- proc {
- $SAFE = 1
- $SAFE.should == 1
- }.call
- end
-
- [2, 3, 4].each do |n|
- it "cannot be set to #{n}" do
- -> {
- proc {
- $SAFE = n
- }.call
- }.should raise_error(ArgumentError, /\$SAFE=2 to 4 are obsolete/)
- end
- end
-
- it "raises ArgumentError when set to values below 0" do
- -> {
- proc {
- $SAFE = -100
- }.call
- }.should raise_error(ArgumentError, "$SAFE should be >= 0")
- end
-
- it "cannot be set to values above 4" do
- -> {
- proc {
- $SAFE = 100
- }.call
- }.should raise_error(ArgumentError, /\$SAFE=2 to 4 are obsolete/)
- end
-
- it "can be manually lowered" do
- $SAFE = 1
- $SAFE = 0
- $SAFE.should == 0
- end
-
- it "is not Proc local" do
- $SAFE.should == 0
- proc {
- $SAFE = 1
- }.call
- $SAFE.should == 1
- end
-
- it "is not lambda local" do
- $SAFE.should == 0
- -> {
- $SAFE = 1
- }.call
- $SAFE.should == 1
- end
-
- it "is global like regular global variables" do
- Thread.new { $SAFE }.value.should == 0
- $SAFE = 1
- Thread.new { $SAFE }.value.should == 1
- end
-
- it "can be read when default from Thread#safe_level" do
- Thread.current.safe_level.should == 0
- end
-
- it "can be read when modified from Thread#safe_level" do
- proc {
- $SAFE = 1
- Thread.current.safe_level.should == 1
- }.call
- end
- end
-
- ruby_version_is "2.7"..."3.0" do
- it "warn when access" do
- -> {
- $SAFE
- }.should complain(/\$SAFE will become a normal global variable in Ruby 3.0/)
- end
-
- it "warn when set" do
- -> {
- $SAFE = 1
- }.should complain(/\$SAFE will become a normal global variable in Ruby 3.0/)
- end
- end
-
- ruby_version_is "3.0" do
- it "$SAFE is a regular global variable" do
- $SAFE.should == nil
- $SAFE = 42
- $SAFE.should == 42
- ensure
- $SAFE = nil
- end
+ it "$SAFE is a regular global variable" do
+ $SAFE.should == nil
+ $SAFE = 42
+ $SAFE.should == 42
+ ensure
+ $SAFE = nil
end
end
diff --git a/spec/ruby/language/send_spec.rb b/spec/ruby/language/send_spec.rb
index e57e2c65dc..aaccdf0998 100644
--- a/spec/ruby/language/send_spec.rb
+++ b/spec/ruby/language/send_spec.rb
@@ -43,7 +43,7 @@ describe "Invoking a method" do
end
describe "with optional arguments" do
- it "uses the optional argument if none is is passed" do
+ it "uses the optional argument if none is passed" do
specs.fooM0O1.should == [1]
end
@@ -258,20 +258,10 @@ describe "Invoking a private setter method" do
end
describe "Invoking a private getter method" do
- ruby_version_is ""..."2.7" do
- it "does not permit self as a receiver" do
- receiver = LangSendSpecs::PrivateGetter.new
- -> { receiver.call_self_foo }.should raise_error(NoMethodError)
- -> { receiver.call_self_foo_or_equals(6) }.should raise_error(NoMethodError)
- end
- end
-
- ruby_version_is "2.7" do
- it "permits self as a receiver" do
- receiver = LangSendSpecs::PrivateGetter.new
- receiver.call_self_foo_or_equals(6)
- receiver.call_self_foo.should == 6
- end
+ it "permits self as a receiver" do
+ receiver = LangSendSpecs::PrivateGetter.new
+ receiver.call_self_foo_or_equals(6)
+ receiver.call_self_foo.should == 6
end
end
@@ -421,36 +411,18 @@ describe "Invoking a method" do
specs.rest_len(0,*a,4,*5,6,7,*c,-1).should == 11
end
- ruby_version_is ""..."3.0" do
- it "expands the Array elements from the splat after executing the arguments and block if no other arguments follow the splat" do
- def self.m(*args, &block)
- [args, block]
- end
-
- args = [1, nil]
- m(*args, &args.pop).should == [[1], nil]
-
- args = [1, nil]
- order = []
- m(*(order << :args; args), &(order << :block; args.pop)).should == [[1], nil]
- order.should == [:args, :block]
+ it "expands the Array elements from the splat before applying block argument operations" do
+ def self.m(*args, &block)
+ [args, block]
end
- end
-
- ruby_version_is "3.0" do
- it "expands the Array elements from the splat before applying block argument operations" do
- def self.m(*args, &block)
- [args, block]
- end
- args = [1, nil]
- m(*args, &args.pop).should == [[1, nil], nil]
+ args = [1, nil]
+ m(*args, &args.pop).should == [[1, nil], nil]
- args = [1, nil]
- order = []
- m(*(order << :args; args), &(order << :block; args.pop)).should == [[1, nil], nil]
- order.should == [:args, :block]
- end
+ args = [1, nil]
+ order = []
+ m(*(order << :args; args), &(order << :block; args.pop)).should == [[1, nil], nil]
+ order.should == [:args, :block]
end
it "evaluates the splatted arguments before the block if there are other arguments after the splat" do
diff --git a/spec/ruby/language/singleton_class_spec.rb b/spec/ruby/language/singleton_class_spec.rb
index c1fb682ea0..45e1f7f3ad 100644
--- a/spec/ruby/language/singleton_class_spec.rb
+++ b/spec/ruby/language/singleton_class_spec.rb
@@ -70,7 +70,7 @@ describe "A singleton class" do
end
it "has class String as the superclass of a String instance" do
- "blah".singleton_class.superclass.should == String
+ "blah".dup.singleton_class.superclass.should == String
end
it "doesn't have singleton class" do
@@ -291,3 +291,27 @@ describe "Instantiating a singleton class" do
}.should raise_error(TypeError)
end
end
+
+describe "Frozen properties" do
+ it "is frozen if the object it is created from is frozen" do
+ o = Object.new
+ o.freeze
+ klass = o.singleton_class
+ klass.frozen?.should == true
+ end
+
+ it "will be frozen if the object it is created from becomes frozen" do
+ o = Object.new
+ klass = o.singleton_class
+ klass.frozen?.should == false
+ o.freeze
+ klass.frozen?.should == true
+ end
+
+ it "will be unfrozen if the frozen object is cloned with freeze set to false" do
+ o = Object.new
+ o.freeze
+ o2 = o.clone(freeze: false)
+ o2.singleton_class.frozen?.should == false
+ end
+end
diff --git a/spec/ruby/language/source_encoding_spec.rb b/spec/ruby/language/source_encoding_spec.rb
index 19364fc676..7135bc0a70 100644
--- a/spec/ruby/language/source_encoding_spec.rb
+++ b/spec/ruby/language/source_encoding_spec.rb
@@ -15,7 +15,7 @@ describe "Source files" do
end
describe "encoded in UTF-16 LE without a BOM" do
- it "are parsed because empty as they contain a NUL byte before the encoding comment" do
+ it "are parsed as empty because they contain a NUL byte before the encoding comment" do
ruby_exe(fixture(__FILE__, "utf16-le-nobom.rb"), args: "2>&1").should == ""
end
end
diff --git a/spec/ruby/language/string_spec.rb b/spec/ruby/language/string_spec.rb
index ce4941569e..083a7f5db5 100644
--- a/spec/ruby/language/string_spec.rb
+++ b/spec/ruby/language/string_spec.rb
@@ -56,28 +56,6 @@ describe "Ruby character strings" do
"#\$".should == '#$'
end
- ruby_version_is ''...'2.7' do
- it "taints the result of interpolation when an interpolated value is tainted" do
- "#{"".taint}".tainted?.should be_true
-
- @ip.taint
- "#@ip".tainted?.should be_true
-
- $ip.taint
- "#$ip".tainted?.should be_true
- end
-
- it "untrusts the result of interpolation when an interpolated value is untrusted" do
- "#{"".untrust}".untrusted?.should be_true
-
- @ip.untrust
- "#@ip".untrusted?.should be_true
-
- $ip.untrust
- "#$ip".untrusted?.should be_true
- end
- end
-
it "allows using non-alnum characters as string delimiters" do
%(hey #{@ip}).should == "hey xxx"
%[hey #{@ip}].should == "hey xxx"
@@ -253,8 +231,16 @@ describe "Ruby String literals" do
ruby_exe(fixture(__FILE__, "freeze_magic_comment_across_files.rb")).chomp.should == "true"
end
- it "produce different objects for literals with the same content in different files if the other file doesn't have the comment" do
- ruby_exe(fixture(__FILE__, "freeze_magic_comment_across_files_no_comment.rb")).chomp.should == "true"
+ guard -> { !(eval("'test'").frozen? && "test".equal?("test")) } do
+ it "produces different objects for literals with the same content in different files if the other file doesn't have the comment and String literals aren't frozen by default" do
+ ruby_exe(fixture(__FILE__, "freeze_magic_comment_across_files_no_comment.rb")).chomp.should == "true"
+ end
+ end
+
+ guard -> { eval("'test'").frozen? && "test".equal?("test") } do
+ it "produces the same objects for literals with the same content in different files if the other file doesn't have the comment and String literals are frozen by default" do
+ ruby_exe(fixture(__FILE__, "freeze_magic_comment_across_files_no_comment.rb")).chomp.should == "false"
+ end
end
it "produce different objects for literals with the same content in different files if they have different encodings" do
@@ -273,12 +259,12 @@ describe "Ruby String interpolation" do
it "returns a string with the source encoding by default" do
"a#{"b"}c".encoding.should == Encoding::BINARY
- eval('"a#{"b"}c"'.force_encoding("us-ascii")).encoding.should == Encoding::US_ASCII
+ eval('"a#{"b"}c"'.dup.force_encoding("us-ascii")).encoding.should == Encoding::US_ASCII
eval("# coding: US-ASCII \n 'a#{"b"}c'").encoding.should == Encoding::US_ASCII
end
it "returns a string with the source encoding, even if the components have another encoding" do
- a = "abc".force_encoding("euc-jp")
+ a = "abc".dup.force_encoding("euc-jp")
"#{a}".encoding.should == Encoding::BINARY
b = "abc".encode("utf-8")
@@ -287,7 +273,7 @@ describe "Ruby String interpolation" do
it "raises an Encoding::CompatibilityError if the Encodings are not compatible" do
a = "\u3042"
- b = "\xff".force_encoding "binary"
+ b = "\xff".dup.force_encoding "binary"
-> { "#{a} #{b}" }.should raise_error(Encoding::CompatibilityError)
end
@@ -299,23 +285,11 @@ describe "Ruby String interpolation" do
eval(code).should_not.frozen?
end
- ruby_version_is "3.0" do
- it "creates a non-frozen String when # frozen-string-literal: true is used" do
- code = <<~'RUBY'
- # frozen-string-literal: true
- "a#{6*7}c"
- RUBY
- eval(code).should_not.frozen?
- end
- end
-
- ruby_version_is ""..."3.0" do
- it "creates a frozen String when # frozen-string-literal: true is used" do
- code = <<~'RUBY'
- # frozen-string-literal: true
- "a#{6*7}c"
- RUBY
- eval(code).should.frozen?
- end
+ it "creates a non-frozen String when # frozen-string-literal: true is used" do
+ code = <<~'RUBY'
+ # frozen-string-literal: true
+ "a#{6*7}c"
+ RUBY
+ eval(code).should_not.frozen?
end
end
diff --git a/spec/ruby/language/super_spec.rb b/spec/ruby/language/super_spec.rb
index 1ac5c5e1be..a98b3b3091 100644
--- a/spec/ruby/language/super_spec.rb
+++ b/spec/ruby/language/super_spec.rb
@@ -203,6 +203,25 @@ describe "The super keyword" do
-> { klass.new.a(:a_called) }.should raise_error(RuntimeError)
end
+ it "is able to navigate to super, when a method is defined dynamically on the singleton class" do
+ foo_class = Class.new do
+ def bar
+ "bar"
+ end
+ end
+
+ mixin_module = Module.new do
+ def bar
+ "super_" + super
+ end
+ end
+
+ foo = foo_class.new
+ foo.singleton_class.define_method(:bar, mixin_module.instance_method(:bar))
+
+ foo.bar.should == "super_bar"
+ end
+
# Rubinius ticket github#157
it "calls method_missing when a superclass method is not found" do
SuperSpecs::MM_B.new.is_a?(Hash).should == false
@@ -316,12 +335,23 @@ describe "The super keyword" do
it "without explicit arguments that are '_'" do
SuperSpecs::ZSuperWithUnderscores::B.new.m(1, 2).should == [1, 2]
+ SuperSpecs::ZSuperWithUnderscores::B.new.m3(1, 2, 3).should == [1, 2, 3]
+ SuperSpecs::ZSuperWithUnderscores::B.new.m4(1, 2, 3, 4).should == [1, 2, 3, 4]
+ SuperSpecs::ZSuperWithUnderscores::B.new.m_default(1).should == [1]
+ SuperSpecs::ZSuperWithUnderscores::B.new.m_default.should == [0]
+ SuperSpecs::ZSuperWithUnderscores::B.new.m_pre_default_rest_post(1, 2, 3, 4, 5, 6, 7).should == [1, 2, 3, 4, 5, 6, 7]
+ SuperSpecs::ZSuperWithUnderscores::B.new.m_rest(1, 2).should == [1, 2]
+ SuperSpecs::ZSuperWithUnderscores::B.new.m_kwrest(a: 1).should == {a: 1}
end
it "without explicit arguments that are '_' including any modifications" do
SuperSpecs::ZSuperWithUnderscores::B.new.m_modified(1, 2).should == [14, 2]
end
+ it "should pass method arguments when called within a closure" do
+ SuperSpecs::ZSuperInBlock::B.new.m(arg: 1).should == 1
+ end
+
describe 'when using keyword arguments' do
before :each do
@req = SuperSpecs::Keywords::RequiredArguments.new
diff --git a/spec/ruby/language/symbol_spec.rb b/spec/ruby/language/symbol_spec.rb
index d6a41d3059..0801d3223e 100644
--- a/spec/ruby/language/symbol_spec.rb
+++ b/spec/ruby/language/symbol_spec.rb
@@ -96,11 +96,13 @@ describe "A Symbol literal" do
%I{a b #{"c"}}.should == [:a, :b, :c]
end
- it "with invalid bytes raises an EncodingError at parse time" do
- ScratchPad.record []
- -> {
- eval 'ScratchPad << 1; :"\xC3"'
- }.should raise_error(EncodingError, /invalid/)
- ScratchPad.recorded.should == []
+ ruby_bug "#20280", ""..."3.4" do
+ it "raises an SyntaxError at parse time when Symbol with invalid bytes" do
+ ScratchPad.record []
+ -> {
+ eval 'ScratchPad << 1; :"\xC3"'
+ }.should raise_error(SyntaxError, /invalid symbol/)
+ ScratchPad.recorded.should == []
+ end
end
end
diff --git a/spec/ruby/language/undef_spec.rb b/spec/ruby/language/undef_spec.rb
index 4e473b803f..29dba4afb4 100644
--- a/spec/ruby/language/undef_spec.rb
+++ b/spec/ruby/language/undef_spec.rb
@@ -38,12 +38,19 @@ describe "The undef keyword" do
-> { @obj.meth(5) }.should raise_error(NoMethodError)
end
- it "with a interpolated symbol" do
+ it "with an interpolated symbol" do
@undef_class.class_eval do
undef :"#{'meth'}"
end
-> { @obj.meth(5) }.should raise_error(NoMethodError)
end
+
+ it "with an interpolated symbol when interpolated expression is not a String literal" do
+ @undef_class.class_eval do
+ undef :"#{'meth'.to_sym}"
+ end
+ -> { @obj.meth(5) }.should raise_error(NoMethodError)
+ end
end
it "allows undefining multiple methods at a time" do
diff --git a/spec/ruby/language/variables_spec.rb b/spec/ruby/language/variables_spec.rb
index 431c5aca99..01be61a9dc 100644
--- a/spec/ruby/language/variables_spec.rb
+++ b/spec/ruby/language/variables_spec.rb
@@ -1,6 +1,86 @@
require_relative '../spec_helper'
require_relative 'fixtures/variables'
+describe "Evaluation order during assignment" do
+ context "with single assignment" do
+ it "evaluates from left to right" do
+ obj = VariablesSpecs::EvalOrder.new
+ obj.instance_eval do
+ foo[0] = a
+ end
+
+ obj.order.should == ["foo", "a", "foo[]="]
+ end
+ end
+
+ context "with multiple assignment" do
+ ruby_version_is ""..."3.1" do
+ it "does not evaluate from left to right" do
+ obj = VariablesSpecs::EvalOrder.new
+
+ obj.instance_eval do
+ foo[0], bar.baz = a, b
+ end
+
+ obj.order.should == ["a", "b", "foo", "foo[]=", "bar", "bar.baz="]
+ end
+
+ it "cannot be used to swap variables with nested method calls" do
+ node = VariablesSpecs::EvalOrder.new.node
+
+ original_node = node
+ original_node_left = node.left
+ original_node_left_right = node.left.right
+
+ node.left, node.left.right, node = node.left.right, node, node.left
+ # Should evaluate in the order of:
+ # RHS: node.left.right, node, node.left
+ # LHS:
+ # * node(original_node), original_node.left = original_node_left_right
+ # * node(original_node), node.left(changed in the previous assignment to original_node_left_right),
+ # original_node_left_right.right = original_node
+ # * node = original_node_left
+
+ node.should == original_node_left
+ node.right.should_not == original_node
+ node.right.left.should_not == original_node_left_right
+ end
+ end
+
+ ruby_version_is "3.1" do
+ it "evaluates from left to right, receivers first then methods" do
+ obj = VariablesSpecs::EvalOrder.new
+ obj.instance_eval do
+ foo[0], bar.baz = a, b
+ end
+
+ obj.order.should == ["foo", "bar", "a", "b", "foo[]=", "bar.baz="]
+ end
+
+ it "can be used to swap variables with nested method calls" do
+ node = VariablesSpecs::EvalOrder.new.node
+
+ original_node = node
+ original_node_left = node.left
+ original_node_left_right = node.left.right
+
+ node.left, node.left.right, node = node.left.right, node, node.left
+ # Should evaluate in the order of:
+ # LHS: node, node.left(original_node_left)
+ # RHS: original_node_left_right, original_node, original_node_left
+ # Ops:
+ # * node(original_node), original_node.left = original_node_left_right
+ # * original_node_left.right = original_node
+ # * node = original_node_left
+
+ node.should == original_node_left
+ node.right.should == original_node
+ node.right.left.should == original_node_left_right
+ end
+ end
+ end
+end
+
describe "Multiple assignment" do
context "with a single RHS value" do
it "assigns a simple MLHS" do
@@ -287,8 +367,13 @@ describe "Multiple assignment" do
it "assigns indexed elements" do
a = []
- a[1], a[2] = 1
- a.should == [nil, 1, nil]
+ a[1], a[2] = 1, 2
+ a.should == [nil, 1, 2]
+
+ # with splatted argument
+ a = []
+ a[*[1]], a[*[2]] = 1, 2
+ a.should == [nil, 1, 2]
end
it "assigns constants" do
@@ -824,22 +909,11 @@ end
describe "Instance variables" do
context "when instance variable is uninitialized" do
- ruby_version_is ""..."3.0" do
- it "warns about accessing uninitialized instance variable" do
- obj = Object.new
- def obj.foobar; a = @a; end
-
- -> { obj.foobar }.should complain(/warning: instance variable @a not initialized/, verbose: true)
- end
- end
-
- ruby_version_is "3.0" do
- it "doesn't warn about accessing uninitialized instance variable" do
- obj = Object.new
- def obj.foobar; a = @a; end
+ it "doesn't warn about accessing uninitialized instance variable" do
+ obj = Object.new
+ def obj.foobar; a = @a; end
- -> { obj.foobar }.should_not complain(verbose: true)
- end
+ -> { obj.foobar }.should_not complain(verbose: true)
end
it "doesn't warn at lazy initialization" do
@@ -849,4 +923,22 @@ describe "Instance variables" do
-> { obj.foobar }.should_not complain(verbose: true)
end
end
+
+ describe "global variable" do
+ context "when global variable is uninitialized" do
+ it "warns about accessing uninitialized global variable in verbose mode" do
+ obj = Object.new
+ def obj.foobar; a = $specs_uninitialized_global_variable; end
+
+ -> { obj.foobar }.should complain(/warning: global variable [`']\$specs_uninitialized_global_variable' not initialized/, verbose: true)
+ end
+
+ it "doesn't warn at lazy initialization" do
+ obj = Object.new
+ def obj.foobar; $specs_uninitialized_global_variable_lazy ||= 42; end
+
+ -> { obj.foobar }.should_not complain(verbose: true)
+ end
+ end
+ end
end
diff --git a/spec/ruby/language/yield_spec.rb b/spec/ruby/language/yield_spec.rb
index 3db6d353a9..5283517636 100644
--- a/spec/ruby/language/yield_spec.rb
+++ b/spec/ruby/language/yield_spec.rb
@@ -186,30 +186,23 @@ describe "The yield call" do
end
describe "Using yield in a singleton class literal" do
- ruby_version_is "2.7"..."3.0" do
- it 'emits a deprecation warning' do
- code = <<~RUBY
- def m
- class << Object.new
- yield
- end
- end
- m { :ok }
- RUBY
+ it 'raises a SyntaxError' do
+ code = <<~RUBY
+ class << Object.new
+ yield
+ end
+ RUBY
- -> { eval(code) }.should complain(/warning: `yield' in class syntax will not be supported from Ruby 3.0/)
- end
+ -> { eval(code) }.should raise_error(SyntaxError, /Invalid yield/)
end
+end
- ruby_version_is "3.0" do
- it 'raises a SyntaxError' do
- code = <<~RUBY
- class << Object.new
- yield
- end
+describe "Using yield in non-lambda block" do
+ it 'raises a SyntaxError' do
+ code = <<~RUBY
+ 1.times { yield }
RUBY
- -> { eval(code) }.should raise_error(SyntaxError, /Invalid yield/)
- end
+ -> { eval(code) }.should raise_error(SyntaxError, /Invalid yield/)
end
end
diff --git a/spec/ruby/library/English/English_spec.rb b/spec/ruby/library/English/English_spec.rb
index 480602d5e5..4d615d1e25 100644
--- a/spec/ruby/library/English/English_spec.rb
+++ b/spec/ruby/library/English/English_spec.rb
@@ -130,13 +130,15 @@ describe "English" do
$LAST_MATCH_INFO.should == $~
end
- it "aliases $IGNORECASE to $=" do
- $VERBOSE, verbose = nil, $VERBOSE
- begin
- $IGNORECASE.should_not be_nil
- $IGNORECASE.should == $=
- ensure
- $VERBOSE = verbose
+ ruby_version_is ""..."3.3" do
+ it "aliases $IGNORECASE to $=" do
+ $VERBOSE, verbose = nil, $VERBOSE
+ begin
+ $IGNORECASE.should_not be_nil
+ $IGNORECASE.should == $=
+ ensure
+ $VERBOSE = verbose
+ end
end
end
diff --git a/spec/ruby/library/bigdecimal/add_spec.rb b/spec/ruby/library/bigdecimal/add_spec.rb
index bea8b8f764..542713011d 100644
--- a/spec/ruby/library/bigdecimal/add_spec.rb
+++ b/spec/ruby/library/bigdecimal/add_spec.rb
@@ -24,7 +24,7 @@ describe "BigDecimal#add" do
end
it "returns a + b with given precision" do
- # documentation states, that precision ist optional, but it ain't,
+ # documentation states that precision is optional, but it ain't,
@two.add(@one, 1).should == @three
@one .add(@two, 1).should == @three
@one.add(@one_minus, 1).should == @zero
@@ -60,7 +60,7 @@ describe "BigDecimal#add" do
end
# TODO:
-# http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-core/17374
+# https://blade.ruby-lang.org/ruby-core/17374
#
# This doesn't work on MRI and looks like a bug to me:
# one can use BigDecimal + Float, but not Bigdecimal.add(Float)
diff --git a/spec/ruby/library/bigdecimal/core_spec.rb b/spec/ruby/library/bigdecimal/core_spec.rb
new file mode 100644
index 0000000000..acee4dcf56
--- /dev/null
+++ b/spec/ruby/library/bigdecimal/core_spec.rb
@@ -0,0 +1,59 @@
+require_relative '../../spec_helper'
+require 'bigdecimal'
+
+describe "Core extension by bigdecimal" do
+ context "Integer#coerce" do
+ it "produces Floats" do
+ x, y = 3.coerce(BigDecimal("3.4"))
+ x.class.should == Float
+ x.should == 3.4
+ y.class.should == Float
+ y.should == 3.0
+ end
+ end
+
+ describe "Time.at passed BigDecimal" do
+ it "doesn't round input value" do
+ Time.at(BigDecimal('1.1')).to_f.should == 1.1
+ end
+ end
+
+ describe "BigDecimal#log" do
+ it "handles high-precision Rational arguments" do
+ result = BigDecimal('0.22314354220170971436137296411949880462556361100856391620766259404746040597133837784E0')
+ r = Rational(1_234_567_890, 987_654_321)
+ BigMath.log(r, 50).should == result
+ end
+ end
+
+ describe "Rational#coerce" do
+ it "returns the passed argument, self as Float, when given a Float" do
+ result = Rational(3, 4).coerce(1.0)
+ result.should == [1.0, 0.75]
+ result.first.is_a?(Float).should be_true
+ result.last.is_a?(Float).should be_true
+ end
+
+ it "returns the passed argument, self as Rational, when given an Integer" do
+ result = Rational(3, 4).coerce(10)
+ result.should == [Rational(10, 1), Rational(3, 4)]
+ result.first.is_a?(Rational).should be_true
+ result.last.is_a?(Rational).should be_true
+ end
+
+ it "coerces to Rational, when given a Complex" do
+ Rational(3, 4).coerce(Complex(5)).should == [Rational(5, 1), Rational(3, 4)]
+ Rational(12, 4).coerce(Complex(5, 1)).should == [Complex(5, 1), Complex(3)]
+ end
+
+ it "returns [argument, self] when given a Rational" do
+ Rational(3, 7).coerce(Rational(9, 2)).should == [Rational(9, 2), Rational(3, 7)]
+ end
+
+ it "raises an error when passed a BigDecimal" do
+ -> {
+ Rational(500, 3).coerce(BigDecimal('166.666666666'))
+ }.should raise_error(TypeError, /BigDecimal can't be coerced into Rational/)
+ end
+ end
+end
diff --git a/spec/ruby/library/bigdecimal/exponent_spec.rb b/spec/ruby/library/bigdecimal/exponent_spec.rb
index f63c4e5798..8877147955 100644
--- a/spec/ruby/library/bigdecimal/exponent_spec.rb
+++ b/spec/ruby/library/bigdecimal/exponent_spec.rb
@@ -18,17 +18,6 @@ describe "BigDecimal#exponent" do
BigDecimal("1234567E10").exponent.should == 17
end
-# commenting this spec out after discussion with Defiler, since it seems to be an MRI bug, not a real feature
-=begin
- platform_is wordsize: 32 do
- # TODO: write specs for both 32 and 64 bit
- it "returns 0 if exponent can't be represented as Integer" do
- BigDecimal("2E1000000000000000").exponent.should == 0
- BigDecimal("-5E-999999999999999").exponent.should == 0
- end
- end
-=end
-
it "returns 0 if self is 0" do
BigDecimal("0").exponent.should == 0
BigDecimal("+0").exponent.should == 0
diff --git a/spec/ruby/library/bigdecimal/remainder_spec.rb b/spec/ruby/library/bigdecimal/remainder_spec.rb
index 1866f665cd..bac5f37ba9 100644
--- a/spec/ruby/library/bigdecimal/remainder_spec.rb
+++ b/spec/ruby/library/bigdecimal/remainder_spec.rb
@@ -54,21 +54,23 @@ describe "BigDecimal#remainder" do
@nan.remainder(@infinity).should.nan?
end
- it "returns NaN if Infinity is involved" do
- @infinity.remainder(@infinity).should.nan?
- @infinity.remainder(@one).should.nan?
- @infinity.remainder(@mixed).should.nan?
- @infinity.remainder(@one_minus).should.nan?
- @infinity.remainder(@frac_1).should.nan?
- @one.remainder(@infinity).should.nan?
+ version_is BigDecimal::VERSION, ""..."3.1.4" do #ruby_version_is ""..."3.3" do
+ it "returns NaN if Infinity is involved" do
+ @infinity.remainder(@infinity).should.nan?
+ @infinity.remainder(@one).should.nan?
+ @infinity.remainder(@mixed).should.nan?
+ @infinity.remainder(@one_minus).should.nan?
+ @infinity.remainder(@frac_1).should.nan?
+ @one.remainder(@infinity).should.nan?
- @infinity_minus.remainder(@infinity_minus).should.nan?
- @infinity_minus.remainder(@one).should.nan?
- @one.remainder(@infinity_minus).should.nan?
- @frac_2.remainder(@infinity_minus).should.nan?
+ @infinity_minus.remainder(@infinity_minus).should.nan?
+ @infinity_minus.remainder(@one).should.nan?
+ @one.remainder(@infinity_minus).should.nan?
+ @frac_2.remainder(@infinity_minus).should.nan?
- @infinity.remainder(@infinity_minus).should.nan?
- @infinity_minus.remainder(@infinity).should.nan?
+ @infinity.remainder(@infinity_minus).should.nan?
+ @infinity_minus.remainder(@infinity).should.nan?
+ end
end
it "coerces arguments to BigDecimal if possible" do
diff --git a/spec/ruby/library/bigdecimal/round_spec.rb b/spec/ruby/library/bigdecimal/round_spec.rb
index 501a1a7342..fba52df65d 100644
--- a/spec/ruby/library/bigdecimal/round_spec.rb
+++ b/spec/ruby/library/bigdecimal/round_spec.rb
@@ -228,7 +228,15 @@ describe "BigDecimal#round" do
-> { BigDecimal('-Infinity').round(2) }.should_not raise_error(FloatDomainError)
end
- it "raise for a non-existent round mode" do
- -> { @p1_50.round(0, :nonsense) }.should raise_error(ArgumentError, "invalid rounding mode")
+ version_is BigDecimal::VERSION, ''...'3.1.3' do #ruby_version_is ''...'3.2' do
+ it 'raise for a non-existent round mode' do
+ -> { @p1_50.round(0, :nonsense) }.should raise_error(ArgumentError, "invalid rounding mode")
+ end
+ end
+
+ version_is BigDecimal::VERSION, '3.1.3' do #ruby_version_is '3.2' do
+ it 'raise for a non-existent round mode' do
+ -> { @p1_50.round(0, :nonsense) }.should raise_error(ArgumentError, "invalid rounding mode (nonsense)")
+ end
end
end
diff --git a/spec/ruby/library/bigdecimal/shared/to_int.rb b/spec/ruby/library/bigdecimal/shared/to_int.rb
index 0f16251612..44b6a3c7b2 100644
--- a/spec/ruby/library/bigdecimal/shared/to_int.rb
+++ b/spec/ruby/library/bigdecimal/shared/to_int.rb
@@ -1,6 +1,6 @@
require 'bigdecimal'
-describe :bigdecimal_to_int , shared: true do
+describe :bigdecimal_to_int, shared: true do
it "raises FloatDomainError if BigDecimal is infinity or NaN" do
-> { BigDecimal("Infinity").send(@method) }.should raise_error(FloatDomainError)
-> { BigDecimal("NaN").send(@method) }.should raise_error(FloatDomainError)
diff --git a/spec/ruby/library/bigdecimal/sqrt_spec.rb b/spec/ruby/library/bigdecimal/sqrt_spec.rb
index d149003b9f..8fd1ec0f39 100644
--- a/spec/ruby/library/bigdecimal/sqrt_spec.rb
+++ b/spec/ruby/library/bigdecimal/sqrt_spec.rb
@@ -36,8 +36,10 @@ describe "BigDecimal#sqrt" do
BigDecimal('121').sqrt(5).should be_close(11, 0.00001)
end
- it "returns square root of 0.9E-99999 with desired precision" do
- @frac_2.sqrt(1).to_s.should =~ /\A0\.3E-49999\z/i
+ platform_is_not wordsize: 32 do # fails on i686
+ it "returns square root of 0.9E-99999 with desired precision" do
+ @frac_2.sqrt(1).to_s.should =~ /\A0\.3E-49999\z/i
+ end
end
it "raises ArgumentError when no argument is given" do
diff --git a/spec/ruby/library/bigdecimal/to_r_spec.rb b/spec/ruby/library/bigdecimal/to_r_spec.rb
index 91d2b33993..c350beff08 100644
--- a/spec/ruby/library/bigdecimal/to_r_spec.rb
+++ b/spec/ruby/library/bigdecimal/to_r_spec.rb
@@ -13,4 +13,16 @@ describe "BigDecimal#to_r" do
r.denominator.should eql(1000000000000000000000000)
end
+ it "returns a Rational from a BigDecimal with an exponent" do
+ r = BigDecimal("1E2").to_r
+ r.numerator.should eql(100)
+ r.denominator.should eql(1)
+ end
+
+ it "returns a Rational from a negative BigDecimal with an exponent" do
+ r = BigDecimal("-1E2").to_r
+ r.numerator.should eql(-100)
+ r.denominator.should eql(1)
+ end
+
end
diff --git a/spec/ruby/library/bigdecimal/to_s_spec.rb b/spec/ruby/library/bigdecimal/to_s_spec.rb
index 4f1054d38e..ba9f960eb3 100644
--- a/spec/ruby/library/bigdecimal/to_s_spec.rb
+++ b/spec/ruby/library/bigdecimal/to_s_spec.rb
@@ -39,20 +39,25 @@ describe "BigDecimal#to_s" do
@bigneg.to_s("+").should_not =~ /^\+.*/
end
- it "inserts a space every n chars, if integer n is supplied" do
+ it "inserts a space every n chars to fraction part, if integer n is supplied" do
re =\
- /\A0\.314 159 265 358 979 323 846 264 338 327 950 288 419 716 939 937E1\z/i
+ /\A0\.314 159 265 358 979 323 846 264 338 327 950 288 419 716 939 937E1\z/i
@bigdec.to_s(3).should =~ re
str1 = '-123.45678 90123 45678 9'
BigDecimal("-123.45678901234567890").to_s('5F').should == str1
- BigDecimal('1000010').to_s('5F').should == "10000 10.0"
# trailing zeroes removed
BigDecimal("1.00000000000").to_s('1F').should == "1.0"
# 0 is treated as no spaces
BigDecimal("1.2345").to_s('0F').should == "1.2345"
end
+ version_is BigDecimal::VERSION, "3.1.5" do #ruby_version_is '3.3' do
+ it "inserts a space every n chars to integer part, if integer n is supplied" do
+ BigDecimal('1000010').to_s('5F').should == "10 00010.0"
+ end
+ end
+
it "can return a leading space for values > 0" do
@bigdec.to_s(" F").should =~ /\ .*/
@bigneg.to_s(" F").should_not =~ /\ .*/
@@ -83,15 +88,13 @@ describe "BigDecimal#to_s" do
end
end
- ruby_version_is "3.0" do
- it "returns a String in US-ASCII encoding when Encoding.default_internal is nil" do
- Encoding.default_internal = nil
- BigDecimal('1.23').to_s.encoding.should equal(Encoding::US_ASCII)
- end
+ it "returns a String in US-ASCII encoding when Encoding.default_internal is nil" do
+ Encoding.default_internal = nil
+ BigDecimal('1.23').to_s.encoding.should equal(Encoding::US_ASCII)
+ end
- it "returns a String in US-ASCII encoding when Encoding.default_internal is not nil" do
- Encoding.default_internal = Encoding::IBM437
- BigDecimal('1.23').to_s.encoding.should equal(Encoding::US_ASCII)
- end
+ it "returns a String in US-ASCII encoding when Encoding.default_internal is not nil" do
+ Encoding.default_internal = Encoding::IBM437
+ BigDecimal('1.23').to_s.encoding.should equal(Encoding::US_ASCII)
end
end
diff --git a/spec/ruby/library/bigmath/log_spec.rb b/spec/ruby/library/bigmath/log_spec.rb
deleted file mode 100644
index 2ffbf8b6b9..0000000000
--- a/spec/ruby/library/bigmath/log_spec.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-require_relative '../../spec_helper'
-require 'bigdecimal'
-
-describe "BigDecimal#log" do
- it "handles high-precision Rational arguments" do
- result = BigDecimal('0.22314354220170971436137296411949880462556361100856391620766259404746040597133837784E0')
- r = Rational(1_234_567_890, 987_654_321)
- BigMath.log(r, 50).should == result
- end
-end
diff --git a/spec/ruby/library/cgi/cookie/name_spec.rb b/spec/ruby/library/cgi/cookie/name_spec.rb
index 14226824c8..326a43ade3 100644
--- a/spec/ruby/library/cgi/cookie/name_spec.rb
+++ b/spec/ruby/library/cgi/cookie/name_spec.rb
@@ -6,18 +6,18 @@ describe "CGI::Cookie#name" do
cookie = CGI::Cookie.new("test-cookie")
cookie.name.should == "test-cookie"
- cookie = CGI::Cookie.new("name" => "another cookie")
- cookie.name.should == "another cookie"
+ cookie = CGI::Cookie.new("name" => "another-cookie")
+ cookie.name.should == "another-cookie"
end
end
describe "CGI::Cookie#name=" do
it "sets self's expiration date" do
cookie = CGI::Cookie.new("test-cookie")
- cookie.name = "another name"
- cookie.name.should == "another name"
+ cookie.name = "another-name"
+ cookie.name.should == "another-name"
- cookie.name = "and one more"
- cookie.name.should == "and one more"
+ cookie.name = "and-one-more"
+ cookie.name.should == "and-one-more"
end
end
diff --git a/spec/ruby/library/cgi/cookie/parse_spec.rb b/spec/ruby/library/cgi/cookie/parse_spec.rb
index 90d2c3d148..d484c7bad9 100644
--- a/spec/ruby/library/cgi/cookie/parse_spec.rb
+++ b/spec/ruby/library/cgi/cookie/parse_spec.rb
@@ -6,16 +6,16 @@ describe "CGI::Cookie.parse" do
expected = { "test-cookie" => ["one", "two", "three"] }
CGI::Cookie.parse("test-cookie=one&two&three").should == expected
- expected = { "second cookie" => ["three", "four"], "first cookie" => ["one", "two"] }
- CGI::Cookie.parse("first cookie=one&two;second cookie=three&four").should == expected
+ expected = { "second-cookie" => ["three", "four"], "first-cookie" => ["one", "two"] }
+ CGI::Cookie.parse("first-cookie=one&two;second-cookie=three&four").should == expected
end
it "does not use , for cookie separators" do
expected = {
- "first cookie" => ["one", "two"],
- "second cookie" => ["three", "four,third_cookie=five", "six"]
+ "first-cookie" => ["one", "two"],
+ "second-cookie" => ["three", "four,third_cookie=five", "six"]
}
- CGI::Cookie.parse("first cookie=one&two;second cookie=three&four,third_cookie=five&six").should == expected
+ CGI::Cookie.parse("first-cookie=one&two;second-cookie=three&four,third_cookie=five&six").should == expected
end
it "unescapes the Cookie values" do
diff --git a/spec/ruby/library/cgi/escapeURIComponent_spec.rb b/spec/ruby/library/cgi/escapeURIComponent_spec.rb
new file mode 100644
index 0000000000..f05795a2f5
--- /dev/null
+++ b/spec/ruby/library/cgi/escapeURIComponent_spec.rb
@@ -0,0 +1,57 @@
+require_relative '../../spec_helper'
+require 'cgi'
+
+ruby_version_is "3.2" do
+ describe "CGI.escapeURIComponent" do
+ it "escapes whitespace" do
+ string = "&<>\" \xE3\x82\x86\xE3\x82\x93\xE3\x82\x86\xE3\x82\x93"
+ CGI.escapeURIComponent(string).should == '%26%3C%3E%22%20%E3%82%86%E3%82%93%E3%82%86%E3%82%93'
+ end
+
+ it "does not escape with unreserved characters" do
+ string = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~"
+ CGI.escapeURIComponent(string).should == "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~"
+ end
+
+ it "supports String with invalid encoding" do
+ string = "\xC0\<\<".dup.force_encoding("UTF-8")
+ CGI.escapeURIComponent(string).should == "%C0%3C%3C"
+ end
+
+ it "processes String bytes one by one, not characters" do
+ CGI.escapeURIComponent("β").should == "%CE%B2" # "β" bytes representation is CE B2
+ end
+
+ it "raises a TypeError with nil" do
+ -> {
+ CGI.escapeURIComponent(nil)
+ }.should raise_error(TypeError, 'no implicit conversion of nil into String')
+ end
+
+ it "encodes empty string" do
+ CGI.escapeURIComponent("").should == ""
+ end
+
+ it "encodes single whitespace" do
+ CGI.escapeURIComponent(" ").should == "%20"
+ end
+
+ it "encodes double whitespace" do
+ CGI.escapeURIComponent(" ").should == "%20%20"
+ end
+
+ it "preserves encoding" do
+ string = "whatever".encode("ASCII-8BIT")
+ CGI.escapeURIComponent(string).encoding.should == Encoding::ASCII_8BIT
+ end
+
+ it "uses implicit type conversion to String" do
+ object = Object.new
+ def object.to_str
+ "a b"
+ end
+
+ CGI.escapeURIComponent(object).should == "a%20b"
+ end
+ end
+end
diff --git a/spec/ruby/library/cgi/initialize_spec.rb b/spec/ruby/library/cgi/initialize_spec.rb
index f794f157f0..61bc971d49 100644
--- a/spec/ruby/library/cgi/initialize_spec.rb
+++ b/spec/ruby/library/cgi/initialize_spec.rb
@@ -29,8 +29,8 @@ describe "CGI#initialize when passed no arguments" do
it "does not extend self with any of the other HTML modules" do
@cgi.send(:initialize)
- @cgi.should_not be_kind_of(CGI::Html3)
@cgi.should_not be_kind_of(CGI::HtmlExtension)
+ @cgi.should_not be_kind_of(CGI::Html3)
@cgi.should_not be_kind_of(CGI::Html4)
@cgi.should_not be_kind_of(CGI::Html4Tr)
@cgi.should_not be_kind_of(CGI::Html4Fr)
diff --git a/spec/ruby/library/cmath/math/acos_spec.rb b/spec/ruby/library/cmath/math/acos_spec.rb
deleted file mode 100644
index 2e9104f835..0000000000
--- a/spec/ruby/library/cmath/math/acos_spec.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'2.7' do
- require 'complex'
- require_relative 'shared/acos'
-
- describe "Math#acos" do
- it_behaves_like :complex_math_acos, :_, IncludesMath.new
-
- it "is a private instance method" do
- IncludesMath.should have_private_instance_method(:acos)
- end
- end
-
- describe "Math.acos" do
- it_behaves_like :complex_math_acos, :_, CMath
- end
-end
diff --git a/spec/ruby/library/cmath/math/acosh_spec.rb b/spec/ruby/library/cmath/math/acosh_spec.rb
deleted file mode 100644
index 809112f6c0..0000000000
--- a/spec/ruby/library/cmath/math/acosh_spec.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'2.7' do
- require 'complex'
- require_relative 'shared/acosh'
-
- describe "Math#acosh" do
- it_behaves_like :complex_math_acosh, :_, IncludesMath.new
-
- it "is a private instance method" do
- IncludesMath.should have_private_instance_method(:acosh)
- end
- end
-
- describe "Math.acosh" do
- it_behaves_like :complex_math_acosh, :_, CMath
- end
-end
diff --git a/spec/ruby/library/cmath/math/asin_spec.rb b/spec/ruby/library/cmath/math/asin_spec.rb
deleted file mode 100644
index 4ac588ebd2..0000000000
--- a/spec/ruby/library/cmath/math/asin_spec.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'2.7' do
- require 'complex'
- require_relative 'shared/asin'
-
- describe "Math#asin" do
- it_behaves_like :complex_math_asin, :_, IncludesMath.new
-
- it "is a private instance method" do
- IncludesMath.should have_private_instance_method(:asin)
- end
- end
-
- describe "Math.asin" do
- it_behaves_like :complex_math_asin, :_, CMath
- end
-end
diff --git a/spec/ruby/library/cmath/math/asinh_spec.rb b/spec/ruby/library/cmath/math/asinh_spec.rb
deleted file mode 100644
index 7d8b397a04..0000000000
--- a/spec/ruby/library/cmath/math/asinh_spec.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'2.7' do
- require 'complex'
- require_relative 'shared/asinh'
-
- describe "Math#asinh" do
- it_behaves_like :complex_math_asinh, :_, IncludesMath.new
-
- it "is a private instance method" do
- IncludesMath.should have_private_instance_method(:asinh)
- end
- end
-
- describe "Math.asinh" do
- it_behaves_like :complex_math_asinh, :_, CMath
- end
-end
diff --git a/spec/ruby/library/cmath/math/atan2_spec.rb b/spec/ruby/library/cmath/math/atan2_spec.rb
deleted file mode 100644
index 1a9b7d7607..0000000000
--- a/spec/ruby/library/cmath/math/atan2_spec.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'2.7' do
- require 'complex'
- require_relative 'shared/atan2'
-
- describe "Math#atan2" do
- it_behaves_like :complex_math_atan2, :_, IncludesMath.new
-
- it "is a private instance method" do
- IncludesMath.should have_private_instance_method(:atan2)
- end
- end
-
- describe "Math.atan2" do
- it_behaves_like :complex_math_atan2, :_, CMath
- end
-end
diff --git a/spec/ruby/library/cmath/math/atan_spec.rb b/spec/ruby/library/cmath/math/atan_spec.rb
deleted file mode 100644
index b0171081a6..0000000000
--- a/spec/ruby/library/cmath/math/atan_spec.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'2.7' do
- require 'complex'
- require_relative 'shared/atan'
-
- describe "Math#atan" do
- it_behaves_like :complex_math_atan, :_, IncludesMath.new
-
- it "is a private instance method" do
- IncludesMath.should have_private_instance_method(:atan)
- end
- end
-
- describe "Math.atan" do
- it_behaves_like :complex_math_atan, :_, CMath
- end
-end
diff --git a/spec/ruby/library/cmath/math/atanh_spec.rb b/spec/ruby/library/cmath/math/atanh_spec.rb
deleted file mode 100644
index 6b22c6c9e4..0000000000
--- a/spec/ruby/library/cmath/math/atanh_spec.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'2.7' do
- require 'complex'
- require_relative '../../../fixtures/math/common'
- require_relative '../../../shared/math/atanh'
- require_relative 'shared/atanh'
-
- describe "Math#atanh" do
- it_behaves_like :math_atanh_base, :atanh, IncludesMath.new
- it_behaves_like :complex_math_atanh_complex, :atanh, IncludesMath.new
-
- it_behaves_like :math_atanh_private, :atanh, IncludesMath.new
- end
-
- describe "Math.atanh" do
- it_behaves_like :math_atanh_base, :atanh, CMath
- it_behaves_like :complex_math_atanh_complex, :atanh, CMath
- end
-end
diff --git a/spec/ruby/library/cmath/math/cos_spec.rb b/spec/ruby/library/cmath/math/cos_spec.rb
deleted file mode 100644
index 3f097bcb3b..0000000000
--- a/spec/ruby/library/cmath/math/cos_spec.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'2.7' do
- require 'complex'
- require_relative 'shared/cos'
-
- describe "Math#cos" do
- it_behaves_like :complex_math_cos, :_, IncludesMath.new
-
- it "is a private instance method" do
- IncludesMath.should have_private_instance_method(:cos)
- end
- end
-
- describe "Math.cos" do
- it_behaves_like :complex_math_cos, :_, CMath
- end
-end
diff --git a/spec/ruby/library/cmath/math/cosh_spec.rb b/spec/ruby/library/cmath/math/cosh_spec.rb
deleted file mode 100644
index 197f899981..0000000000
--- a/spec/ruby/library/cmath/math/cosh_spec.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'2.7' do
- require 'complex'
- require_relative 'shared/cosh'
-
- describe "Math#cosh" do
- it_behaves_like :complex_math_cosh, :_, IncludesMath.new
-
- it "is a private instance method" do
- IncludesMath.should have_private_instance_method(:cosh)
- end
- end
-
- describe "Math.cosh" do
- it_behaves_like :complex_math_cosh, :_, CMath
- end
-end
diff --git a/spec/ruby/library/cmath/math/exp_spec.rb b/spec/ruby/library/cmath/math/exp_spec.rb
deleted file mode 100644
index eef2ec3129..0000000000
--- a/spec/ruby/library/cmath/math/exp_spec.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'2.7' do
- require 'complex'
- require_relative 'shared/exp'
-
- describe "Math#exp" do
- it_behaves_like :complex_math_exp, :_, IncludesMath.new
-
- it "is a private instance method" do
- IncludesMath.should have_private_instance_method(:exp)
- end
- end
-
- describe "Math.exp" do
- it_behaves_like :complex_math_exp, :_, CMath
- end
-end
diff --git a/spec/ruby/library/cmath/math/fixtures/classes.rb b/spec/ruby/library/cmath/math/fixtures/classes.rb
deleted file mode 100644
index 443c1a9ace..0000000000
--- a/spec/ruby/library/cmath/math/fixtures/classes.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-require 'cmath'
-class IncludesMath
- include CMath
-end
diff --git a/spec/ruby/library/cmath/math/log10_spec.rb b/spec/ruby/library/cmath/math/log10_spec.rb
deleted file mode 100644
index 603bbb1457..0000000000
--- a/spec/ruby/library/cmath/math/log10_spec.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'2.7' do
- require 'complex'
- require_relative 'shared/log10'
-
- describe "Math#log10" do
- it_behaves_like :complex_math_log10, :_, IncludesMath.new
-
- it "is a private instance method" do
- IncludesMath.should have_private_instance_method(:log10)
- end
- end
-
- describe "Math.log10" do
- it_behaves_like :complex_math_log10, :_, CMath
- end
-end
diff --git a/spec/ruby/library/cmath/math/log_spec.rb b/spec/ruby/library/cmath/math/log_spec.rb
deleted file mode 100644
index b4da781323..0000000000
--- a/spec/ruby/library/cmath/math/log_spec.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'2.7' do
- require 'complex'
- require_relative 'shared/log'
-
- describe "Math#log" do
- it_behaves_like :complex_math_log, :_, IncludesMath.new
-
- it "is a private instance method" do
- IncludesMath.should have_private_instance_method(:log)
- end
- end
-
- describe "Math.log" do
- it_behaves_like :complex_math_log, :_, CMath
- end
-end
diff --git a/spec/ruby/library/cmath/math/shared/acos.rb b/spec/ruby/library/cmath/math/shared/acos.rb
deleted file mode 100644
index 65637fa838..0000000000
--- a/spec/ruby/library/cmath/math/shared/acos.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-require_relative '../fixtures/classes'
-
-describe :complex_math_acos, shared: true do
- it "returns the arccosine of the passed argument" do
- @object.send(:acos, 1).should be_close(0.0, TOLERANCE)
- @object.send(:acos, 0).should be_close(1.5707963267949, TOLERANCE)
- @object.send(:acos, -1).should be_close(Math::PI,TOLERANCE)
- end
-
- it "returns the arccosine for Complex numbers" do
- @object.send(:acos, Complex(3, 4)).should be_close(Complex(0.93681246115572, -2.30550903124348), TOLERANCE)
- end
-
- it "returns the arccosine for numbers greater than 1.0 as a Complex number" do
- @object.send(:acos, 1.0001).should be_close(Complex(0.0, 0.0141420177752494), TOLERANCE)
- end
-
- it "returns the arccosine for numbers less than -1.0 as a Complex number" do
- @object.send(:acos, -1.0001).should be_close(Complex(3.14159265358979, -0.0141420177752495), TOLERANCE)
- end
-end
-
-describe :complex_math_acos_bang, shared: true do
- it "returns the arccosine of the argument" do
- @object.send(:acos!, 1).should be_close(0.0, TOLERANCE)
- @object.send(:acos!, 0).should be_close(1.5707963267949, TOLERANCE)
- @object.send(:acos!, -1).should be_close(Math::PI,TOLERANCE)
- end
-
- it "raises a TypeError when passed a Complex number" do
- -> { @object.send(:acos!, Complex(4, 5)) }.should raise_error(TypeError)
- end
-
- it "raises an Errno::EDOM for numbers greater than 1.0" do
- -> { @object.send(:acos!, 1.0001) }.should raise_error(Errno::EDOM)
- end
-
- it "raises an Errno::EDOM for numbers less than -1.0" do
- -> { @object.send(:acos!, -1.0001) }.should raise_error(Errno::EDOM)
- end
-end
diff --git a/spec/ruby/library/cmath/math/shared/acosh.rb b/spec/ruby/library/cmath/math/shared/acosh.rb
deleted file mode 100644
index 285b0b823f..0000000000
--- a/spec/ruby/library/cmath/math/shared/acosh.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-require_relative '../fixtures/classes'
-
-describe :complex_math_acosh, shared: true do
- it "returns the principle value of the inverse hyperbolic cosine of the argument" do
- @object.send(:acosh, 14.2).should be_close(3.345146999647, TOLERANCE)
- @object.send(:acosh, 1.0).should be_close(0.0, TOLERANCE)
- end
-
- it "returns the principle value of the inverse hyperbolic cosine for numbers less than 1.0 as a Complex number" do
- @object.send(:acosh, 1.0 - TOLERANCE).should be_close(Complex(0.0, 0.00774598605746135), TOLERANCE)
- @object.send(:acosh, 0).should be_close(Complex(0.0, 1.5707963267949), TOLERANCE)
- @object.send(:acosh, -1.0).should be_close(Complex(0.0, 3.14159265358979), TOLERANCE)
- end
-
- it "returns the principle value of the inverse hyperbolic cosine for Complex numbers" do
- @object.send(:acosh, Complex(3, 4))
- @object.send(:acosh, Complex(3, 4)).imaginary.should be_close(0.93681246115572, TOLERANCE)
- @object.send(:acosh, Complex(3, 4)).real.should be_close(2.305509031243477, TOLERANCE)
- end
-end
-
-describe :complex_math_acosh_bang, shared: true do
- it "returns the principle value of the inverse hyperbolic cosine of the argument" do
- @object.send(:acosh!, 14.2).should be_close(3.345146999647, TOLERANCE)
- @object.send(:acosh!, 1.0).should be_close(0.0, TOLERANCE)
- end
-
- it "raises Errno::EDOM for numbers less than 1.0" do
- -> { @object.send(:acosh!, 1.0 - TOLERANCE) }.should raise_error(Errno::EDOM)
- -> { @object.send(:acosh!, 0) }.should raise_error(Errno::EDOM)
- -> { @object.send(:acosh!, -1.0) }.should raise_error(Errno::EDOM)
- end
-
- it "raises a TypeError when passed a Complex number" do
- -> { @object.send(:acosh!, Complex(4, 5)) }.should raise_error(TypeError)
- end
-end
diff --git a/spec/ruby/library/cmath/math/shared/asin.rb b/spec/ruby/library/cmath/math/shared/asin.rb
deleted file mode 100644
index 91fed7aa06..0000000000
--- a/spec/ruby/library/cmath/math/shared/asin.rb
+++ /dev/null
@@ -1,47 +0,0 @@
-require_relative '../fixtures/classes'
-
-describe :complex_math_asin, shared: true do
- it "returns the arcsine of the argument" do
- @object.send(:asin, 1).should be_close(Math::PI/2, TOLERANCE)
- @object.send(:asin, 0).should be_close(0.0, TOLERANCE)
- @object.send(:asin, -1).should be_close(-Math::PI/2, TOLERANCE)
- @object.send(:asin, 0.25).should be_close(0.252680255142079, TOLERANCE)
- @object.send(:asin, 0.50).should be_close(0.523598775598299, TOLERANCE)
- @object.send(:asin, 0.75).should be_close(0.8480620789814816,TOLERANCE)
- end
-
- it "returns the arcsine for Complex numbers" do
- @object.send(:asin, Complex(3, 4)).should be_close(Complex(0.633983865639174, 2.30550903124347), TOLERANCE)
- end
-
- it "returns a Complex number when the argument is greater than 1.0" do
- @object.send(:asin, 1.0001).should be_close(Complex(1.5707963267949, -0.0141420177752494), TOLERANCE)
- end
-
- it "returns a Complex number when the argument is less than -1.0" do
- @object.send(:asin, -1.0001).should be_close(Complex(-1.5707963267949, 0.0141420177752494), TOLERANCE)
- end
-end
-
-describe :complex_math_asin_bang, shared: true do
- it "returns the arcsine of the argument" do
- @object.send(:asin!, 1).should be_close(Math::PI/2, TOLERANCE)
- @object.send(:asin!, 0).should be_close(0.0, TOLERANCE)
- @object.send(:asin!, -1).should be_close(-Math::PI/2, TOLERANCE)
- @object.send(:asin!, 0.25).should be_close(0.252680255142079, TOLERANCE)
- @object.send(:asin!, 0.50).should be_close(0.523598775598299, TOLERANCE)
- @object.send(:asin!, 0.75).should be_close(0.8480620789814816,TOLERANCE)
- end
-
- it "raises an Errno::EDOM if the argument is greater than 1.0" do
- -> { @object.send(:asin!, 1.0001) }.should raise_error( Errno::EDOM)
- end
-
- it "raises an Errno::EDOM if the argument is less than -1.0" do
- -> { @object.send(:asin!, -1.0001) }.should raise_error( Errno::EDOM)
- end
-
- it "raises a TypeError when passed a Complex number" do
- -> { @object.send(:asin!, Complex(4, 5)) }.should raise_error(TypeError)
- end
-end
diff --git a/spec/ruby/library/cmath/math/shared/asinh.rb b/spec/ruby/library/cmath/math/shared/asinh.rb
deleted file mode 100644
index b4ddd3a22e..0000000000
--- a/spec/ruby/library/cmath/math/shared/asinh.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-require_relative '../fixtures/classes'
-
-describe :complex_math_asinh, shared: true do
- it "returns the inverse hyperbolic sin of the argument" do
- @object.send(:asinh, 1.5).should be_close(1.19476321728711, TOLERANCE)
- @object.send(:asinh, -2.97).should be_close(-1.8089166921397, TOLERANCE)
- @object.send(:asinh, 0.0).should == 0.0
- @object.send(:asinh, -0.0).should == -0.0
- @object.send(:asinh, 1.05367e-08).should be_close(1.05367e-08, TOLERANCE)
- @object.send(:asinh, -1.05367e-08).should be_close(-1.05367e-08, TOLERANCE)
- end
-
- it "returns the inverse hyperbolic sin for Complex numbers" do
- @object.send(:asinh, Complex(3, 4)).should be_close(Complex(2.29991404087927, 0.917616853351479), TOLERANCE)
- @object.send(:asinh, Complex(3.5, -4)).should be_close(Complex(2.36263337274419, -0.843166327537659), TOLERANCE)
- end
-end
-
-describe :complex_math_asinh_bang, shared: true do
- it "returns the inverse hyperbolic sin of the argument" do
- @object.send(:asinh!, 1.5).should be_close(1.19476321728711, TOLERANCE)
- @object.send(:asinh!, -2.97).should be_close(-1.8089166921397, TOLERANCE)
- @object.send(:asinh!, 0.0).should == 0.0
- @object.send(:asinh!, -0.0).should == -0.0
- @object.send(:asinh!, 1.05367e-08).should be_close(1.05367e-08, TOLERANCE)
- @object.send(:asinh!, -1.05367e-08).should be_close(-1.05367e-08, TOLERANCE)
- end
-
- it "raises a TypeError when passed a Complex number" do
- -> { @object.send(:asinh!, Complex(4, 5)) }.should raise_error(TypeError)
- end
-end
diff --git a/spec/ruby/library/cmath/math/shared/atan.rb b/spec/ruby/library/cmath/math/shared/atan.rb
deleted file mode 100644
index 63a496e841..0000000000
--- a/spec/ruby/library/cmath/math/shared/atan.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-require_relative '../fixtures/classes'
-
-describe :complex_math_atan, shared: true do
- it "returns the arctangent of the argument" do
- @object.send(:atan, 1).should be_close(Math::PI/4, TOLERANCE)
- @object.send(:atan, 0).should be_close(0.0, TOLERANCE)
- @object.send(:atan, -1).should be_close(-Math::PI/4, TOLERANCE)
- @object.send(:atan, 0.25).should be_close(0.244978663126864, TOLERANCE)
- @object.send(:atan, 0.50).should be_close(0.463647609000806, TOLERANCE)
- @object.send(:atan, 0.75).should be_close(0.643501108793284, TOLERANCE)
- end
-
- it "returns the arctangent for Complex numbers" do
- @object.send(:atan, Complex(3, 4)).should be_close(Complex(1.44830699523146, 0.158997191679999), TOLERANCE)
- @object.send(:atan, Complex(3.5, -4)).should be_close(Complex(1.44507428165589, -0.140323762363786), TOLERANCE)
- end
-end
-
-describe :complex_math_atan_bang, shared: true do
- it "returns the arctangent of the argument" do
- @object.send(:atan!, 1).should be_close(Math::PI/4, TOLERANCE)
- @object.send(:atan!, 0).should be_close(0.0, TOLERANCE)
- @object.send(:atan!, -1).should be_close(-Math::PI/4, TOLERANCE)
- @object.send(:atan!, 0.25).should be_close(0.244978663126864, TOLERANCE)
- @object.send(:atan!, 0.50).should be_close(0.463647609000806, TOLERANCE)
- @object.send(:atan!, 0.75).should be_close(0.643501108793284, TOLERANCE)
- end
-
- it "raises a TypeError when passed a Complex number" do
- -> { @object.send(:atan!, Complex(4, 5)) }.should raise_error(TypeError)
- end
-end
diff --git a/spec/ruby/library/cmath/math/shared/atan2.rb b/spec/ruby/library/cmath/math/shared/atan2.rb
deleted file mode 100644
index 6d89423924..0000000000
--- a/spec/ruby/library/cmath/math/shared/atan2.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-require_relative '../fixtures/classes'
-
-describe :complex_math_atan2, shared: true do
- it "returns the arc tangent of the passed arguments" do
- @object.send(:atan2, 4.2, 0.3).should be_close(1.49948886200961, TOLERANCE)
- @object.send(:atan2, 0.0, 1.0).should be_close(0.0, TOLERANCE)
- @object.send(:atan2, -9.1, 3.2).should be_close(-1.23265379809025, TOLERANCE)
- @object.send(:atan2, 7.22, -3.3).should be_close(1.99950888779256, TOLERANCE)
- end
-
- it "returns the arc tangent for two Complex numbers" do
- CMath.atan2(Complex(3, 4), Complex(3.5, -4)).should be_close(Complex(-0.641757436698881, 1.10829873031207), TOLERANCE)
- end
-
- it "returns the arc tangent for Complex and real numbers" do
- CMath.atan2(Complex(3, 4), -7).should be_close(Complex(2.61576754731561, -0.494290673139855), TOLERANCE)
- CMath.atan2(5, Complex(3.5, -4)).should be_close(Complex(0.739102348493673, 0.487821626522923), TOLERANCE)
- end
-end
-
-describe :complex_math_atan2_bang, shared: true do
- it "returns the arc tangent of the passed arguments" do
- @object.send(:atan2!, 4.2, 0.3).should be_close(1.49948886200961, TOLERANCE)
- @object.send(:atan2!, 0.0, 1.0).should be_close(0.0, TOLERANCE)
- @object.send(:atan2!, -9.1, 3.2).should be_close(-1.23265379809025, TOLERANCE)
- @object.send(:atan2!, 7.22, -3.3).should be_close(1.99950888779256, TOLERANCE)
- end
-
- it "raises a TypeError when passed a Complex number" do
- -> { @object.send(:atan2!, Complex(4, 5), Complex(4, 5)) }.should raise_error(TypeError)
- -> { @object.send(:atan2!, 4, Complex(4, 5)) }.should raise_error(TypeError)
- -> { @object.send(:atan2!, Complex(4, 5), 5) }.should raise_error(TypeError)
- end
-end
diff --git a/spec/ruby/library/cmath/math/shared/atanh.rb b/spec/ruby/library/cmath/math/shared/atanh.rb
deleted file mode 100644
index ae80e61bec..0000000000
--- a/spec/ruby/library/cmath/math/shared/atanh.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-require_relative '../fixtures/classes'
-
-describe :complex_math_atanh_complex, shared: true do
- it "returns the inverse hyperbolic tangent as a Complex number for arguments greater than 1.0" do
- value = Complex(18.36840028483855, 1.5707963267948966)
- @object.send(@method, 1.0 + Float::EPSILON).should be_close(value, TOLERANCE)
-
- value = Complex(0.100335347731076, 1.5707963267949)
- @object.send(@method, 10).should be_close(value, TOLERANCE)
- end
-
- it "returns the inverse hyperbolic tangent as a Complex number for arguments greater than 1.0" do
- value = Complex(-18.36840028483855, 1.5707963267948966)
- @object.send(@method, -1.0 - Float::EPSILON).should be_close(value, TOLERANCE)
-
- value = Complex(0.100335347731076, 1.5707963267949)
- @object.send(@method, 10).should be_close(value, TOLERANCE)
- end
-
- it "returns the inverse hyperbolic tangent for Complex numbers" do
- value = Complex(0.117500907311434, 1.40992104959658)
- @object.send(@method, Complex(3, 4)).should be_close(value, TOLERANCE)
- end
-end
-
-describe :complex_math_atanh_no_complex, shared: true do
- it "raises a TypeError when passed a Complex number" do
- -> { @object.send(:atanh!, Complex(4, 5)) }.should raise_error(TypeError)
- end
-end
diff --git a/spec/ruby/library/cmath/math/shared/cos.rb b/spec/ruby/library/cmath/math/shared/cos.rb
deleted file mode 100644
index 31cb5ab1e5..0000000000
--- a/spec/ruby/library/cmath/math/shared/cos.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-require_relative '../fixtures/classes'
-
-describe :complex_math_cos, shared: true do
- it "returns the cosine of the argument expressed in radians" do
- @object.send(:cos, CMath::PI).should be_close(-1.0, TOLERANCE)
- @object.send(:cos, 0).should be_close(1.0, TOLERANCE)
- @object.send(:cos, CMath::PI/2).should be_close(0.0, TOLERANCE)
- @object.send(:cos, 3*Math::PI/2).should be_close(0.0, TOLERANCE)
- @object.send(:cos, 2*Math::PI).should be_close(1.0, TOLERANCE)
- end
-
- it "returns the cosine for Complex numbers" do
- @object.send(:cos, Complex(0, CMath::PI)).should be_close(Complex(11.5919532755215, 0.0), TOLERANCE)
- @object.send(:cos, Complex(3, 4)).should be_close(Complex(-27.0349456030742, -3.85115333481178), TOLERANCE)
- end
-end
-
-describe :complex_math_cos_bang, shared: true do
- it "returns the cosine of the argument expressed in radians" do
- @object.send(:cos!, CMath::PI).should be_close(-1.0, TOLERANCE)
- @object.send(:cos!, 0).should be_close(1.0, TOLERANCE)
- @object.send(:cos!, CMath::PI/2).should be_close(0.0, TOLERANCE)
- @object.send(:cos!, 3*Math::PI/2).should be_close(0.0, TOLERANCE)
- @object.send(:cos!, 2*Math::PI).should be_close(1.0, TOLERANCE)
- end
-
- it "raises a TypeError when passed a Complex number" do
- -> { @object.send(:cos!, Complex(3, 4)) }.should raise_error(TypeError)
- end
-end
diff --git a/spec/ruby/library/cmath/math/shared/cosh.rb b/spec/ruby/library/cmath/math/shared/cosh.rb
deleted file mode 100644
index 7cf561c985..0000000000
--- a/spec/ruby/library/cmath/math/shared/cosh.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-require_relative '../fixtures/classes'
-
-describe :complex_math_cosh, shared: true do
- it "returns the hyperbolic cosine of the passed argument" do
- @object.send(:cosh, 0.0).should == 1.0
- @object.send(:cosh, -0.0).should == 1.0
- @object.send(:cosh, 1.5).should be_close(2.35240961524325, TOLERANCE)
- @object.send(:cosh, -2.99).should be_close(9.96798496414416, TOLERANCE)
- end
-
- it "returns the hyperbolic cosine for Complex numbers" do
- @object.send(:cosh, Complex(0, CMath::PI)).should be_close(Complex(-1.0, 0.0), TOLERANCE)
- @object.send(:cosh, Complex(3, 4)).should be_close(Complex(-6.58066304055116, -7.58155274274654), TOLERANCE)
- end
-end
-
-describe :complex_math_cosh_bang, shared: true do
- it "returns the hyperbolic cosine of the passed argument" do
- @object.send(:cosh!, 0.0).should == 1.0
- @object.send(:cosh!, -0.0).should == 1.0
- @object.send(:cosh!, 1.5).should be_close(2.35240961524325, TOLERANCE)
- @object.send(:cosh!, -2.99).should be_close(9.96798496414416, TOLERANCE)
- end
-
- it "raises a TypeError when passed a Complex number" do
- -> { @object.send(:cosh!, Complex(4, 5)) }.should raise_error(TypeError)
- end
-end
diff --git a/spec/ruby/library/cmath/math/shared/exp.rb b/spec/ruby/library/cmath/math/shared/exp.rb
deleted file mode 100644
index 6715ac63d3..0000000000
--- a/spec/ruby/library/cmath/math/shared/exp.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-require_relative '../fixtures/classes'
-
-describe :complex_math_exp, shared: true do
- it "returns the base-e exponential of the passed argument" do
- @object.send(:exp, 0.0).should == 1.0
- @object.send(:exp, -0.0).should == 1.0
- @object.send(:exp, -1.8).should be_close(0.165298888221587, TOLERANCE)
- @object.send(:exp, 1.25).should be_close(3.49034295746184, TOLERANCE)
- end
-
- it "returns the base-e exponential for Complex numbers" do
- @object.send(:exp, Complex(0, 0)).should == Complex(1.0, 0.0)
- @object.send(:exp, Complex(1, 3)).should be_close(Complex(-2.69107861381979, 0.383603953541131), TOLERANCE)
- end
-end
-
-describe :complex_math_exp_bang, shared: true do
- it "returns the base-e exponential of the passed argument" do
- @object.send(:exp!, 0.0).should == 1.0
- @object.send(:exp!, -0.0).should == 1.0
- @object.send(:exp!, -1.8).should be_close(0.165298888221587, TOLERANCE)
- @object.send(:exp!, 1.25).should be_close(3.49034295746184, TOLERANCE)
- end
-
- it "raises a TypeError when passed a Complex number" do
- -> { @object.send(:exp!, Complex(1, 3)) }.should raise_error(TypeError)
- end
-end
diff --git a/spec/ruby/library/cmath/math/shared/log.rb b/spec/ruby/library/cmath/math/shared/log.rb
deleted file mode 100644
index 4b23e8c5f2..0000000000
--- a/spec/ruby/library/cmath/math/shared/log.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-require_relative '../fixtures/classes'
-
-describe :complex_math_log, shared: true do
- it "returns the natural logarithm of the passed argument" do
- @object.send(:log, 0.0001).should be_close(-9.21034037197618, TOLERANCE)
- @object.send(:log, 0.000000000001e-15).should be_close(-62.1697975108392, TOLERANCE)
- @object.send(:log, 1).should be_close(0.0, TOLERANCE)
- @object.send(:log, 10).should be_close( 2.30258509299405, TOLERANCE)
- @object.send(:log, 10e15).should be_close(36.8413614879047, TOLERANCE)
- end
-
- it "returns the natural logarithm for Complex numbers" do
- @object.send(:log, Complex(3, 4)).should be_close(Complex(1.6094379124341, 0.927295218001612), TOLERANCE)
- @object.send(:log, Complex(-3, 4)).should be_close(Complex(1.6094379124341, 2.21429743558818), TOLERANCE)
- end
-
- it "returns the natural logarithm for negative numbers as a Complex number" do
- @object.send(:log, -10).should be_close(Complex(2.30258509299405, 3.14159265358979), TOLERANCE)
- @object.send(:log, -20).should be_close(Complex(2.99573227355399, 3.14159265358979), TOLERANCE)
- end
-end
-
-describe :complex_math_log_bang, shared: true do
- it "returns the natural logarithm of the argument" do
- @object.send(:log!, 0.0001).should be_close(-9.21034037197618, TOLERANCE)
- @object.send(:log!, 0.000000000001e-15).should be_close(-62.1697975108392, TOLERANCE)
- @object.send(:log!, 1).should be_close(0.0, TOLERANCE)
- @object.send(:log!, 10).should be_close( 2.30258509299405, TOLERANCE)
- @object.send(:log!, 10e15).should be_close(36.8413614879047, TOLERANCE)
- end
-
- it "raises an Errno::EDOM if the argument is less than 0" do
- -> { @object.send(:log!, -10) }.should raise_error(Errno::EDOM)
- end
-
- it "raises a TypeError when passed a Complex number" do
- -> { @object.send(:log!, Complex(4, 5)) }.should raise_error(TypeError)
- end
-end
diff --git a/spec/ruby/library/cmath/math/shared/log10.rb b/spec/ruby/library/cmath/math/shared/log10.rb
deleted file mode 100644
index f49934d958..0000000000
--- a/spec/ruby/library/cmath/math/shared/log10.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-require_relative '../fixtures/classes'
-
-describe :complex_math_log10, shared: true do
- it "returns the base-10 logarithm of the passed argument" do
- @object.send(:log10, 0.0001).should be_close(-4.0, TOLERANCE)
- @object.send(:log10, 0.000000000001e-15).should be_close(-27.0, TOLERANCE)
- @object.send(:log10, 1).should be_close(0.0, TOLERANCE)
- @object.send(:log10, 10).should be_close(1.0, TOLERANCE)
- @object.send(:log10, 10e15).should be_close(16.0, TOLERANCE)
- end
-
- it "returns the base-10 logarithm for Complex numbers" do
- @object.send(:log10, Complex(3, 4)).should be_close(Complex(0.698970004336019, 0.402719196273373), TOLERANCE)
- @object.send(:log10, Complex(-3, 4)).should be_close(Complex(0.698970004336019, 0.961657157568468), TOLERANCE)
- end
-
- # BUG: does not work correctly, because Math#log10
- # does not check for negative values
- #it "returns the base-10 logarithm for negative numbers as a Complex number" do
- # @object.send(:log10, -10).should be_close(Complex(2.30258509299405, 3.14159265358979), TOLERANCE)
- # @object.send(:log10, -20).should be_close(Complex(2.99573227355399, 3.14159265358979), TOLERANCE)
- #end
-end
-
-describe :complex_math_log10_bang, shared: true do
- it "returns the base-10 logarithm of the argument" do
- @object.send(:log10!, 0.0001).should be_close(-4.0, TOLERANCE)
- @object.send(:log10!, 0.000000000001e-15).should be_close(-27.0, TOLERANCE)
- @object.send(:log10!, 1).should be_close(0.0, TOLERANCE)
- @object.send(:log10!, 10).should be_close(1.0, TOLERANCE)
- @object.send(:log10!, 10e15).should be_close(16.0, TOLERANCE)
- end
-
- it "raises an Errno::EDOM when the passed argument is negative" do
- -> { @object.send(:log10!, -10) }.should raise_error(Errno::EDOM)
- end
-
- it "raises a TypeError when passed a Complex number" do
- -> { @object.send(:log10!, Complex(4, 5)) }.should raise_error(TypeError)
- end
-end
diff --git a/spec/ruby/library/cmath/math/shared/sin.rb b/spec/ruby/library/cmath/math/shared/sin.rb
deleted file mode 100644
index 1cb1b29cda..0000000000
--- a/spec/ruby/library/cmath/math/shared/sin.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-require_relative '../fixtures/classes'
-
-describe :complex_math_sin, shared: true do
- it "returns the sine of the passed argument expressed in radians" do
- @object.send(:sin, CMath::PI).should be_close(0.0, TOLERANCE)
- @object.send(:sin, 0).should be_close(0.0, TOLERANCE)
- @object.send(:sin, CMath::PI/2).should be_close(1.0, TOLERANCE)
- @object.send(:sin, 3*Math::PI/2).should be_close(-1.0, TOLERANCE)
- @object.send(:sin, 2*Math::PI).should be_close(0.0, TOLERANCE)
- end
-
- it "returns the sine for Complex numbers" do
- @object.send(:sin, Complex(0, CMath::PI)).should be_close(Complex(0.0, 11.5487393572577), TOLERANCE)
- @object.send(:sin, Complex(3, 4)).should be_close(Complex(3.85373803791938, -27.0168132580039), TOLERANCE)
- end
-end
-
-describe :complex_math_sin_bang, shared: true do
- it "returns the sine of the passed argument expressed in radians" do
- @object.send(:sin!, CMath::PI).should be_close(0.0, TOLERANCE)
- @object.send(:sin!, 0).should be_close(0.0, TOLERANCE)
- @object.send(:sin!, CMath::PI/2).should be_close(1.0, TOLERANCE)
- @object.send(:sin!, 3*Math::PI/2).should be_close(-1.0, TOLERANCE)
- @object.send(:sin!, 2*Math::PI).should be_close(0.0, TOLERANCE)
- end
-
- it "raises a TypeError when passed a Complex number" do
- -> { @object.send(:sin!, Complex(4, 5)) }.should raise_error(TypeError)
- end
-end
diff --git a/spec/ruby/library/cmath/math/shared/sinh.rb b/spec/ruby/library/cmath/math/shared/sinh.rb
deleted file mode 100644
index de80a376da..0000000000
--- a/spec/ruby/library/cmath/math/shared/sinh.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-require_relative '../fixtures/classes'
-
-describe :complex_math_sinh, shared: true do
- it "returns the hyperbolic sin of the argument" do
- @object.send(:sinh, 0.0).should == 0.0
- @object.send(:sinh, -0.0).should == 0.0
- @object.send(:sinh, 1.5).should be_close(2.12927945509482, TOLERANCE)
- @object.send(:sinh, -2.8).should be_close(-8.19191835423591, TOLERANCE)
- end
-
- it "returns the hyperbolic sin for Complex numbers" do
- @object.send(:sinh, Complex(0, CMath::PI)).should be_close(Complex(-0.0, 1.22464679914735e-16), TOLERANCE)
- @object.send(:sinh, Complex(3, 4)).should be_close(Complex(-6.548120040911, -7.61923172032141), TOLERANCE)
- end
-end
-
-describe :complex_math_sinh_bang, shared: true do
- it "returns the hyperbolic sin of the argument" do
- @object.send(:sinh!, 0.0).should == 0.0
- @object.send(:sinh!, -0.0).should == 0.0
- @object.send(:sinh!, 1.5).should be_close(2.12927945509482, TOLERANCE)
- @object.send(:sinh!, -2.8).should be_close(-8.19191835423591, TOLERANCE)
- end
-
- it "raises a TypeError when passed a Complex number" do
- -> { @object.send(:sinh!, Complex(4, 5)) }.should raise_error(TypeError)
- end
-end
diff --git a/spec/ruby/library/cmath/math/shared/sqrt.rb b/spec/ruby/library/cmath/math/shared/sqrt.rb
deleted file mode 100644
index 23b1ba48ff..0000000000
--- a/spec/ruby/library/cmath/math/shared/sqrt.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-require_relative '../fixtures/classes'
-
-describe :complex_math_sqrt, shared: true do
- it "returns the square root for positive numbers" do
- @object.send(:sqrt, 4).should == 2
- @object.send(:sqrt, 19.36).should == 4.4
- end
-
- it "returns the square root for negative numbers" do
- @object.send(:sqrt, -4).should == Complex(0, 2.0)
- @object.send(:sqrt, -19.36).should == Complex(0, 4.4)
- end
-
- it "returns the square root for Complex numbers" do
- @object.send(:sqrt, Complex(4, 5)).should be_close(Complex(2.2806933416653, 1.09615788950152), TOLERANCE)
- @object.send(:sqrt, Complex(4, -5)).should be_close(Complex(2.2806933416653, -1.09615788950152), TOLERANCE)
- end
-end
-
-describe :complex_math_sqrt_bang, shared: true do
- it "returns the square root for positive numbers" do
- @object.send(:sqrt!, 4).should == 2
- @object.send(:sqrt!, 19.36).should == 4.4
- end
-
- it "raises Errno::EDOM when the passed argument is negative" do
- -> { @object.send(:sqrt!, -4) }.should raise_error(Errno::EDOM)
- -> { @object.send(:sqrt!, -19.36) }.should raise_error(Errno::EDOM)
- end
-
- it "raises a TypeError when passed a Complex number" do
- -> { @object.send(:sqrt!, Complex(4, 5)) }.should raise_error(TypeError)
- end
-end
diff --git a/spec/ruby/library/cmath/math/shared/tan.rb b/spec/ruby/library/cmath/math/shared/tan.rb
deleted file mode 100644
index 9022c84fc9..0000000000
--- a/spec/ruby/library/cmath/math/shared/tan.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-require_relative '../fixtures/classes'
-
-describe :complex_math_tan, shared: true do
- it "returns the tangent of the argument" do
- @object.send(:tan, 0.0).should == 0.0
- @object.send(:tan, -0.0).should == -0.0
- @object.send(:tan, 4.22).should be_close(1.86406937682395, TOLERANCE)
- @object.send(:tan, -9.65).should be_close(-0.229109052606441, TOLERANCE)
- end
-
- it "returns the tangent for Complex numbers" do
- @object.send(:tan, Complex(0, CMath::PI)).should be_close(Complex(0.0, 0.99627207622075), TOLERANCE)
- @object.send(:tan, Complex(3, 4)).should be_close(Complex(-0.000187346204629452, 0.999355987381473), TOLERANCE)
- end
-end
-
-describe :complex_math_tan_bang, shared: true do
- it "returns the tangent of the argument" do
- @object.send(:tan!, 0.0).should == 0.0
- @object.send(:tan!, -0.0).should == -0.0
- @object.send(:tan!, 4.22).should be_close(1.86406937682395, TOLERANCE)
- @object.send(:tan!, -9.65).should be_close(-0.229109052606441, TOLERANCE)
- end
-
- it "raises a TypeError when passed a Complex number" do
- -> { @object.send(:tan!, Complex(4, 5)) }.should raise_error(TypeError)
- end
-end
diff --git a/spec/ruby/library/cmath/math/shared/tanh.rb b/spec/ruby/library/cmath/math/shared/tanh.rb
deleted file mode 100644
index f2c9a5abb1..0000000000
--- a/spec/ruby/library/cmath/math/shared/tanh.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-require_relative '../fixtures/classes'
-
-describe :complex_math_tanh, shared: true do
- it "returns the hyperbolic tangent of the argument" do
- @object.send(:tanh, 0.0).should == 0.0
- @object.send(:tanh, -0.0).should == -0.0
- @object.send(:tanh, infinity_value).should == 1.0
- @object.send(:tanh, -infinity_value).should == -1.0
- @object.send(:tanh, 2.5).should be_close(0.98661429815143, TOLERANCE)
- @object.send(:tanh, -4.892).should be_close(-0.999887314427707, TOLERANCE)
- end
-
- it "returns the hyperbolic tangent for Complex numbers" do
- @object.send(:tanh, Complex(0, CMath::PI)).should be_close(Complex(0.0, -1.22464679914735e-16), TOLERANCE)
- @object.send(:tanh, Complex(3, 4)).should be_close(Complex(1.00070953606723, 0.00490825806749599), TOLERANCE)
- end
-end
-
-describe :complex_math_tanh_bang, shared: true do
- it "returns the hyperbolic tangent of the argument" do
- @object.send(:tanh!, 0.0).should == 0.0
- @object.send(:tanh!, -0.0).should == -0.0
- @object.send(:tanh!, infinity_value).should == 1.0
- @object.send(:tanh!, -infinity_value).should == -1.0
- @object.send(:tanh!, 2.5).should be_close(0.98661429815143, TOLERANCE)
- @object.send(:tanh!, -4.892).should be_close(-0.999887314427707, TOLERANCE)
- end
-
- it "raises a TypeError when passed a Complex number" do
- -> { @object.send(:tanh!, Complex(4, 5)) }.should raise_error(TypeError)
- end
-end
diff --git a/spec/ruby/library/cmath/math/sin_spec.rb b/spec/ruby/library/cmath/math/sin_spec.rb
deleted file mode 100644
index b7a219fbbd..0000000000
--- a/spec/ruby/library/cmath/math/sin_spec.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'2.7' do
- require 'complex'
- require_relative 'shared/sin'
-
- describe "Math#sin" do
- it_behaves_like :complex_math_sin, :_, IncludesMath.new
-
- it "is a private instance method" do
- IncludesMath.should have_private_instance_method(:sin)
- end
- end
-
- describe "Math.sin" do
- it_behaves_like :complex_math_sin, :_, CMath
- end
-end
diff --git a/spec/ruby/library/cmath/math/sinh_spec.rb b/spec/ruby/library/cmath/math/sinh_spec.rb
deleted file mode 100644
index c6e6a3baf4..0000000000
--- a/spec/ruby/library/cmath/math/sinh_spec.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'2.7' do
- require 'complex'
- require_relative 'shared/sinh'
-
- describe "Math#sinh" do
- it_behaves_like :complex_math_sinh, :_, IncludesMath.new
-
- it "is a private instance method" do
- IncludesMath.should have_private_instance_method(:sinh)
- end
- end
-
- describe "Math.sinh" do
- it_behaves_like :complex_math_sinh, :_, CMath
- end
-end
diff --git a/spec/ruby/library/cmath/math/sqrt_spec.rb b/spec/ruby/library/cmath/math/sqrt_spec.rb
deleted file mode 100644
index 421824f99c..0000000000
--- a/spec/ruby/library/cmath/math/sqrt_spec.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'2.7' do
- require 'complex'
- require_relative 'shared/sqrt'
-
- describe "Math#sqrt" do
- it_behaves_like :complex_math_sqrt, :_, IncludesMath.new
-
- it "is a private instance method" do
- IncludesMath.should have_private_instance_method(:sqrt)
- end
- end
-
- describe "Math.sqrt" do
- it_behaves_like :complex_math_sqrt, :_, CMath
- end
-end
diff --git a/spec/ruby/library/cmath/math/tan_spec.rb b/spec/ruby/library/cmath/math/tan_spec.rb
deleted file mode 100644
index e2acdd8091..0000000000
--- a/spec/ruby/library/cmath/math/tan_spec.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'2.7' do
- require 'complex'
- require_relative 'shared/tan'
-
- describe "Math#tan" do
- it_behaves_like :complex_math_tan, :_, IncludesMath.new
-
- it "is a private instance method" do
- IncludesMath.should have_private_instance_method(:tan)
- end
- end
-
- describe "Math.tan" do
- it_behaves_like :complex_math_tan, :_, CMath
- end
-end
diff --git a/spec/ruby/library/cmath/math/tanh_spec.rb b/spec/ruby/library/cmath/math/tanh_spec.rb
deleted file mode 100644
index 94da20cd51..0000000000
--- a/spec/ruby/library/cmath/math/tanh_spec.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'2.7' do
- require 'complex'
- require_relative 'shared/tanh'
-
- describe "Math#tanh" do
- it_behaves_like :complex_math_tanh, :_, IncludesMath.new
-
- it "is a private instance method" do
- IncludesMath.should have_private_instance_method(:tanh)
- end
- end
-
- describe "Math.tanh" do
- it_behaves_like :complex_math_tanh, :_, CMath
- end
-end
diff --git a/spec/ruby/library/coverage/result_spec.rb b/spec/ruby/library/coverage/result_spec.rb
index 4cc43e8462..33276778e8 100644
--- a/spec/ruby/library/coverage/result_spec.rb
+++ b/spec/ruby/library/coverage/result_spec.rb
@@ -8,10 +8,16 @@ describe 'Coverage.result' do
@eval_code_file = fixture __FILE__, 'eval_code.rb'
end
+ before :each do
+ Coverage.running?.should == false
+ end
+
after :each do
$LOADED_FEATURES.delete(@class_file)
$LOADED_FEATURES.delete(@config_file)
$LOADED_FEATURES.delete(@eval_code_file)
+
+ Coverage.result if Coverage.running?
end
it 'gives the covered files as a hash with arrays of count or nil' do
@@ -26,6 +32,41 @@ describe 'Coverage.result' do
}
end
+ ruby_version_is "3.2" do
+ it 'returns results for each mode separately when enabled :all modes' do
+ Coverage.start(:all)
+ require @class_file.chomp('.rb')
+ result = Coverage.result
+
+ result.should == {
+ @class_file => {
+ lines: [
+ nil, nil, 1, nil, nil, 1, nil, nil, 0, nil, nil, nil, nil, nil, nil, nil
+ ],
+ branches: {},
+ methods: {
+ [SomeClass, :some_method, 6, 2, 11, 5] => 0
+ }
+ }
+ }
+ end
+
+ it 'returns results for each mode separately when enabled any mode explicitly' do
+ Coverage.start(lines: true)
+ require @class_file.chomp('.rb')
+ result = Coverage.result
+
+ result.should == {
+ @class_file =>
+ {
+ lines: [
+ nil, nil, 1, nil, nil, 1, nil, nil, 0, nil, nil, nil, nil, nil, nil, nil
+ ]
+ }
+ }
+ end
+ end
+
it 'no requires/loads should give empty hash' do
Coverage.start
result = Coverage.result
@@ -75,31 +116,242 @@ describe 'Coverage.result' do
end
end
- ruby_version_is '3.1' do
- it 'second Coverage.start give exception' do
+ it 'does not include the file starting coverage since it is not tracked' do
+ require @config_file.chomp('.rb')
+ Coverage.result.should_not include(@config_file)
+ end
+
+ ruby_version_is '3.1'...'3.2' do
+ it 'returns the correct results when eval is used' do
Coverage.start
- -> {
- require @config_file.chomp('.rb')
- }.should raise_error(RuntimeError, 'coverage measurement is already setup')
- ensure
- Coverage.result
+ require @eval_code_file.chomp('.rb')
+ result = Coverage.result
+
+ result.should == {
+ @eval_code_file => [
+ 1, nil, 1, nil, 1, nil, nil, nil, nil, nil, 1
+ ]
+ }
end
end
- it 'does not include the file starting coverage since it is not tracked' do
- require @config_file.chomp('.rb')
- Coverage.result.should_not include(@config_file)
+ ruby_version_is '3.2' do
+ it 'returns the correct results when eval coverage is enabled' do
+ Coverage.supported?(:eval).should == true
+
+ Coverage.start(lines: true, eval: true)
+ require @eval_code_file.chomp('.rb')
+ result = Coverage.result
+
+ result.should == {
+ @eval_code_file => {
+ lines: [1, nil, 1, nil, 1, 1, nil, nil, nil, nil, 1]
+ }
+ }
+ end
+
+ it 'returns the correct results when eval coverage is disabled' do
+ Coverage.supported?(:eval).should == true
+
+ Coverage.start(lines: true, eval: false)
+ require @eval_code_file.chomp('.rb')
+ result = Coverage.result
+
+ result.should == {
+ @eval_code_file => {
+ lines: [1, nil, 1, nil, 1, nil, nil, nil, nil, nil, 1]
+ }
+ }
+ end
end
- it 'returns the correct results when eval is used' do
+ it "disables coverage measurement when stop option is not specified" do
Coverage.start
- require @eval_code_file.chomp('.rb')
- result = Coverage.result
+ require @class_file.chomp('.rb')
+
+ Coverage.result
+ Coverage.running?.should == false
+ end
+
+ it "disables coverage measurement when stop: true option is specified" do
+ Coverage.start
+ require @class_file.chomp('.rb')
+
+ -> {
+ Coverage.result(stop: true)
+ }.should complain(/warning: stop implies clear/)
+
+ Coverage.running?.should == false
+ end
+
+ it "does not disable coverage measurement when stop: false option is specified" do
+ Coverage.start
+ require @class_file.chomp('.rb')
+
+ Coverage.result(stop: false)
+ Coverage.running?.should == true
+ end
+
+ it "does not disable coverage measurement when stop option is not specified but clear: true specified" do
+ Coverage.start
+ require @class_file.chomp('.rb')
+
+ Coverage.result(clear: true)
+ Coverage.running?.should == true
+ end
+
+ it "does not disable coverage measurement when stop option is not specified but clear: false specified" do
+ Coverage.start
+ require @class_file.chomp('.rb')
+
+ Coverage.result(clear: false)
+ Coverage.running?.should == true
+ end
+
+ it "disables coverage measurement when stop: true and clear: true specified" do
+ Coverage.start
+ require @class_file.chomp('.rb')
+
+ Coverage.result(stop: true, clear: true)
+ Coverage.running?.should == false
+ end
+
+ it "disables coverage measurement when stop: true and clear: false specified" do
+ Coverage.start
+ require @class_file.chomp('.rb')
+
+ -> {
+ Coverage.result(stop: true, clear: false)
+ }.should complain(/warning: stop implies clear/)
+
+ Coverage.running?.should == false
+ end
+
+ it "does not disable coverage measurement when stop: false and clear: true specified" do
+ Coverage.start
+ require @class_file.chomp('.rb')
+
+ Coverage.result(stop: false, clear: true)
+ Coverage.running?.should == true
+ end
+
+ it "does not disable coverage measurement when stop: false and clear: false specified" do
+ Coverage.start
+ require @class_file.chomp('.rb')
+ Coverage.result(stop: false, clear: false)
+ Coverage.running?.should == true
+ end
+
+ it "resets counters (remove them) when stop: true specified but clear option is not specified" do
+ Coverage.start
+ require @class_file.chomp('.rb')
+
+ -> {
+ Coverage.result(stop: true) # clears counters
+ }.should complain(/warning: stop implies clear/)
+
+ Coverage.start
+ Coverage.peek_result.should == {}
+ end
+
+ it "resets counters (remove them) when stop: true and clear: true specified" do
+ Coverage.start
+ require @class_file.chomp('.rb')
+
+ Coverage.result(stop: true, clear: true) # clears counters
+
+ Coverage.start
+ Coverage.peek_result.should == {}
+ end
+
+ it "resets counters (remove them) when stop: true and clear: false specified" do
+ Coverage.start
+ require @class_file.chomp('.rb')
+
+ -> {
+ Coverage.result(stop: true, clear: false) # clears counters
+ }.should complain(/warning: stop implies clear/)
+
+ Coverage.start
+ Coverage.peek_result.should == {}
+ end
+
+ it "resets counters (remove them) when both stop and clear options are not specified" do
+ Coverage.start
+ require @class_file.chomp('.rb')
+
+ Coverage.result # clears counters
+
+ Coverage.start
+ Coverage.peek_result.should == {}
+ end
+
+ it "clears counters (sets 0 values) when stop is not specified but clear: true specified" do
+ Coverage.start
+ require @class_file.chomp('.rb')
+
+ Coverage.result(clear: true) # clears counters
+
+ Coverage.peek_result.should == {
+ @class_file => [
+ nil, nil, 0, nil, nil, 0, nil, nil, 0, nil, nil, nil, nil, nil, nil, nil
+ ]
+ }
+ end
+
+ it "does not clear counters when stop is not specified but clear: false specified" do
+ Coverage.start
+ require @class_file.chomp('.rb')
+
+ result = Coverage.result(clear: false) # doesn't clear counters
result.should == {
- @eval_code_file => [
- 1, nil, 1, nil, 1, nil, nil, nil, nil, nil, 1
- ]
+ @class_file => [
+ nil, nil, 1, nil, nil, 1, nil, nil, 0, nil, nil, nil, nil, nil, nil, nil
+ ]
+ }
+
+ Coverage.peek_result.should == result
+ end
+
+ it "does not clear counters when stop: false and clear is not specified" do
+ Coverage.start
+ require @class_file.chomp('.rb')
+
+ result = Coverage.result(stop: false) # doesn't clear counters
+ result.should == {
+ @class_file => [
+ nil, nil, 1, nil, nil, 1, nil, nil, 0, nil, nil, nil, nil, nil, nil, nil
+ ]
+ }
+
+ Coverage.peek_result.should == result
+ end
+
+ it "clears counters (sets 0 values) when stop: false and clear: true specified" do
+ Coverage.start
+ require @class_file.chomp('.rb')
+
+ Coverage.result(stop: false, clear: true) # clears counters
+
+ Coverage.peek_result.should == {
+ @class_file => [
+ nil, nil, 0, nil, nil, 0, nil, nil, 0, nil, nil, nil, nil, nil, nil, nil
+ ]
+ }
+ end
+
+ it "does not clear counters when stop: false and clear: false specified" do
+ Coverage.start
+ require @class_file.chomp('.rb')
+
+ result = Coverage.result(stop: false, clear: false) # doesn't clear counters
+ result.should == {
+ @class_file => [
+ nil, nil, 1, nil, nil, 1, nil, nil, 0, nil, nil, nil, nil, nil, nil, nil
+ ]
}
+
+ Coverage.peek_result.should == result
end
end
diff --git a/spec/ruby/library/coverage/running_spec.rb b/spec/ruby/library/coverage/running_spec.rb
new file mode 100644
index 0000000000..e9cc7ada5a
--- /dev/null
+++ b/spec/ruby/library/coverage/running_spec.rb
@@ -0,0 +1,20 @@
+require_relative '../../spec_helper'
+require 'coverage'
+
+describe 'Coverage.running?' do
+ it "returns false if coverage is not started" do
+ Coverage.running?.should == false
+ end
+
+ it "returns true if coverage is started" do
+ Coverage.start
+ Coverage.running?.should == true
+ Coverage.result
+ end
+
+ it "returns false if coverage was started and stopped" do
+ Coverage.start
+ Coverage.result
+ Coverage.running?.should == false
+ end
+end
diff --git a/spec/ruby/library/coverage/start_spec.rb b/spec/ruby/library/coverage/start_spec.rb
index ddfad8b47c..7fccf2d5cf 100644
--- a/spec/ruby/library/coverage/start_spec.rb
+++ b/spec/ruby/library/coverage/start_spec.rb
@@ -2,5 +2,90 @@ require_relative '../../spec_helper'
require 'coverage'
describe 'Coverage.start' do
- it 'needs to be reviewed for spec completeness'
+ before :each do
+ Coverage.should_not.running?
+ end
+
+ after :each do
+ Coverage.result(stop: true, clear: true) if Coverage.running?
+ end
+
+ it "enables the coverage measurement" do
+ Coverage.start
+ Coverage.should.running?
+ end
+
+ it "returns nil" do
+ Coverage.start.should == nil
+ end
+
+ ruby_version_is '3.1' do
+ it 'raises error when repeated Coverage.start call happens' do
+ Coverage.start
+
+ -> {
+ Coverage.start
+ }.should raise_error(RuntimeError, 'coverage measurement is already setup')
+ end
+ end
+
+ ruby_version_is '3.2' do
+ it "accepts :all optional argument" do
+ Coverage.start(:all)
+ Coverage.should.running?
+ end
+
+ it "accepts lines: optional keyword argument" do
+ Coverage.start(lines: true)
+ Coverage.should.running?
+ end
+
+ it "accepts branches: optional keyword argument" do
+ Coverage.start(branches: true)
+ Coverage.should.running?
+ end
+
+ it "accepts methods: optional keyword argument" do
+ Coverage.start(methods: true)
+ Coverage.should.running?
+ end
+
+ it "accepts eval: optional keyword argument" do
+ Coverage.start(eval: true)
+ Coverage.should.running?
+ end
+
+ it "accepts oneshot_lines: optional keyword argument" do
+ Coverage.start(oneshot_lines: true)
+ Coverage.should.running?
+ end
+
+ it "ignores unknown keyword arguments" do
+ Coverage.start(foo: true)
+ Coverage.should.running?
+ end
+
+ it "expects a Hash if not passed :all" do
+ -> {
+ Coverage.start(42)
+ }.should raise_error(TypeError, "no implicit conversion of Integer into Hash")
+ end
+
+ it "does not accept both lines: and oneshot_lines: keyword arguments" do
+ -> {
+ Coverage.start(lines: true, oneshot_lines: true)
+ }.should raise_error(RuntimeError, "cannot enable lines and oneshot_lines simultaneously")
+ end
+
+ it "enables the coverage measurement if passed options with `false` value" do
+ Coverage.start(lines: false, branches: false, methods: false, eval: false, oneshot_lines: false)
+ Coverage.should.running?
+ end
+
+ it "measures coverage within eval" do
+ Coverage.start(lines: true, eval: true)
+ eval("Object.new\n"*3, binding, "test.rb", 1)
+ Coverage.result["test.rb"].should == {lines: [1, 1, 1]}
+ end
+ end
end
diff --git a/spec/ruby/library/coverage/supported_spec.rb b/spec/ruby/library/coverage/supported_spec.rb
new file mode 100644
index 0000000000..78b3784ee0
--- /dev/null
+++ b/spec/ruby/library/coverage/supported_spec.rb
@@ -0,0 +1,32 @@
+require_relative '../../spec_helper'
+require 'coverage'
+
+describe "Coverage.supported?" do
+ ruby_version_is "3.2" do
+ it "returns true or false if coverage measurement is supported for the given mode" do
+ [true, false].should.include?(Coverage.supported?(:lines))
+ [true, false].should.include?(Coverage.supported?(:branches))
+ [true, false].should.include?(Coverage.supported?(:methods))
+ [true, false].should.include?(Coverage.supported?(:eval))
+ end
+
+ it "returns false for not existing modes" do
+ Coverage.supported?(:foo).should == false
+ Coverage.supported?(:bar).should == false
+ end
+
+ it "raise TypeError if argument is not Symbol" do
+ -> {
+ Coverage.supported?("lines")
+ }.should raise_error(TypeError, "wrong argument type String (expected Symbol)")
+
+ -> {
+ Coverage.supported?([])
+ }.should raise_error(TypeError, "wrong argument type Array (expected Symbol)")
+
+ -> {
+ Coverage.supported?(1)
+ }.should raise_error(TypeError, "wrong argument type Integer (expected Symbol)")
+ end
+ end
+end
diff --git a/spec/ruby/library/csv/generate_spec.rb b/spec/ruby/library/csv/generate_spec.rb
index 0a1e3d9604..b45e2eb95b 100644
--- a/spec/ruby/library/csv/generate_spec.rb
+++ b/spec/ruby/library/csv/generate_spec.rb
@@ -21,7 +21,7 @@ describe "CSV.generate" do
end
it "appends and returns the argument itself" do
- str = ""
+ str = +""
csv_str = CSV.generate(str) do |csv|
csv.add_row [1, 2, 3]
csv << [4, 5, 6]
diff --git a/spec/ruby/library/date/civil_spec.rb b/spec/ruby/library/date/civil_spec.rb
index f3537c2f84..1c780fce56 100644
--- a/spec/ruby/library/date/civil_spec.rb
+++ b/spec/ruby/library/date/civil_spec.rb
@@ -2,11 +2,6 @@ require_relative '../../spec_helper'
require_relative 'shared/civil'
require 'date'
-describe "Date#civil" do
- it_behaves_like :date_civil, :civil
-end
-
-
describe "Date.civil" do
- it "needs to be reviewed for spec completeness"
+ it_behaves_like :date_civil, :civil
end
diff --git a/spec/ruby/library/date/deconstruct_keys_spec.rb b/spec/ruby/library/date/deconstruct_keys_spec.rb
new file mode 100644
index 0000000000..92579e35c7
--- /dev/null
+++ b/spec/ruby/library/date/deconstruct_keys_spec.rb
@@ -0,0 +1,44 @@
+require_relative '../../spec_helper'
+require 'date'
+date_version = defined?(Date::VERSION) ? Date::VERSION : '3.1.0'
+
+version_is date_version, "3.3" do #ruby_version_is "3.2" do
+ describe "Date#deconstruct_keys" do
+ it "returns whole hash for nil as an argument" do
+ d = Date.new(2022, 10, 5)
+ d.deconstruct_keys(nil).should == { year: 2022, month: 10, day: 5, yday: 278, wday: 3 }
+ end
+
+ it "returns only specified keys" do
+ d = Date.new(2022, 10, 5)
+ d.deconstruct_keys([:year, :month]).should == { year: 2022, month: 10 }
+ end
+
+ it "requires one argument" do
+ -> {
+ Date.new(2022, 10, 5).deconstruct_keys
+ }.should raise_error(ArgumentError)
+ end
+
+ it "it raises error when argument is neither nil nor array" do
+ d = Date.new(2022, 10, 5)
+
+ -> { d.deconstruct_keys(1) }.should raise_error(TypeError, "wrong argument type Integer (expected Array or nil)")
+ -> { d.deconstruct_keys("asd") }.should raise_error(TypeError, "wrong argument type String (expected Array or nil)")
+ -> { d.deconstruct_keys(:x) }.should raise_error(TypeError, "wrong argument type Symbol (expected Array or nil)")
+ -> { d.deconstruct_keys({}) }.should raise_error(TypeError, "wrong argument type Hash (expected Array or nil)")
+ end
+
+ it "returns {} when passed []" do
+ Date.new(2022, 10, 5).deconstruct_keys([]).should == {}
+ end
+
+ it "ignores non-Symbol keys" do
+ Date.new(2022, 10, 5).deconstruct_keys(['year', []]).should == {}
+ end
+
+ it "ignores not existing Symbol keys" do
+ Date.new(2022, 10, 5).deconstruct_keys([:year, :a]).should == { year: 2022 }
+ end
+ end
+end
diff --git a/spec/ruby/library/date/iso8601_spec.rb b/spec/ruby/library/date/iso8601_spec.rb
index 2c698db514..af66845a6b 100644
--- a/spec/ruby/library/date/iso8601_spec.rb
+++ b/spec/ruby/library/date/iso8601_spec.rb
@@ -17,18 +17,21 @@ describe "Date.iso8601" do
d.should == Date.civil(-4712, 1, 1)
end
- it "parses a Symbol into a Date object" do
- d = Date.iso8601(:'2015-10-15')
- d.should == Date.civil(2015, 10, 15)
- end
-
it "parses a StringSubclass into a Date object" do
d = Date.iso8601(Class.new(String).new("-4712-01-01"))
d.should == Date.civil(-4712, 1, 1)
end
- it "raises an ArgumentError when passed a Symbol without a valid Date" do
- -> { Date.iso8601(:test) }.should raise_error(ArgumentError)
+ it "raises a Date::Error if the argument is a invalid Date" do
+ -> {
+ Date.iso8601('invalid')
+ }.should raise_error(Date::Error, "invalid date")
+ end
+
+ it "raises a Date::Error when passed a nil" do
+ -> {
+ Date.iso8601(nil)
+ }.should raise_error(Date::Error, "invalid date")
end
it "raises a TypeError when passed an Object" do
@@ -41,4 +44,13 @@ describe "Date._iso8601" do
h = Date._iso8601('invalid')
h.should == {}
end
+
+ it "returns an empty hash if the argument is nil" do
+ h = Date._iso8601(nil)
+ h.should == {}
+ end
+
+ it "raises a TypeError when passed an Object" do
+ -> { Date._iso8601(Object.new) }.should raise_error(TypeError)
+ end
end
diff --git a/spec/ruby/library/date/new_spec.rb b/spec/ruby/library/date/new_spec.rb
index 18120118c0..cb64cabce6 100644
--- a/spec/ruby/library/date/new_spec.rb
+++ b/spec/ruby/library/date/new_spec.rb
@@ -1,7 +1,6 @@
require 'date'
require_relative '../../spec_helper'
require_relative 'shared/civil'
-require_relative 'shared/new_bang'
describe "Date.new" do
it_behaves_like :date_civil, :new
diff --git a/spec/ruby/library/date/parse_spec.rb b/spec/ruby/library/date/parse_spec.rb
index ef72ba3f4e..5ef4f6e9b5 100644
--- a/spec/ruby/library/date/parse_spec.rb
+++ b/spec/ruby/library/date/parse_spec.rb
@@ -67,7 +67,7 @@ describe "Date#parse" do
it "raises a TypeError trying to parse non-String-like object" do
-> { Date.parse(1) }.should raise_error(TypeError)
- -> { Date.parse(:invalid) }.should raise_error(TypeError)
+ -> { Date.parse([]) }.should raise_error(TypeError)
end
it "coerces using to_str" do
@@ -93,7 +93,7 @@ describe "Date#parse with '.' separator" do
@sep = '.'
end
- it_should_behave_like "date_parse"
+ it_should_behave_like :date_parse
end
describe "Date#parse with '/' separator" do
@@ -101,7 +101,7 @@ describe "Date#parse with '/' separator" do
@sep = '/'
end
- it_should_behave_like "date_parse"
+ it_should_behave_like :date_parse
end
describe "Date#parse with ' ' separator" do
@@ -109,7 +109,7 @@ describe "Date#parse with ' ' separator" do
@sep = ' '
end
- it_should_behave_like "date_parse"
+ it_should_behave_like :date_parse
end
describe "Date#parse with '/' separator US-style" do
@@ -117,7 +117,7 @@ describe "Date#parse with '/' separator US-style" do
@sep = '/'
end
- it_should_behave_like "date_parse_us"
+ it_should_behave_like :date_parse_us
end
describe "Date#parse with '-' separator EU-style" do
@@ -125,7 +125,7 @@ describe "Date#parse with '-' separator EU-style" do
@sep = '-'
end
- it_should_behave_like "date_parse_eu"
+ it_should_behave_like :date_parse_eu
end
describe "Date#parse(.)" do
diff --git a/spec/ruby/library/date/shared/new_bang.rb b/spec/ruby/library/date/shared/new_bang.rb
deleted file mode 100644
index 90f1b432f0..0000000000
--- a/spec/ruby/library/date/shared/new_bang.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-describe :date_new_bang, shared: true do
-
- it "returns a new Date object set to Astronomical Julian Day 0 if no arguments passed" do
- d = Date.send(@method)
- d.ajd.should == 0
- end
-
- it "accepts astronomical julian day number, offset as a fraction of a day and returns a new Date object" do
- d = Date.send(@method, 10, 0.5)
- d.ajd.should == 10
- d.jd.should == 11
- end
-
-end
diff --git a/spec/ruby/library/date/shared/parse.rb b/spec/ruby/library/date/shared/parse.rb
index 1015285e04..40af908386 100644
--- a/spec/ruby/library/date/shared/parse.rb
+++ b/spec/ruby/library/date/shared/parse.rb
@@ -13,7 +13,7 @@ describe :date_parse, shared: true do
d.day.should == 23
end
- it "can parse a 'mmm DD YYYY' string into a Date object" do
+ it "can parse a 'DD mmm YYYY' string into a Date object" do
d = Date.parse("23#{@sep}feb#{@sep}2008")
d.year.should == 2008
d.month.should == 2
@@ -42,7 +42,7 @@ describe :date_parse, shared: true do
d.should == Date.civil(2005, 11, 5)
end
- it "can parse a year, day and month name into a Date object" do
+ it "can parse a day, month name and year into a Date object" do
d = Date.parse("5th#{@sep}november#{@sep}2005")
d.should == Date.civil(2005, 11, 5)
end
diff --git a/spec/ruby/library/date/shared/parse_eu.rb b/spec/ruby/library/date/shared/parse_eu.rb
index ecb15e3c0e..3819524a57 100644
--- a/spec/ruby/library/date/shared/parse_eu.rb
+++ b/spec/ruby/library/date/shared/parse_eu.rb
@@ -7,28 +7,28 @@ describe :date_parse_eu, shared: true do
d.day.should == 1
end
- it "can parse a MM-DD-YYYY string into a Date object" do
+ it "can parse a DD-MM-YYYY string into a Date object" do
d = Date.parse("10#{@sep}01#{@sep}2007")
d.year.should == 2007
d.month.should == 1
d.day.should == 10
end
- it "can parse a MM-DD-YY string into a Date object" do
+ it "can parse a YY-MM-DD string into a Date object" do
d = Date.parse("10#{@sep}01#{@sep}07")
d.year.should == 2010
d.month.should == 1
d.day.should == 7
end
- it "can parse a MM-DD-YY string into a Date object NOT using the year digits as 20XX" do
+ it "can parse a YY-MM-DD string into a Date object NOT using the year digits as 20XX" do
d = Date.parse("10#{@sep}01#{@sep}07", false)
d.year.should == 10
d.month.should == 1
d.day.should == 7
end
- it "can parse a MM-DD-YY string into a Date object using the year digits as 20XX" do
+ it "can parse a YY-MM-DD string into a Date object using the year digits as 20XX" do
d = Date.parse("10#{@sep}01#{@sep}07", true)
d.year.should == 2010
d.month.should == 1
diff --git a/spec/ruby/library/date/shared/parse_us.rb b/spec/ruby/library/date/shared/parse_us.rb
index 7be62b1af1..17e2fc96c1 100644
--- a/spec/ruby/library/date/shared/parse_us.rb
+++ b/spec/ruby/library/date/shared/parse_us.rb
@@ -6,28 +6,28 @@ describe :date_parse_us, shared: true do
d.day.should == 1
end
- it "parses a MM#{@sep}DD#{@sep}YYYY string into a Date object" do
+ it "parses a DD#{@sep}MM#{@sep}YYYY string into a Date object" do
d = Date.parse("10#{@sep}01#{@sep}2007")
d.year.should == 2007
d.month.should == 1
d.day.should == 10
end
- it "parses a MM#{@sep}DD#{@sep}YY string into a Date object" do
+ it "parses a YY#{@sep}MM#{@sep}DD string into a Date object" do
d = Date.parse("10#{@sep}01#{@sep}07")
d.year.should == 2010
d.month.should == 1
d.day.should == 7
end
- it "parses a MM#{@sep}DD#{@sep}YY string into a Date object NOT using the year digits as 20XX" do
+ it "parses a YY#{@sep}MM#{@sep}DD string into a Date object NOT using the year digits as 20XX" do
d = Date.parse("10#{@sep}01#{@sep}07", false)
d.year.should == 10
d.month.should == 1
d.day.should == 7
end
- it "parses a MM#{@sep}DD#{@sep}YY string into a Date object using the year digits as 20XX" do
+ it "parses a YY#{@sep}MM#{@sep}DD string into a Date object using the year digits as 20XX" do
d = Date.parse("10#{@sep}01#{@sep}07", true)
d.year.should == 2010
d.month.should == 1
diff --git a/spec/ruby/library/date/shared/valid_jd.rb b/spec/ruby/library/date/shared/valid_jd.rb
index f6ca3f579d..e474dfb450 100644
--- a/spec/ruby/library/date/shared/valid_jd.rb
+++ b/spec/ruby/library/date/shared/valid_jd.rb
@@ -10,23 +10,11 @@ describe :date_valid_jd?, shared: true do
Date.send(@method, nil).should be_false
end
- ruby_version_is ''...'2.7' do
- it "returns true if passed symbol" do
- Date.send(@method, :number).should be_true
- end
-
- it "returns true if passed false" do
- Date.send(@method, false).should be_true
- end
+ it "returns false if passed symbol" do
+ Date.send(@method, :number).should be_false
end
- ruby_version_is '2.7' do
- it "returns false if passed symbol" do
- Date.send(@method, :number).should be_false
- end
-
- it "returns false if passed false" do
- Date.send(@method, false).should be_false
- end
+ it "returns false if passed false" do
+ Date.send(@method, false).should be_false
end
end
diff --git a/spec/ruby/library/date/strftime_spec.rb b/spec/ruby/library/date/strftime_spec.rb
index 8b1ebe061c..b5232a2073 100644
--- a/spec/ruby/library/date/strftime_spec.rb
+++ b/spec/ruby/library/date/strftime_spec.rb
@@ -1,5 +1,7 @@
+require_relative "../../spec_helper"
require 'date'
require_relative '../../shared/time/strftime_for_date'
+date_version = defined?(Date::VERSION) ? Date::VERSION : '3.1.0'
describe "Date#strftime" do
before :all do
@@ -22,14 +24,14 @@ describe "Date#strftime" do
end
# %v is %e-%b-%Y for Date/DateTime
- ruby_version_is ""..."3.1" do
+ version_is date_version, ""..."3.2" do #ruby_version_is ""..."3.1" do
it "should be able to show the commercial week" do
@date.strftime("%v").should == " 9-Apr-2000"
@date.strftime("%v").should == @date.strftime('%e-%b-%Y')
end
end
- ruby_version_is "3.1" do
+ version_is date_version, "3.2" do #ruby_version_is "3.1" do
it "should be able to show the commercial week" do
@date.strftime("%v").should == " 9-APR-2000"
@date.strftime("%v").should != @date.strftime('%e-%b-%Y')
diff --git a/spec/ruby/library/datetime/deconstruct_keys_spec.rb b/spec/ruby/library/datetime/deconstruct_keys_spec.rb
new file mode 100644
index 0000000000..77ceaa51c4
--- /dev/null
+++ b/spec/ruby/library/datetime/deconstruct_keys_spec.rb
@@ -0,0 +1,46 @@
+require_relative '../../spec_helper'
+require 'date'
+date_version = defined?(Date::VERSION) ? Date::VERSION : '3.1.0'
+
+version_is date_version, "3.3" do #ruby_version_is "3.2" do
+ describe "DateTime#deconstruct_keys" do
+ it "returns whole hash for nil as an argument" do
+ d = DateTime.new(2022, 10, 5, 13, 30)
+ res = { year: 2022, month: 10, day: 5, yday: 278, wday: 3, hour: 13,
+ min: 30, sec: 0, sec_fraction: (0/1), zone: "+00:00" }
+ d.deconstruct_keys(nil).should == res
+ end
+
+ it "returns only specified keys" do
+ d = DateTime.new(2022, 10, 5, 13, 39)
+ d.deconstruct_keys([:zone, :hour]).should == { zone: "+00:00", hour: 13 }
+ end
+
+ it "requires one argument" do
+ -> {
+ DateTime.new(2022, 10, 5, 13, 30).deconstruct_keys
+ }.should raise_error(ArgumentError)
+ end
+
+ it "it raises error when argument is neither nil nor array" do
+ d = DateTime.new(2022, 10, 5, 13, 30)
+
+ -> { d.deconstruct_keys(1) }.should raise_error(TypeError, "wrong argument type Integer (expected Array or nil)")
+ -> { d.deconstruct_keys("asd") }.should raise_error(TypeError, "wrong argument type String (expected Array or nil)")
+ -> { d.deconstruct_keys(:x) }.should raise_error(TypeError, "wrong argument type Symbol (expected Array or nil)")
+ -> { d.deconstruct_keys({}) }.should raise_error(TypeError, "wrong argument type Hash (expected Array or nil)")
+ end
+
+ it "returns {} when passed []" do
+ DateTime.new(2022, 10, 5, 13, 30).deconstruct_keys([]).should == {}
+ end
+
+ it "ignores non-Symbol keys" do
+ DateTime.new(2022, 10, 5, 13, 30).deconstruct_keys(['year', []]).should == {}
+ end
+
+ it "ignores not existing Symbol keys" do
+ DateTime.new(2022, 10, 5, 13, 30).deconstruct_keys([:year, :a]).should == { year: 2022 }
+ end
+ end
+end
diff --git a/spec/ruby/library/datetime/rfc2822_spec.rb b/spec/ruby/library/datetime/rfc2822_spec.rb
index 70bfca60b4..83f7fa8d5b 100644
--- a/spec/ruby/library/datetime/rfc2822_spec.rb
+++ b/spec/ruby/library/datetime/rfc2822_spec.rb
@@ -3,4 +3,8 @@ require 'date'
describe "DateTime.rfc2822" do
it "needs to be reviewed for spec completeness"
+
+ it "raises DateError if passed nil" do
+ -> { DateTime.rfc2822(nil) }.should raise_error(Date::Error, "invalid date")
+ end
end
diff --git a/spec/ruby/library/datetime/strftime_spec.rb b/spec/ruby/library/datetime/strftime_spec.rb
index 725bcafb0d..abb0838e8e 100644
--- a/spec/ruby/library/datetime/strftime_spec.rb
+++ b/spec/ruby/library/datetime/strftime_spec.rb
@@ -2,6 +2,7 @@ require_relative '../../spec_helper'
require 'date'
require_relative '../../shared/time/strftime_for_date'
require_relative '../../shared/time/strftime_for_time'
+date_version = defined?(Date::VERSION) ? Date::VERSION : '3.1.0'
describe "DateTime#strftime" do
before :all do
@@ -33,14 +34,14 @@ describe "DateTime#strftime" do
end
# %v is %e-%b-%Y for Date/DateTime
- ruby_version_is ""..."3.1" do
+ version_is date_version, ""..."3.2" do #ruby_version_is ""..."3.1" do
it "should be able to show the commercial week" do
@time.strftime("%v").should == " 3-Feb-2001"
@time.strftime("%v").should == @time.strftime('%e-%b-%Y')
end
end
- ruby_version_is "3.1" do
+ version_is date_version, "3.2" do #ruby_version_is "3.1" do
it "should be able to show the commercial week" do
@time.strftime("%v").should == " 3-FEB-2001"
@time.strftime("%v").should != @time.strftime('%e-%b-%Y')
diff --git a/spec/ruby/library/datetime/to_time_spec.rb b/spec/ruby/library/datetime/to_time_spec.rb
index a11b6e30e1..09e6192e7f 100644
--- a/spec/ruby/library/datetime/to_time_spec.rb
+++ b/spec/ruby/library/datetime/to_time_spec.rb
@@ -1,5 +1,6 @@
require_relative '../../spec_helper'
require 'date'
+date_version = defined?(Date::VERSION) ? Date::VERSION : '3.1.0'
describe "DateTime#to_time" do
it "yields a new Time object" do
@@ -7,10 +8,10 @@ describe "DateTime#to_time" do
end
it "returns a Time representing the same instant" do
- datetime = DateTime.civil(3, 12, 31, 23, 58, 59)
+ datetime = DateTime.civil(2012, 12, 31, 23, 58, 59)
time = datetime.to_time.utc
- time.year.should == 3
+ time.year.should == 2012
time.month.should == 12
time.day.should == 31
time.hour.should == 23
@@ -18,6 +19,19 @@ describe "DateTime#to_time" do
time.sec.should == 59
end
+ version_is date_version, '3.2.3' do #ruby_version_is "3.2" do
+ it "returns a Time representing the same instant before Gregorian" do
+ datetime = DateTime.civil(1582, 10, 4, 23, 58, 59)
+ time = datetime.to_time.utc
+ time.year.should == 1582
+ time.month.should == 10
+ time.day.should == 14
+ time.hour.should == 23
+ time.min.should == 58
+ time.sec.should == 59
+ end
+ end
+
it "preserves the same time regardless of local time or zone" do
date = DateTime.new(2012, 12, 24, 12, 23, 00, '+03:00')
diff --git a/spec/ruby/library/delegate/delegate_class/respond_to_missing_spec.rb b/spec/ruby/library/delegate/delegate_class/respond_to_missing_spec.rb
index 729cfc96c6..3975e5208b 100644
--- a/spec/ruby/library/delegate/delegate_class/respond_to_missing_spec.rb
+++ b/spec/ruby/library/delegate/delegate_class/respond_to_missing_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
require 'delegate'
describe "DelegateClass#respond_to_missing?" do
diff --git a/spec/ruby/library/delegate/delegator/taint_spec.rb b/spec/ruby/library/delegate/delegator/taint_spec.rb
index b875b5a6b8..6bf13bb73d 100644
--- a/spec/ruby/library/delegate/delegator/taint_spec.rb
+++ b/spec/ruby/library/delegate/delegator/taint_spec.rb
@@ -5,21 +5,4 @@ describe "Delegator#taint" do
before :each do
@delegate = DelegateSpecs::Delegator.new("")
end
-
- ruby_version_is ''...'2.7' do
- it "returns self" do
- @delegate.taint.equal?(@delegate).should be_true
- end
-
- it "taints the delegator" do
- @delegate.__setobj__(nil)
- @delegate.taint
- @delegate.tainted?.should be_true
- end
-
- it "taints the delegated object" do
- @delegate.taint
- @delegate.__getobj__.tainted?.should be_true
- end
- end
end
diff --git a/spec/ruby/library/delegate/delegator/trust_spec.rb b/spec/ruby/library/delegate/delegator/trust_spec.rb
index 492f02e27f..f1b81814c5 100644
--- a/spec/ruby/library/delegate/delegator/trust_spec.rb
+++ b/spec/ruby/library/delegate/delegator/trust_spec.rb
@@ -5,20 +5,4 @@ describe "Delegator#trust" do
before :each do
@delegate = DelegateSpecs::Delegator.new([])
end
-
- ruby_version_is ''...'2.7' do
- it "returns self" do
- @delegate.trust.equal?(@delegate).should be_true
- end
-
- it "trusts the delegator" do
- @delegate.trust
- @delegate.untrusted?.should be_false
- end
-
- it "trusts the delegated object" do
- @delegate.trust
- @delegate.__getobj__.untrusted?.should be_false
- end
- end
end
diff --git a/spec/ruby/library/delegate/delegator/untaint_spec.rb b/spec/ruby/library/delegate/delegator/untaint_spec.rb
index 3f8f7721a9..4051fd2629 100644
--- a/spec/ruby/library/delegate/delegator/untaint_spec.rb
+++ b/spec/ruby/library/delegate/delegator/untaint_spec.rb
@@ -5,22 +5,4 @@ describe "Delegator#untaint" do
before :each do
@delegate = -> { DelegateSpecs::Delegator.new("") }.call
end
-
- ruby_version_is ''...'2.7' do
- it "returns self" do
- @delegate.untaint.equal?(@delegate).should be_true
- end
-
- it "untaints the delegator" do
- @delegate.untaint
- @delegate.tainted?.should be_false
- # No additional meaningful test; that it does or not taint
- # "for real" the delegator has no consequence
- end
-
- it "untaints the delegated object" do
- @delegate.untaint
- @delegate.__getobj__.tainted?.should be_false
- end
- end
end
diff --git a/spec/ruby/library/delegate/delegator/untrust_spec.rb b/spec/ruby/library/delegate/delegator/untrust_spec.rb
index acc91b099a..4f7fa1e582 100644
--- a/spec/ruby/library/delegate/delegator/untrust_spec.rb
+++ b/spec/ruby/library/delegate/delegator/untrust_spec.rb
@@ -5,21 +5,4 @@ describe "Delegator#untrust" do
before :each do
@delegate = DelegateSpecs::Delegator.new("")
end
-
- ruby_version_is ''...'2.7' do
- it "returns self" do
- @delegate.untrust.equal?(@delegate).should be_true
- end
-
- it "untrusts the delegator" do
- @delegate.__setobj__(nil)
- @delegate.untrust
- @delegate.untrusted?.should be_true
- end
-
- it "untrusts the delegated object" do
- @delegate.untrust
- @delegate.__getobj__.untrusted?.should be_true
- end
- end
end
diff --git a/spec/ruby/library/digest/instance/shared/update.rb b/spec/ruby/library/digest/instance/shared/update.rb
index dccc8f80df..17779e54a4 100644
--- a/spec/ruby/library/digest/instance/shared/update.rb
+++ b/spec/ruby/library/digest/instance/shared/update.rb
@@ -3,6 +3,6 @@ describe :digest_instance_update, shared: true do
c = Class.new do
include Digest::Instance
end
- -> { c.new.update("test") }.should raise_error(RuntimeError)
+ -> { c.new.send(@method, "test") }.should raise_error(RuntimeError)
end
end
diff --git a/spec/ruby/library/digest/md5/shared/sample.rb b/spec/ruby/library/digest/md5/shared/sample.rb
deleted file mode 100644
index 2bb4f658b1..0000000000
--- a/spec/ruby/library/digest/md5/shared/sample.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-# -*- encoding: binary -*-
-
-require 'digest/md5'
-
-module MD5Constants
-
- Contents = "Ipsum is simply dummy text of the printing and typesetting industry. \nLorem Ipsum has been the industrys standard dummy text ever since the 1500s, when an unknown printer took a galley of type and scrambled it to make a type specimen book. \nIt has survived not only five centuries, but also the leap into electronic typesetting, remaining essentially unchanged. \nIt was popularised in the 1960s with the release of Letraset sheets containing Lorem Ipsum passages, and more recently with desktop publishing software like Aldus PageMaker including versions of Lorem Ipsum."
-
- Klass = ::Digest::MD5
- BlockLength = 64
- DigestLength = 16
- BlankDigest = "\324\035\214\331\217\000\262\004\351\200\t\230\354\370B~"
- Digest = "\2473\267qw\276\364\343\345\320\304\350\313\314\217n"
- BlankHexdigest = "d41d8cd98f00b204e9800998ecf8427e"
- Hexdigest = "a733b77177bef4e3e5d0c4e8cbcc8f6e"
-
-end
diff --git a/spec/ruby/library/drb/start_service_spec.rb b/spec/ruby/library/drb/start_service_spec.rb
index 016c8b2cff..57a8cf6e15 100644
--- a/spec/ruby/library/drb/start_service_spec.rb
+++ b/spec/ruby/library/drb/start_service_spec.rb
@@ -1,28 +1,33 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/test_server'
-require 'drb'
-describe "DRb.start_service" do
- before :each do
- @server = DRb.start_service("druby://localhost:0", TestServer.new)
- end
+# This does not work yet when run in CRuby via make test-spec:
+# Gem::MissingSpecError: Could not find 'ruby2_keywords' (>= 0) among 28 total gem(s)
+guard_not -> { MSpecScript.instance_variable_defined?(:@testing_ruby) } do
+ require_relative 'fixtures/test_server'
+ require 'drb'
- after :each do
- DRb.stop_service if @server
- end
+ describe "DRb.start_service" do
+ before :each do
+ @server = DRb.start_service("druby://localhost:0", TestServer.new)
+ end
- it "runs a basic remote call" do
- DRb.current_server.should == @server
- obj = DRbObject.new(nil, @server.uri)
- obj.add(1,2,3).should == 6
- end
+ after :each do
+ DRb.stop_service if @server
+ end
+
+ it "runs a basic remote call" do
+ DRb.current_server.should == @server
+ obj = DRbObject.new(nil, @server.uri)
+ obj.add(1,2,3).should == 6
+ end
- it "runs a basic remote call passing a block" do
- DRb.current_server.should == @server
- obj = DRbObject.new(nil, @server.uri)
- obj.add_yield(2) do |i|
- i.should == 2
- i+1
- end.should == 4
+ it "runs a basic remote call passing a block" do
+ DRb.current_server.should == @server
+ obj = DRbObject.new(nil, @server.uri)
+ obj.add_yield(2) do |i|
+ i.should == 2
+ i+1
+ end.should == 4
+ end
end
end
diff --git a/spec/ruby/library/erb/new_spec.rb b/spec/ruby/library/erb/new_spec.rb
index f18e25939e..a5aeeaeed1 100644
--- a/spec/ruby/library/erb/new_spec.rb
+++ b/spec/ruby/library/erb/new_spec.rb
@@ -138,4 +138,20 @@ END
ERB.new(@eruby_str).result
->{ ERB.new("<%= list %>").result }.should raise_error(NameError)
end
+
+ describe "warning about arguments" do
+ version_is ERB.version, "2.2.1" do #ruby_version_is "3.1" do
+ it "warns when passed safe_level and later arguments" do
+ -> {
+ ERB.new(@eruby_str, nil, '%')
+ }.should complain(/warning: Passing safe_level with the 2nd argument of ERB.new is deprecated. Do not use it, and specify other arguments as keyword arguments./)
+ end
+
+ it "does not warn when passed arguments as keyword argument" do
+ -> {
+ ERB.new(@eruby_str, trim_mode: '%')
+ }.should_not complain(/warning: Passing safe_level with the 2nd argument of ERB.new is deprecated. Do not use it, and specify other arguments as keyword arguments./)
+ end
+ end
+ end
end
diff --git a/spec/ruby/library/erb/run_spec.rb b/spec/ruby/library/erb/run_spec.rb
index 8c07442d8f..602e53ab38 100644
--- a/spec/ruby/library/erb/run_spec.rb
+++ b/spec/ruby/library/erb/run_spec.rb
@@ -6,7 +6,7 @@ describe "ERB#run" do
# lambda { ... }.should output
def _steal_stdout
orig = $stdout
- s = ''
+ s = +''
def s.write(arg); self << arg.to_s; end
$stdout = s
begin
diff --git a/spec/ruby/library/etc/confstr_spec.rb b/spec/ruby/library/etc/confstr_spec.rb
index 41a970a918..5b43461150 100644
--- a/spec/ruby/library/etc/confstr_spec.rb
+++ b/spec/ruby/library/etc/confstr_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+require_relative '../../spec_helper'
require 'etc'
platform_is_not :windows, :android do
diff --git a/spec/ruby/library/etc/passwd_spec.rb b/spec/ruby/library/etc/passwd_spec.rb
index d61dada451..7157fd3f2e 100644
--- a/spec/ruby/library/etc/passwd_spec.rb
+++ b/spec/ruby/library/etc/passwd_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+require_relative '../../spec_helper'
require 'etc'
platform_is_not :windows do
diff --git a/spec/ruby/library/etc/sysconf_spec.rb b/spec/ruby/library/etc/sysconf_spec.rb
index e7d59d1b22..1f2c7a770f 100644
--- a/spec/ruby/library/etc/sysconf_spec.rb
+++ b/spec/ruby/library/etc/sysconf_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+require_relative '../../spec_helper'
require 'etc'
platform_is_not :windows do
diff --git a/spec/ruby/library/etc/sysconfdir_spec.rb b/spec/ruby/library/etc/sysconfdir_spec.rb
index d54299c513..8538faa65b 100644
--- a/spec/ruby/library/etc/sysconfdir_spec.rb
+++ b/spec/ruby/library/etc/sysconfdir_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+require_relative '../../spec_helper'
require 'etc'
describe "Etc.sysconfdir" do
diff --git a/spec/ruby/library/etc/systmpdir_spec.rb b/spec/ruby/library/etc/systmpdir_spec.rb
index 99c82903f8..5b007aa9f9 100644
--- a/spec/ruby/library/etc/systmpdir_spec.rb
+++ b/spec/ruby/library/etc/systmpdir_spec.rb
@@ -1,4 +1,4 @@
-require File.expand_path('../../../spec_helper', __FILE__)
+require_relative '../../spec_helper'
require 'etc'
describe "Etc.systmpdir" do
diff --git a/spec/ruby/library/etc/uname_spec.rb b/spec/ruby/library/etc/uname_spec.rb
new file mode 100644
index 0000000000..a42558f593
--- /dev/null
+++ b/spec/ruby/library/etc/uname_spec.rb
@@ -0,0 +1,14 @@
+require_relative '../../spec_helper'
+require 'etc'
+
+describe "Etc.uname" do
+ it "returns a Hash with the documented keys" do
+ uname = Etc.uname
+ uname.should be_kind_of(Hash)
+ uname.should.key?(:sysname)
+ uname.should.key?(:nodename)
+ uname.should.key?(:release)
+ uname.should.key?(:version)
+ uname.should.key?(:machine)
+ end
+end
diff --git a/spec/ruby/library/expect/expect_spec.rb b/spec/ruby/library/expect/expect_spec.rb
index a7041d42ee..76ea3d5451 100644
--- a/spec/ruby/library/expect/expect_spec.rb
+++ b/spec/ruby/library/expect/expect_spec.rb
@@ -1,5 +1,6 @@
+require_relative '../../spec_helper'
+
platform_is_not :windows do
- require_relative '../../spec_helper'
require 'expect'
describe "IO#expect" do
diff --git a/spec/ruby/library/fiber/current_spec.rb b/spec/ruby/library/fiber/current_spec.rb
index e67d7d050a..1467a88d0d 100644
--- a/spec/ruby/library/fiber/current_spec.rb
+++ b/spec/ruby/library/fiber/current_spec.rb
@@ -3,6 +3,12 @@ require_relative '../../spec_helper'
require 'fiber'
describe "Fiber.current" do
+ ruby_version_is "3.1" do
+ it "is available without an extra require" do
+ ruby_exe("print Fiber.current.class", options: '--disable-gems --disable-did-you-mean').should == "Fiber"
+ end
+ end
+
it "returns the root Fiber when called outside of a Fiber" do
root = Fiber.current
root.should be_an_instance_of(Fiber)
@@ -42,22 +48,11 @@ describe "Fiber.current" do
fiber3 = Fiber.new do
states << :fiber3
fiber2.transfer
- ruby_version_is '3.0' do
- states << :fiber3_terminated
- end
- ruby_version_is '' ... '3.0' do
- flunk
- end
+ states << :fiber3_terminated
end
fiber3.resume
- ruby_version_is "" ... "3.0" do
- states.should == [:fiber3, :fiber2, :fiber]
- end
-
- ruby_version_is "3.0" do
- states.should == [:fiber3, :fiber2, :fiber, :fiber3_terminated]
- end
+ states.should == [:fiber3, :fiber2, :fiber, :fiber3_terminated]
end
end
diff --git a/spec/ruby/library/fiber/resume_spec.rb b/spec/ruby/library/fiber/resume_spec.rb
index 8b7c104a6f..fd69d3ba99 100644
--- a/spec/ruby/library/fiber/resume_spec.rb
+++ b/spec/ruby/library/fiber/resume_spec.rb
@@ -3,33 +3,16 @@ require_relative '../../spec_helper'
require 'fiber'
describe "Fiber#resume" do
- ruby_version_is '' ... '3.0' do
- it "raises a FiberError if the Fiber has transferred control to another Fiber" do
- fiber1 = Fiber.new { true }
- fiber2 = Fiber.new { fiber1.transfer; Fiber.yield }
- fiber2.resume
- -> { fiber2.resume }.should raise_error(FiberError)
- end
-
- it "raises a FiberError if the Fiber attempts to resume a resuming fiber" do
- root_fiber = Fiber.current
- fiber1 = Fiber.new { root_fiber.resume }
- -> { fiber1.resume }.should raise_error(FiberError, /double resume/)
- end
+ 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
- ruby_version_is '3.0' do
- it "can work with Fiber#transfer" do
- fiber1 = Fiber.new { true }
- fiber2 = Fiber.new { fiber1.transfer; Fiber.yield 10 ; Fiber.yield 20; raise }
- fiber2.resume.should == 10
- fiber2.resume.should == 20
- end
-
- it "raises a FiberError if the Fiber attempts to resume a resuming fiber" do
- root_fiber = Fiber.current
- fiber1 = Fiber.new { root_fiber.resume }
- -> { fiber1.resume }.should raise_error(FiberError, /attempt to resume a resuming fiber/)
- end
+ 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/library/fiber/transfer_spec.rb b/spec/ruby/library/fiber/transfer_spec.rb
index 7af548da1a..e20d51352e 100644
--- a/spec/ruby/library/fiber/transfer_spec.rb
+++ b/spec/ruby/library/fiber/transfer_spec.rb
@@ -11,13 +11,7 @@ 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 }
-
- ruby_version_is '' ... '3.0' do
- fiber2.resume.should == :fiber1
- end
- ruby_version_is '3.0' do
- fiber2.resume.should == :fiber2
- end
+ fiber2.resume.should == :fiber2
end
it "returns to the root Fiber when finished" do
@@ -40,24 +34,12 @@ describe "Fiber#transfer" do
states.should == [:start, :end]
end
- ruby_version_is '' ... '3.0' do
- it "can transfer control to a Fiber that has transferred to another Fiber" do
- states = []
- fiber1 = Fiber.new { states << :fiber1 }
- fiber2 = Fiber.new { states << :fiber2_start; fiber1.transfer; states << :fiber2_end}
- fiber2.resume.should == [:fiber2_start, :fiber1]
- fiber2.transfer.should == [:fiber2_start, :fiber1, :fiber2_end]
- end
- end
-
- ruby_version_is '3.0' do
- it "can not transfer control to a Fiber that has suspended by Fiber.yield" do
- states = []
- fiber1 = Fiber.new { states << :fiber1 }
- fiber2 = Fiber.new { states << :fiber2_start; Fiber.yield fiber1.transfer; states << :fiber2_end}
- fiber2.resume.should == [:fiber2_start, :fiber1]
- -> { fiber2.transfer }.should raise_error(FiberError)
- end
+ 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
@@ -101,28 +83,4 @@ describe "Fiber#transfer" do
thread.join
states.should == [0, 1, 2, 3]
end
-
- ruby_version_is "" ... "3.0" do
- it "runs until Fiber.yield" do
- obj = mock('obj')
- obj.should_not_receive(:do)
- fiber = Fiber.new { 1 + 2; Fiber.yield; obj.do }
- fiber.transfer
- end
-
- it "resumes from the last call to Fiber.yield on subsequent invocations" do
- fiber = Fiber.new { Fiber.yield :first; :second }
- fiber.transfer.should == :first
- fiber.transfer.should == :second
- end
-
- it "sets the block parameters to its arguments on the first invocation" do
- first = mock('first')
- first.should_receive(:arg).with(:first).twice
-
- fiber = Fiber.new { |arg| first.arg arg; Fiber.yield; first.arg arg; }
- fiber.transfer :first
- fiber.transfer :second
- end
- end
end
diff --git a/spec/ruby/library/fiddle/handle/initialize_spec.rb b/spec/ruby/library/fiddle/handle/initialize_spec.rb
new file mode 100644
index 0000000000..51c2470efd
--- /dev/null
+++ b/spec/ruby/library/fiddle/handle/initialize_spec.rb
@@ -0,0 +1,10 @@
+require_relative '../../../spec_helper'
+require 'fiddle'
+
+describe "Fiddle::Handle#initialize" do
+ it "raises Fiddle::DLError if the library cannot be found" do
+ -> {
+ Fiddle::Handle.new("doesnotexist.doesnotexist")
+ }.should raise_error(Fiddle::DLError)
+ end
+end
diff --git a/spec/ruby/library/io-wait/fixtures/classes.rb b/spec/ruby/library/io-wait/fixtures/classes.rb
new file mode 100644
index 0000000000..837c7edd06
--- /dev/null
+++ b/spec/ruby/library/io-wait/fixtures/classes.rb
@@ -0,0 +1,12 @@
+module IOWaitSpec
+ def self.exhaust_write_buffer(io)
+ written = 0
+ buf = " " * 4096
+
+ begin
+ written += io.write_nonblock(buf)
+ rescue Errno::EAGAIN, Errno::EWOULDBLOCK
+ return written
+ end while true
+ end
+end
diff --git a/spec/ruby/library/io-wait/wait_readable_spec.rb b/spec/ruby/library/io-wait/wait_readable_spec.rb
new file mode 100644
index 0000000000..06ffbda5c8
--- /dev/null
+++ b/spec/ruby/library/io-wait/wait_readable_spec.rb
@@ -0,0 +1,27 @@
+require_relative '../../spec_helper'
+
+ruby_version_is ''...'3.2' do
+ require 'io/wait'
+end
+
+describe "IO#wait_readable" do
+ before :each do
+ @io = File.new(__FILE__ )
+ end
+
+ after :each do
+ @io.close
+ end
+
+ it "waits for the IO to become readable with no timeout" do
+ @io.wait_readable.should == @io
+ end
+
+ it "waits for the IO to become readable with the given timeout" do
+ @io.wait_readable(1).should == @io
+ end
+
+ it "waits for the IO to become readable with the given large timeout" do
+ @io.wait_readable(365 * 24 * 60 * 60).should == @io
+ end
+end
diff --git a/spec/ruby/library/io-wait/wait_spec.rb b/spec/ruby/library/io-wait/wait_spec.rb
new file mode 100644
index 0000000000..fc07c6a8d9
--- /dev/null
+++ b/spec/ruby/library/io-wait/wait_spec.rb
@@ -0,0 +1,155 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+
+ruby_version_is ''...'3.2' do
+ require 'io/wait'
+end
+
+describe "IO#wait" do
+ before :each do
+ @io = File.new(__FILE__ )
+
+ if /mswin|mingw/ =~ RUBY_PLATFORM
+ require 'socket'
+ @r, @w = Socket.pair(Socket::AF_INET, Socket::SOCK_STREAM, 0)
+ else
+ @r, @w = IO.pipe
+ end
+ end
+
+ after :each do
+ @io.close unless @io.closed?
+
+ @r.close unless @r.closed?
+ @w.close unless @w.closed?
+ end
+
+ context "[events, timeout] passed" do
+ ruby_version_is ""..."3.2" do
+ it "returns self when the READABLE event is ready during the timeout" do
+ @w.write('data to read')
+ @r.wait(IO::READABLE, 2).should.equal?(@r)
+ end
+
+ it "returns self when the WRITABLE event is ready during the timeout" do
+ @w.wait(IO::WRITABLE, 0).should.equal?(@w)
+ end
+ end
+
+ ruby_version_is "3.2" do
+ it "returns events mask when the READABLE event is ready during the timeout" do
+ @w.write('data to read')
+ @r.wait(IO::READABLE, 2).should == IO::READABLE
+ end
+
+ it "returns events mask when the WRITABLE event is ready during the timeout" do
+ @w.wait(IO::WRITABLE, 0).should == IO::WRITABLE
+ end
+ end
+
+ it "waits for the READABLE event to be ready" do
+ @r.wait(IO::READABLE, 0).should == nil
+
+ @w.write('data to read')
+ @r.wait(IO::READABLE, 0).should_not == nil
+ end
+
+ it "waits for the WRITABLE event to be ready" do
+ written_bytes = IOWaitSpec.exhaust_write_buffer(@w)
+ @w.wait(IO::WRITABLE, 0).should == nil
+
+ @r.read(written_bytes)
+ @w.wait(IO::WRITABLE, 0).should_not == nil
+ end
+
+ it "returns nil when the READABLE event is not ready during the timeout" do
+ @w.wait(IO::READABLE, 0).should == nil
+ end
+
+ it "returns nil when the WRITABLE event is not ready during the timeout" do
+ IOWaitSpec.exhaust_write_buffer(@w)
+ @w.wait(IO::WRITABLE, 0).should == nil
+ end
+
+ it "raises IOError when io is closed (closed stream (IOError))" do
+ @io.close
+ -> { @io.wait(IO::READABLE, 0) }.should raise_error(IOError, "closed stream")
+ end
+
+ ruby_version_is "3.2" do
+ it "raises ArgumentError when events is not positive" do
+ -> { @w.wait(0, 0) }.should raise_error(ArgumentError, "Events must be positive integer!")
+ -> { @w.wait(-1, 0) }.should raise_error(ArgumentError, "Events must be positive integer!")
+ end
+ end
+
+ it "changes thread status to 'sleep' when waits for READABLE event" do
+ t = Thread.new { @r.wait(IO::READABLE, 10) }
+ sleep 1
+ t.status.should == 'sleep'
+ t.kill
+ t.join # Thread#kill doesn't wait for the thread to end
+ end
+
+ it "changes thread status to 'sleep' when waits for WRITABLE event" do
+ written_bytes = IOWaitSpec.exhaust_write_buffer(@w)
+
+ t = Thread.new { @w.wait(IO::WRITABLE, 10) }
+ sleep 1
+ t.status.should == 'sleep'
+ t.kill
+ t.join # Thread#kill doesn't wait for the thread to end
+ end
+ end
+
+ context "[timeout, mode] passed" do
+ it "accepts :r, :read, :readable mode to check READABLE event" do
+ @io.wait(0, :r).should == @io
+ @io.wait(0, :read).should == @io
+ @io.wait(0, :readable).should == @io
+ end
+
+ it "accepts :w, :write, :writable mode to check WRITABLE event" do
+ @io.wait(0, :w).should == @io
+ @io.wait(0, :write).should == @io
+ @io.wait(0, :writable).should == @io
+ end
+
+ it "accepts :rw, :read_write, :readable_writable mode to check READABLE and WRITABLE events" do
+ @io.wait(0, :rw).should == @io
+ @io.wait(0, :read_write).should == @io
+ @io.wait(0, :readable_writable).should == @io
+ end
+
+ it "accepts a list of modes" do
+ @io.wait(0, :r, :w, :rw).should == @io
+ end
+
+ # It works at least since 2.7 but by some reason may fail on 3.1
+ ruby_version_is "3.2" do
+ it "accepts timeout and mode in any order" do
+ @io.wait(0, :r).should == @io
+ @io.wait(:r, 0).should == @io
+ @io.wait(:r, 0, :w).should == @io
+ end
+ end
+
+ it "raises ArgumentError when passed wrong Symbol value as mode argument" do
+ -> { @io.wait(0, :wrong) }.should raise_error(ArgumentError, "unsupported mode: wrong")
+ end
+
+ # It works since 3.0 but by some reason may fail on 3.1
+ ruby_version_is "3.2" do
+ it "raises ArgumentError when several Integer arguments passed" do
+ -> { @w.wait(0, 10, :r) }.should raise_error(ArgumentError, "timeout given more than once")
+ end
+ end
+
+ ruby_version_is "3.2" do
+ it "raises IOError when io is closed (closed stream (IOError))" do
+ @io.close
+ -> { @io.wait(0, :r) }.should raise_error(IOError, "closed stream")
+ end
+ end
+ end
+end
diff --git a/spec/ruby/library/io-wait/wait_writable_spec.rb b/spec/ruby/library/io-wait/wait_writable_spec.rb
new file mode 100644
index 0000000000..8c44780d39
--- /dev/null
+++ b/spec/ruby/library/io-wait/wait_writable_spec.rb
@@ -0,0 +1,20 @@
+require_relative '../../spec_helper'
+
+ruby_version_is ''...'3.2' do
+ require 'io/wait'
+end
+
+describe "IO#wait_writable" do
+ it "waits for the IO to become writable with no timeout" do
+ STDOUT.wait_writable.should == STDOUT
+ end
+
+ it "waits for the IO to become writable with the given timeout" do
+ STDOUT.wait_writable(1).should == STDOUT
+ end
+
+ it "waits for the IO to become writable with the given large timeout" do
+ # Represents one year and is larger than a 32-bit int
+ STDOUT.wait_writable(365 * 24 * 60 * 60).should == STDOUT
+ end
+end
diff --git a/spec/ruby/library/ipaddr/new_spec.rb b/spec/ruby/library/ipaddr/new_spec.rb
index 053928c3cf..714c1e2f1a 100644
--- a/spec/ruby/library/ipaddr/new_spec.rb
+++ b/spec/ruby/library/ipaddr/new_spec.rb
@@ -77,7 +77,13 @@ describe "IPAddr#new" do
a.family.should == Socket::AF_INET6
end
- ruby_version_is ""..."3.1" do
+ ipaddr_version = if defined?(IPAddr::VERSION) #ruby_version_is ""..."3.1" do
+ IPAddr::VERSION
+ else
+ "1.2.2"
+ end
+
+ version_is ipaddr_version, ""..."1.2.3" do #ruby_version_is ""..."3.1" do
it "raises on incorrect IPAddr strings" do
[
["fe80::1%fxp0"],
@@ -93,7 +99,7 @@ describe "IPAddr#new" do
end
end
- ruby_version_is "3.1" do
+ version_is ipaddr_version, "1.2.3" do #ruby_version_is "3.1" do
it "raises on incorrect IPAddr strings" do
[
["::1/255.255.255.0"],
diff --git a/spec/ruby/library/logger/device/close_spec.rb b/spec/ruby/library/logger/device/close_spec.rb
index d7d107fcce..1db5d582a7 100644
--- a/spec/ruby/library/logger/device/close_spec.rb
+++ b/spec/ruby/library/logger/device/close_spec.rb
@@ -15,17 +15,8 @@ describe "Logger::LogDevice#close" do
rm_r @file_path
end
- ruby_version_is ""..."2.7" do
- it "closes the LogDevice's stream" do
- @device.close
- -> { @device.write("Test") }.should complain(/\Alog writing failed\./)
- end
- end
-
- ruby_version_is "2.7" do
- it "closes the LogDevice's stream" do
- @device.close
- -> { @device.write("Test") }.should complain(/\Alog shifting failed\./)
- end
+ it "closes the LogDevice's stream" do
+ @device.close
+ -> { @device.write("Test") }.should complain(/\Alog shifting failed\./)
end
end
diff --git a/spec/ruby/library/logger/device/write_spec.rb b/spec/ruby/library/logger/device/write_spec.rb
index 5506bb2c38..87ecf2ad6a 100644
--- a/spec/ruby/library/logger/device/write_spec.rb
+++ b/spec/ruby/library/logger/device/write_spec.rb
@@ -35,17 +35,8 @@ describe "Logger::LogDevice#write" do
rm_r path
end
- ruby_version_is ""..."2.7" do
- it "fails if the device is already closed" do
- @device.close
- -> { @device.write "foo" }.should complain(/\Alog writing failed\./)
- end
- end
-
- ruby_version_is "2.7" do
- it "fails if the device is already closed" do
- @device.close
- -> { @device.write "foo" }.should complain(/\Alog shifting failed\./)
- end
+ it "fails if the device is already closed" do
+ @device.close
+ -> { @device.write "foo" }.should complain(/\Alog shifting failed\./)
end
end
diff --git a/spec/ruby/library/matrix/I_spec.rb b/spec/ruby/library/matrix/I_spec.rb
index aa064ed54b..6eeffe8e98 100644
--- a/spec/ruby/library/matrix/I_spec.rb
+++ b/spec/ruby/library/matrix/I_spec.rb
@@ -1,9 +1,6 @@
require_relative '../../spec_helper'
+require_relative 'shared/identity'
-ruby_version_is ""..."3.1" do
- require_relative 'shared/identity'
-
- describe "Matrix.I" do
- it_behaves_like :matrix_identity, :I
- end
+describe "Matrix.I" do
+ it_behaves_like :matrix_identity, :I
end
diff --git a/spec/ruby/library/matrix/antisymmetric_spec.rb b/spec/ruby/library/matrix/antisymmetric_spec.rb
index dcc3c30f3e..200df703cb 100644
--- a/spec/ruby/library/matrix/antisymmetric_spec.rb
+++ b/spec/ruby/library/matrix/antisymmetric_spec.rb
@@ -1,38 +1,36 @@
require_relative '../../spec_helper'
-ruby_version_is ""..."3.1" do
- require 'matrix'
+require 'matrix'
- describe "Matrix#antisymmetric?" do
- it "returns true for an antisymmetric Matrix" do
- Matrix[[0, -2, Complex(1, 3)], [2, 0, 5], [-Complex(1, 3), -5, 0]].antisymmetric?.should be_true
- end
+describe "Matrix#antisymmetric?" do
+ it "returns true for an antisymmetric Matrix" do
+ Matrix[[0, -2, Complex(1, 3)], [2, 0, 5], [-Complex(1, 3), -5, 0]].antisymmetric?.should be_true
+ end
- it "returns true for a 0x0 empty matrix" do
- Matrix.empty.antisymmetric?.should be_true
- end
+ it "returns true for a 0x0 empty matrix" do
+ Matrix.empty.antisymmetric?.should be_true
+ end
- it "returns false for non-antisymmetric matrices" do
- [
- Matrix[[1, 2, 3], [4, 5, 6], [7, 8, 9]],
- Matrix[[1, -2, 3], [2, 0, 6], [-3, -6, 0]], # wrong diagonal element
- Matrix[[0, 2, -3], [2, 0, 6], [-3, 6, 0]] # only signs wrong
- ].each do |matrix|
- matrix.antisymmetric?.should be_false
- end
+ it "returns false for non-antisymmetric matrices" do
+ [
+ Matrix[[1, 2, 3], [4, 5, 6], [7, 8, 9]],
+ Matrix[[1, -2, 3], [2, 0, 6], [-3, -6, 0]], # wrong diagonal element
+ Matrix[[0, 2, -3], [2, 0, 6], [-3, 6, 0]] # only signs wrong
+ ].each do |matrix|
+ matrix.antisymmetric?.should be_false
end
+ end
- it "raises an error for rectangular matrices" do
- [
- Matrix[[0], [0]],
- Matrix[[0, 0]],
- Matrix.empty(0, 2),
- Matrix.empty(2, 0),
- ].each do |rectangular_matrix|
- -> {
- rectangular_matrix.antisymmetric?
- }.should raise_error(Matrix::ErrDimensionMismatch)
- end
+ it "raises an error for rectangular matrices" do
+ [
+ Matrix[[0], [0]],
+ Matrix[[0, 0]],
+ Matrix.empty(0, 2),
+ Matrix.empty(2, 0),
+ ].each do |rectangular_matrix|
+ -> {
+ rectangular_matrix.antisymmetric?
+ }.should raise_error(Matrix::ErrDimensionMismatch)
end
end
end
diff --git a/spec/ruby/library/matrix/build_spec.rb b/spec/ruby/library/matrix/build_spec.rb
index d3055a1aa7..6d8017a3df 100644
--- a/spec/ruby/library/matrix/build_spec.rb
+++ b/spec/ruby/library/matrix/build_spec.rb
@@ -1,76 +1,73 @@
require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require_relative 'fixtures/classes'
- require 'matrix'
+describe "Matrix.build" do
- describe "Matrix.build" do
-
- it "returns a Matrix object of the given size" do
- m = Matrix.build(3, 4){1}
- m.should be_an_instance_of(Matrix)
- m.row_size.should == 3
- m.column_size.should == 4
- end
+ it "returns a Matrix object of the given size" do
+ m = Matrix.build(3, 4){1}
+ m.should be_an_instance_of(Matrix)
+ m.row_size.should == 3
+ m.column_size.should == 4
+ end
- it "builds the Matrix using the given block" do
- Matrix.build(2, 3){|col, row| 10*col - row}.should ==
- Matrix[[0, -1, -2], [10, 9, 8]]
- end
+ it "builds the Matrix using the given block" do
+ Matrix.build(2, 3){|col, row| 10*col - row}.should ==
+ Matrix[[0, -1, -2], [10, 9, 8]]
+ end
- it "iterates through the first row, then the second, ..." do
- acc = []
- Matrix.build(2, 3){|*args| acc << args}
- acc.should == [[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2]]
- end
+ it "iterates through the first row, then the second, ..." do
+ acc = []
+ Matrix.build(2, 3){|*args| acc << args}
+ acc.should == [[0, 0], [0, 1], [0, 2], [1, 0], [1, 1], [1, 2]]
+ end
- it "returns an Enumerator is no block is given" do
- enum = Matrix.build(2, 1)
- enum.should be_an_instance_of(Enumerator)
- enum.each{1}.should == Matrix[[1], [1]]
- end
+ it "returns an Enumerator is no block is given" do
+ enum = Matrix.build(2, 1)
+ enum.should be_an_instance_of(Enumerator)
+ enum.each{1}.should == Matrix[[1], [1]]
+ end
- it "requires integers as parameters" do
- -> { Matrix.build("1", "2"){1} }.should raise_error(TypeError)
- -> { Matrix.build(nil, nil){1} }.should raise_error(TypeError)
- -> { Matrix.build(1..2){1} }.should raise_error(TypeError)
- end
+ it "requires integers as parameters" do
+ -> { Matrix.build("1", "2"){1} }.should raise_error(TypeError)
+ -> { Matrix.build(nil, nil){1} }.should raise_error(TypeError)
+ -> { Matrix.build(1..2){1} }.should raise_error(TypeError)
+ end
- it "requires non-negative integers" do
- -> { Matrix.build(-1, 1){1} }.should raise_error(ArgumentError)
- -> { Matrix.build(+1,-1){1} }.should raise_error(ArgumentError)
- end
+ it "requires non-negative integers" do
+ -> { Matrix.build(-1, 1){1} }.should raise_error(ArgumentError)
+ -> { Matrix.build(+1,-1){1} }.should raise_error(ArgumentError)
+ end
- it "returns empty Matrix if one argument is zero" do
- m = Matrix.build(0, 3){
- raise "Should not yield"
- }
- m.should be_empty
- m.column_size.should == 3
+ it "returns empty Matrix if one argument is zero" do
+ m = Matrix.build(0, 3){
+ raise "Should not yield"
+ }
+ m.should be_empty
+ m.column_size.should == 3
- m = Matrix.build(3, 0){
- raise "Should not yield"
- }
- m.should be_empty
- m.row_size.should == 3
- end
+ m = Matrix.build(3, 0){
+ raise "Should not yield"
+ }
+ m.should be_empty
+ m.row_size.should == 3
+ end
- it "tries to calls :to_int on arguments" do
- int = mock('int')
- int.should_receive(:to_int).twice.and_return(2)
- Matrix.build(int, int){ 1 }.should == Matrix[ [1,1], [1,1] ]
- end
+ it "tries to calls :to_int on arguments" do
+ int = mock('int')
+ int.should_receive(:to_int).twice.and_return(2)
+ Matrix.build(int, int){ 1 }.should == Matrix[ [1,1], [1,1] ]
+ end
- it "builds an nxn Matrix when given only one argument" do
- m = Matrix.build(3){1}
- m.row_size.should == 3
- m.column_size.should == 3
- end
+ it "builds an nxn Matrix when given only one argument" do
+ m = Matrix.build(3){1}
+ m.row_size.should == 3
+ m.column_size.should == 3
end
+end
- describe "for a subclass of Matrix" do
- it "returns an instance of that subclass" do
- MatrixSub.build(3){1}.should be_an_instance_of(MatrixSub)
- end
+describe "for a subclass of Matrix" do
+ it "returns an instance of that subclass" do
+ MatrixSub.build(3){1}.should be_an_instance_of(MatrixSub)
end
end
diff --git a/spec/ruby/library/matrix/clone_spec.rb b/spec/ruby/library/matrix/clone_spec.rb
index bde119988f..74e5bf157e 100644
--- a/spec/ruby/library/matrix/clone_spec.rb
+++ b/spec/ruby/library/matrix/clone_spec.rb
@@ -1,28 +1,25 @@
require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require_relative 'fixtures/classes'
- require 'matrix'
-
- describe "Matrix#clone" do
- before :each do
- @a = Matrix[[1, 2], [3, 4], [5, 6]]
- end
+describe "Matrix#clone" do
+ before :each do
+ @a = Matrix[[1, 2], [3, 4], [5, 6]]
+ end
- it "returns a shallow copy of the matrix" do
- b = @a.clone
- @a.should_not equal(b)
- b.should be_kind_of(Matrix)
- b.should == @a
- 0.upto(@a.row_size - 1) do |i|
- @a.row(i).should_not equal(b.row(i))
- end
+ it "returns a shallow copy of the matrix" do
+ b = @a.clone
+ @a.should_not equal(b)
+ b.should be_kind_of(Matrix)
+ b.should == @a
+ 0.upto(@a.row_size - 1) do |i|
+ @a.row(i).should_not equal(b.row(i))
end
+ end
- describe "for a subclass of Matrix" do
- it "returns an instance of that subclass" do
- MatrixSub.ins.clone.should be_an_instance_of(MatrixSub)
- end
+ describe "for a subclass of Matrix" do
+ it "returns an instance of that subclass" do
+ MatrixSub.ins.clone.should be_an_instance_of(MatrixSub)
end
end
end
diff --git a/spec/ruby/library/matrix/coerce_spec.rb b/spec/ruby/library/matrix/coerce_spec.rb
index aa3a32765a..4022f00236 100644
--- a/spec/ruby/library/matrix/coerce_spec.rb
+++ b/spec/ruby/library/matrix/coerce_spec.rb
@@ -1,11 +1,8 @@
require_relative '../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
-
- describe "Matrix#coerce" do
- it "allows the division of integer by a Matrix " do
- (1/Matrix[[0,1],[-1,0]]).should == Matrix[[0,-1],[1,0]]
- end
+describe "Matrix#coerce" do
+ it "allows the division of integer by a Matrix " do
+ (1/Matrix[[0,1],[-1,0]]).should == Matrix[[0,-1],[1,0]]
end
end
diff --git a/spec/ruby/library/matrix/collect_spec.rb b/spec/ruby/library/matrix/collect_spec.rb
index 66ec3486c8..bba640213b 100644
--- a/spec/ruby/library/matrix/collect_spec.rb
+++ b/spec/ruby/library/matrix/collect_spec.rb
@@ -1,9 +1,6 @@
require_relative '../../spec_helper'
+require_relative 'shared/collect'
-ruby_version_is ""..."3.1" do
- require_relative 'shared/collect'
-
- describe "Matrix#collect" do
- it_behaves_like :collect, :collect
- end
+describe "Matrix#collect" do
+ it_behaves_like :collect, :collect
end
diff --git a/spec/ruby/library/matrix/column_size_spec.rb b/spec/ruby/library/matrix/column_size_spec.rb
index e7b42b101e..041914e5b9 100644
--- a/spec/ruby/library/matrix/column_size_spec.rb
+++ b/spec/ruby/library/matrix/column_size_spec.rb
@@ -1,16 +1,13 @@
require_relative '../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
-
- describe "Matrix#column_size" do
- it "returns the number of columns" do
- Matrix[ [1,2], [3,4] ].column_size.should == 2
- end
+describe "Matrix#column_size" do
+ it "returns the number of columns" do
+ Matrix[ [1,2], [3,4] ].column_size.should == 2
+ end
- it "returns 0 for empty matrices" do
- Matrix[ [], [] ].column_size.should == 0
- Matrix[ ].column_size.should == 0
- end
+ it "returns 0 for empty matrices" do
+ Matrix[ [], [] ].column_size.should == 0
+ Matrix[ ].column_size.should == 0
end
end
diff --git a/spec/ruby/library/matrix/column_spec.rb b/spec/ruby/library/matrix/column_spec.rb
index 98a767ad08..1f3c80964a 100644
--- a/spec/ruby/library/matrix/column_spec.rb
+++ b/spec/ruby/library/matrix/column_spec.rb
@@ -1,38 +1,35 @@
require_relative '../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
-
- describe "Matrix#column" do
- before :all do
- @m = Matrix[[1,2,3], [2,3,4]]
- end
+describe "Matrix#column" do
+ before :all do
+ @m = Matrix[[1,2,3], [2,3,4]]
+ end
- it "returns a Vector when called without a block" do
- @m.column(1).should == Vector[2,3]
- end
+ it "returns a Vector when called without a block" do
+ @m.column(1).should == Vector[2,3]
+ end
- it "yields each element in the column to the block" do
- a = []
- @m.column(1) {|n| a << n }
- a.should == [2,3]
- end
+ it "yields each element in the column to the block" do
+ a = []
+ @m.column(1) {|n| a << n }
+ a.should == [2,3]
+ end
- it "counts backwards for negative argument" do
- @m.column(-1).should == Vector[3, 4]
- end
+ it "counts backwards for negative argument" do
+ @m.column(-1).should == Vector[3, 4]
+ end
- it "returns self when called with a block" do
- @m.column(0) { |x| x }.should equal(@m)
- end
+ it "returns self when called with a block" do
+ @m.column(0) { |x| x }.should equal(@m)
+ end
- it "returns nil when out of bounds" do
- @m.column(3).should == nil
- end
+ it "returns nil when out of bounds" do
+ @m.column(3).should == nil
+ end
- it "never yields when out of bounds" do
- -> { @m.column(3){ raise } }.should_not raise_error
- -> { @m.column(-4){ raise } }.should_not raise_error
- end
+ it "never yields when out of bounds" do
+ -> { @m.column(3){ raise } }.should_not raise_error
+ -> { @m.column(-4){ raise } }.should_not raise_error
end
end
diff --git a/spec/ruby/library/matrix/column_vector_spec.rb b/spec/ruby/library/matrix/column_vector_spec.rb
index afdeaced47..47e866a8d5 100644
--- a/spec/ruby/library/matrix/column_vector_spec.rb
+++ b/spec/ruby/library/matrix/column_vector_spec.rb
@@ -1,28 +1,25 @@
require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require_relative 'fixtures/classes'
- require 'matrix'
+describe "Matrix.column_vector" do
- describe "Matrix.column_vector" do
-
- it "returns a single column Matrix when called with an Array" do
- m = Matrix.column_vector([4,5,6])
- m.should be_an_instance_of(Matrix)
- m.should == Matrix[ [4],[5],[6] ]
- end
+ it "returns a single column Matrix when called with an Array" do
+ m = Matrix.column_vector([4,5,6])
+ m.should be_an_instance_of(Matrix)
+ m.should == Matrix[ [4],[5],[6] ]
+ end
- it "returns an empty Matrix when called with an empty Array" do
- m = Matrix.column_vector([])
- m.should be_an_instance_of(Matrix)
- m.row_size.should == 0
- m.column_size.should == 1
- end
+ it "returns an empty Matrix when called with an empty Array" do
+ m = Matrix.column_vector([])
+ m.should be_an_instance_of(Matrix)
+ m.row_size.should == 0
+ m.column_size.should == 1
+ end
- describe "for a subclass of Matrix" do
- it "returns an instance of that subclass" do
- MatrixSub.column_vector([4,5,6]).should be_an_instance_of(MatrixSub)
- end
+ describe "for a subclass of Matrix" do
+ it "returns an instance of that subclass" do
+ MatrixSub.column_vector([4,5,6]).should be_an_instance_of(MatrixSub)
end
end
end
diff --git a/spec/ruby/library/matrix/column_vectors_spec.rb b/spec/ruby/library/matrix/column_vectors_spec.rb
index 7bec095b9a..b0cb6f914c 100644
--- a/spec/ruby/library/matrix/column_vectors_spec.rb
+++ b/spec/ruby/library/matrix/column_vectors_spec.rb
@@ -1,29 +1,26 @@
require_relative '../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
+describe "Matrix#column_vectors" do
- describe "Matrix#column_vectors" do
-
- before :each do
- @vectors = Matrix[ [1,2], [3,4] ].column_vectors
- end
-
- it "returns an Array" do
- Matrix[ [1,2], [3,4] ].column_vectors.should be_an_instance_of(Array)
- end
+ before :each do
+ @vectors = Matrix[ [1,2], [3,4] ].column_vectors
+ end
- it "returns an Array of Vectors" do
- @vectors.all? {|v| v.should be_an_instance_of(Vector)}
- end
+ it "returns an Array" do
+ Matrix[ [1,2], [3,4] ].column_vectors.should be_an_instance_of(Array)
+ end
- it "returns each column as a Vector" do
- @vectors.should == [Vector[1,3], Vector[2,4]]
- end
+ it "returns an Array of Vectors" do
+ @vectors.all? {|v| v.should be_an_instance_of(Vector)}
+ end
- it "returns an empty Array for empty matrices" do
- Matrix[ [] ].column_vectors.should == []
- end
+ it "returns each column as a Vector" do
+ @vectors.should == [Vector[1,3], Vector[2,4]]
+ end
+ it "returns an empty Array for empty matrices" do
+ Matrix[ [] ].column_vectors.should == []
end
+
end
diff --git a/spec/ruby/library/matrix/columns_spec.rb b/spec/ruby/library/matrix/columns_spec.rb
index 757086c14b..3095fdd7af 100644
--- a/spec/ruby/library/matrix/columns_spec.rb
+++ b/spec/ruby/library/matrix/columns_spec.rb
@@ -1,45 +1,42 @@
require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require_relative 'fixtures/classes'
- require 'matrix'
-
- describe "Matrix.columns" do
- before :each do
- @a = [1, 2]
- @b = [3, 4]
- @m = Matrix.columns([@a, @b])
- end
+describe "Matrix.columns" do
+ before :each do
+ @a = [1, 2]
+ @b = [3, 4]
+ @m = Matrix.columns([@a, @b])
+ end
- it "creates a Matrix from argument columns" do
- @m.should be_an_instance_of(Matrix)
- @m.column(0).to_a.should == @a
- @m.column(1).to_a.should == @b
- end
+ it "creates a Matrix from argument columns" do
+ @m.should be_an_instance_of(Matrix)
+ @m.column(0).to_a.should == @a
+ @m.column(1).to_a.should == @b
+ end
- it "accepts Vectors as argument columns" do
- m = Matrix.columns([Vector[*@a], Vector[*@b]])
- m.should == @m
- m.column(0).to_a.should == @a
- m.column(1).to_a.should == @b
- end
+ it "accepts Vectors as argument columns" do
+ m = Matrix.columns([Vector[*@a], Vector[*@b]])
+ m.should == @m
+ m.column(0).to_a.should == @a
+ m.column(1).to_a.should == @b
+ end
- it "handles empty matrices" do
- e = Matrix.columns([])
- e.row_size.should == 0
- e.column_size.should == 0
- e.should == Matrix[]
+ it "handles empty matrices" do
+ e = Matrix.columns([])
+ e.row_size.should == 0
+ e.column_size.should == 0
+ e.should == Matrix[]
- v = Matrix.columns([[],[],[]])
- v.row_size.should == 0
- v.column_size.should == 3
- v.should == Matrix[[], [], []].transpose
- end
+ v = Matrix.columns([[],[],[]])
+ v.row_size.should == 0
+ v.column_size.should == 3
+ v.should == Matrix[[], [], []].transpose
+ end
- describe "for a subclass of Matrix" do
- it "returns an instance of that subclass" do
- MatrixSub.columns([[1]]).should be_an_instance_of(MatrixSub)
- end
+ describe "for a subclass of Matrix" do
+ it "returns an instance of that subclass" do
+ MatrixSub.columns([[1]]).should be_an_instance_of(MatrixSub)
end
end
end
diff --git a/spec/ruby/library/matrix/conj_spec.rb b/spec/ruby/library/matrix/conj_spec.rb
index a922580399..ecee95c255 100644
--- a/spec/ruby/library/matrix/conj_spec.rb
+++ b/spec/ruby/library/matrix/conj_spec.rb
@@ -1,9 +1,6 @@
require_relative '../../spec_helper'
+require_relative 'shared/conjugate'
-ruby_version_is ""..."3.1" do
- require_relative 'shared/conjugate'
-
- describe "Matrix#conj" do
- it_behaves_like :matrix_conjugate, :conj
- end
+describe "Matrix#conj" do
+ it_behaves_like :matrix_conjugate, :conj
end
diff --git a/spec/ruby/library/matrix/conjugate_spec.rb b/spec/ruby/library/matrix/conjugate_spec.rb
index b99792a24b..682bd41d94 100644
--- a/spec/ruby/library/matrix/conjugate_spec.rb
+++ b/spec/ruby/library/matrix/conjugate_spec.rb
@@ -1,9 +1,6 @@
require_relative '../../spec_helper'
+require_relative 'shared/conjugate'
-ruby_version_is ""..."3.1" do
- require_relative 'shared/conjugate'
-
- describe "Matrix#conjugate" do
- it_behaves_like :matrix_conjugate, :conjugate
- end
+describe "Matrix#conjugate" do
+ it_behaves_like :matrix_conjugate, :conjugate
end
diff --git a/spec/ruby/library/matrix/constructor_spec.rb b/spec/ruby/library/matrix/constructor_spec.rb
index d8224b4430..70d77babbb 100644
--- a/spec/ruby/library/matrix/constructor_spec.rb
+++ b/spec/ruby/library/matrix/constructor_spec.rb
@@ -1,68 +1,65 @@
require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require_relative 'fixtures/classes'
- require 'matrix'
+describe "Matrix.[]" do
- describe "Matrix.[]" do
-
- it "requires arrays as parameters" do
- -> { Matrix[5] }.should raise_error(TypeError)
- -> { Matrix[nil] }.should raise_error(TypeError)
- -> { Matrix[1..2] }.should raise_error(TypeError)
- -> { Matrix[[1, 2], 3] }.should raise_error(TypeError)
- end
+ it "requires arrays as parameters" do
+ -> { Matrix[5] }.should raise_error(TypeError)
+ -> { Matrix[nil] }.should raise_error(TypeError)
+ -> { Matrix[1..2] }.should raise_error(TypeError)
+ -> { Matrix[[1, 2], 3] }.should raise_error(TypeError)
+ end
- it "creates an empty Matrix with no arguments" do
- m = Matrix[]
- m.column_size.should == 0
- m.row_size.should == 0
- end
+ it "creates an empty Matrix with no arguments" do
+ m = Matrix[]
+ m.column_size.should == 0
+ m.row_size.should == 0
+ end
- it "raises for non-rectangular matrices" do
- ->{ Matrix[ [0], [0,1] ] }.should \
- raise_error(Matrix::ErrDimensionMismatch)
- ->{ Matrix[ [0,1], [0,1,2], [0,1] ]}.should \
- raise_error(Matrix::ErrDimensionMismatch)
- end
+ it "raises for non-rectangular matrices" do
+ ->{ Matrix[ [0], [0,1] ] }.should \
+ raise_error(Matrix::ErrDimensionMismatch)
+ ->{ Matrix[ [0,1], [0,1,2], [0,1] ]}.should \
+ raise_error(Matrix::ErrDimensionMismatch)
+ end
- it "accepts vector arguments" do
- a = Matrix[Vector[1, 2], Vector[3, 4]]
- a.should be_an_instance_of(Matrix)
- a.should == Matrix[ [1, 2], [3, 4] ]
- end
+ it "accepts vector arguments" do
+ a = Matrix[Vector[1, 2], Vector[3, 4]]
+ a.should be_an_instance_of(Matrix)
+ a.should == Matrix[ [1, 2], [3, 4] ]
+ end
- it "tries to calls :to_ary on arguments" do
- array = mock('ary')
- array.should_receive(:to_ary).and_return([1,2])
- Matrix[array, [3,4] ].should == Matrix[ [1,2], [3,4] ]
- end
+ it "tries to calls :to_ary on arguments" do
+ array = mock('ary')
+ array.should_receive(:to_ary).and_return([1,2])
+ Matrix[array, [3,4] ].should == Matrix[ [1,2], [3,4] ]
+ end
- it "returns a Matrix object" do
- Matrix[ [1] ].should be_an_instance_of(Matrix)
- end
+ it "returns a Matrix object" do
+ Matrix[ [1] ].should be_an_instance_of(Matrix)
+ end
- it "can create an nxn Matrix" do
- m = Matrix[ [20,30], [40.5, 9] ]
- m.row_size.should == 2
- m.column_size.should == 2
- m.column(0).should == Vector[20, 40.5]
- m.column(1).should == Vector[30, 9]
- m.row(0).should == Vector[20, 30]
- m.row(1).should == Vector[40.5, 9]
- end
+ it "can create an nxn Matrix" do
+ m = Matrix[ [20,30], [40.5, 9] ]
+ m.row_size.should == 2
+ m.column_size.should == 2
+ m.column(0).should == Vector[20, 40.5]
+ m.column(1).should == Vector[30, 9]
+ m.row(0).should == Vector[20, 30]
+ m.row(1).should == Vector[40.5, 9]
+ end
- it "can create a 0xn Matrix" do
- m = Matrix[ [], [], [] ]
- m.row_size.should == 3
- m.column_size.should == 0
- end
+ it "can create a 0xn Matrix" do
+ m = Matrix[ [], [], [] ]
+ m.row_size.should == 3
+ m.column_size.should == 0
+ end
- describe "for a subclass of Matrix" do
- it "returns an instance of that subclass" do
- MatrixSub[ [20,30], [40.5, 9] ].should be_an_instance_of(MatrixSub)
- end
+ describe "for a subclass of Matrix" do
+ it "returns an instance of that subclass" do
+ MatrixSub[ [20,30], [40.5, 9] ].should be_an_instance_of(MatrixSub)
end
end
end
diff --git a/spec/ruby/library/matrix/det_spec.rb b/spec/ruby/library/matrix/det_spec.rb
index 7d3d547735..aa7086cacf 100644
--- a/spec/ruby/library/matrix/det_spec.rb
+++ b/spec/ruby/library/matrix/det_spec.rb
@@ -1,10 +1,7 @@
require_relative '../../spec_helper'
+require_relative 'shared/determinant'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require_relative 'shared/determinant'
- require 'matrix'
-
- describe "Matrix#det" do
- it_behaves_like :determinant, :det
- end
+describe "Matrix#det" do
+ it_behaves_like :determinant, :det
end
diff --git a/spec/ruby/library/matrix/determinant_spec.rb b/spec/ruby/library/matrix/determinant_spec.rb
index bfd91fcf68..825c9907b1 100644
--- a/spec/ruby/library/matrix/determinant_spec.rb
+++ b/spec/ruby/library/matrix/determinant_spec.rb
@@ -1,10 +1,7 @@
require_relative '../../spec_helper'
+require_relative 'shared/determinant'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require_relative 'shared/determinant'
- require 'matrix'
-
- describe "Matrix#determinant" do
- it_behaves_like :determinant, :determinant
- end
+describe "Matrix#determinant" do
+ it_behaves_like :determinant, :determinant
end
diff --git a/spec/ruby/library/matrix/diagonal_spec.rb b/spec/ruby/library/matrix/diagonal_spec.rb
index 8c82433fde..ef9738e73e 100644
--- a/spec/ruby/library/matrix/diagonal_spec.rb
+++ b/spec/ruby/library/matrix/diagonal_spec.rb
@@ -1,75 +1,72 @@
require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require_relative 'fixtures/classes'
- require 'matrix'
-
- describe "Matrix.diagonal" do
- before :each do
- @m = Matrix.diagonal(10, 11, 12, 13, 14)
- end
+describe "Matrix.diagonal" do
+ before :each do
+ @m = Matrix.diagonal(10, 11, 12, 13, 14)
+ end
- it "returns an object of type Matrix" do
- @m.should be_kind_of(Matrix)
- end
+ it "returns an object of type Matrix" do
+ @m.should be_kind_of(Matrix)
+ end
- it "returns a square Matrix of the right size" do
- @m.column_size.should == 5
- @m.row_size.should == 5
- end
+ it "returns a square Matrix of the right size" do
+ @m.column_size.should == 5
+ @m.row_size.should == 5
+ end
- it "sets the diagonal to the arguments" do
- (0..4).each do |i|
- @m[i, i].should == i + 10
- end
+ it "sets the diagonal to the arguments" do
+ (0..4).each do |i|
+ @m[i, i].should == i + 10
end
+ end
- it "fills all non-diagonal cells with 0" do
- (0..4).each do |i|
- (0..4).each do |j|
- if i != j
- @m[i, j].should == 0
- end
+ it "fills all non-diagonal cells with 0" do
+ (0..4).each do |i|
+ (0..4).each do |j|
+ if i != j
+ @m[i, j].should == 0
end
end
end
+ end
- describe "for a subclass of Matrix" do
- it "returns an instance of that subclass" do
- MatrixSub.diagonal(1).should be_an_instance_of(MatrixSub)
- end
+ describe "for a subclass of Matrix" do
+ it "returns an instance of that subclass" do
+ MatrixSub.diagonal(1).should be_an_instance_of(MatrixSub)
end
end
+end
- describe "Matrix.diagonal?" do
- it "returns true for a diagonal Matrix" do
- Matrix.diagonal([1, 2, 3]).diagonal?.should be_true
- end
+describe "Matrix.diagonal?" do
+ it "returns true for a diagonal Matrix" do
+ Matrix.diagonal([1, 2, 3]).diagonal?.should be_true
+ end
- it "returns true for a zero square Matrix" do
- Matrix.zero(3).diagonal?.should be_true
- end
+ it "returns true for a zero square Matrix" do
+ Matrix.zero(3).diagonal?.should be_true
+ end
- it "returns false for a non diagonal square Matrix" do
- Matrix[[0, 1], [0, 0]].diagonal?.should be_false
- Matrix[[1, 2, 3], [1, 2, 3], [1, 2, 3]].diagonal?.should be_false
- end
+ it "returns false for a non diagonal square Matrix" do
+ Matrix[[0, 1], [0, 0]].diagonal?.should be_false
+ Matrix[[1, 2, 3], [1, 2, 3], [1, 2, 3]].diagonal?.should be_false
+ end
- it "returns true for an empty 0x0 matrix" do
- Matrix.empty(0,0).diagonal?.should be_true
- end
+ it "returns true for an empty 0x0 matrix" do
+ Matrix.empty(0,0).diagonal?.should be_true
+ end
- it "raises an error for rectangular matrices" do
- [
- Matrix[[0], [0]],
- Matrix[[0, 0]],
- Matrix.empty(0, 2),
- Matrix.empty(2, 0),
- ].each do |rectangular_matrix|
- -> {
- rectangular_matrix.diagonal?
- }.should raise_error(Matrix::ErrDimensionMismatch)
- end
+ it "raises an error for rectangular matrices" do
+ [
+ Matrix[[0], [0]],
+ Matrix[[0, 0]],
+ Matrix.empty(0, 2),
+ Matrix.empty(2, 0),
+ ].each do |rectangular_matrix|
+ -> {
+ rectangular_matrix.diagonal?
+ }.should raise_error(Matrix::ErrDimensionMismatch)
end
end
end
diff --git a/spec/ruby/library/matrix/divide_spec.rb b/spec/ruby/library/matrix/divide_spec.rb
index 68e6f1fde5..2e3bb85bf6 100644
--- a/spec/ruby/library/matrix/divide_spec.rb
+++ b/spec/ruby/library/matrix/divide_spec.rb
@@ -1,57 +1,54 @@
require_relative '../../spec_helper'
+require_relative 'spec_helper'
+require_relative 'fixtures/classes'
+require 'matrix'
+
+describe "Matrix#/" do
+ before :each do
+ @a = Matrix[ [1, 2], [3, 4] ]
+ @b = Matrix[ [4, 5], [6, 7] ]
+ @c = Matrix[ [1.2, 2.4], [3.6, 4.8] ]
+ end
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
- require_relative 'fixtures/classes'
- require 'matrix'
+ it "returns the result of dividing self by another Matrix" do
+ (@a / @b).should be_close_to_matrix([[2.5, -1.5], [1.5, -0.5]])
+ end
- describe "Matrix#/" do
- before :each do
- @a = Matrix[ [1, 2], [3, 4] ]
- @b = Matrix[ [4, 5], [6, 7] ]
- @c = Matrix[ [1.2, 2.4], [3.6, 4.8] ]
+ # Guard against the Mathn library
+ guard -> { !defined?(Math.rsqrt) } do
+ it "returns the result of dividing self by a Fixnum" do
+ (@a / 2).should == Matrix[ [0, 1], [1, 2] ]
end
- it "returns the result of dividing self by another Matrix" do
- (@a / @b).should be_close_to_matrix([[2.5, -1.5], [1.5, -0.5]])
- end
-
- # Guard against the Mathn library
- guard -> { !defined?(Math.rsqrt) } do
- it "returns the result of dividing self by a Fixnum" do
- (@a / 2).should == Matrix[ [0, 1], [1, 2] ]
- end
-
- it "returns the result of dividing self by a Bignum" do
- (@a / bignum_value).should == Matrix[ [0, 0], [0, 0] ]
- end
+ it "returns the result of dividing self by a Bignum" do
+ (@a / bignum_value).should == Matrix[ [0, 0], [0, 0] ]
end
+ end
- it "returns the result of dividing self by a Float" do
- (@c / 1.2).should == Matrix[ [1, 2], [3, 4] ]
- end
+ it "returns the result of dividing self by a Float" do
+ (@c / 1.2).should == Matrix[ [1, 2], [3, 4] ]
+ end
- it "raises a Matrix::ErrDimensionMismatch if the matrices are different sizes" do
- -> { @a / Matrix[ [1] ] }.should raise_error(Matrix::ErrDimensionMismatch)
- end
+ it "raises a Matrix::ErrDimensionMismatch if the matrices are different sizes" do
+ -> { @a / Matrix[ [1] ] }.should raise_error(Matrix::ErrDimensionMismatch)
+ end
- it "returns an instance of Matrix" do
- (@a / @b).should be_kind_of(Matrix)
- end
+ it "returns an instance of Matrix" do
+ (@a / @b).should be_kind_of(Matrix)
+ end
- describe "for a subclass of Matrix" do
- it "returns an instance of that subclass" do
- m = MatrixSub.ins
- (m/m).should be_an_instance_of(MatrixSub)
- (m/1).should be_an_instance_of(MatrixSub)
- end
+ describe "for a subclass of Matrix" do
+ it "returns an instance of that subclass" do
+ m = MatrixSub.ins
+ (m/m).should be_an_instance_of(MatrixSub)
+ (m/1).should be_an_instance_of(MatrixSub)
end
+ end
- it "raises a TypeError if other is of wrong type" do
- -> { @a / nil }.should raise_error(TypeError)
- -> { @a / "a" }.should raise_error(TypeError)
- -> { @a / [ [1, 2] ] }.should raise_error(TypeError)
- -> { @a / Object.new }.should raise_error(TypeError)
- end
+ it "raises a TypeError if other is of wrong type" do
+ -> { @a / nil }.should raise_error(TypeError)
+ -> { @a / "a" }.should raise_error(TypeError)
+ -> { @a / [ [1, 2] ] }.should raise_error(TypeError)
+ -> { @a / Object.new }.should raise_error(TypeError)
end
end
diff --git a/spec/ruby/library/matrix/each_spec.rb b/spec/ruby/library/matrix/each_spec.rb
index d2b13c80b6..f3b0f01867 100644
--- a/spec/ruby/library/matrix/each_spec.rb
+++ b/spec/ruby/library/matrix/each_spec.rb
@@ -1,77 +1,74 @@
require_relative '../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
-
- describe "Matrix#each" do
- before :all do
- @m = Matrix[ [1, 2, 3], [4, 5, 6] ]
- @result = (1..6).to_a
- end
+describe "Matrix#each" do
+ before :all do
+ @m = Matrix[ [1, 2, 3], [4, 5, 6] ]
+ @result = (1..6).to_a
+ end
- it "returns an Enumerator when called without a block" do
- enum = @m.each
- enum.should be_an_instance_of(Enumerator)
- enum.to_a.should == @result
- end
+ it "returns an Enumerator when called without a block" do
+ enum = @m.each
+ enum.should be_an_instance_of(Enumerator)
+ enum.to_a.should == @result
+ end
- it "returns self" do
- @m.each{}.should equal(@m)
- end
+ it "returns self" do
+ @m.each{}.should equal(@m)
+ end
- it "yields the elements starting with the those of the first row" do
- a = []
- @m.each {|x| a << x}
- a.should == @result
- end
+ it "yields the elements starting with the those of the first row" do
+ a = []
+ @m.each {|x| a << x}
+ a.should == @result
end
+end
- describe "Matrix#each with an argument" do
- before :all do
- @m = Matrix[ [1, 2, 3, 4], [5, 6, 7, 8] ]
- @t = Matrix[ [1, 2], [3, 4], [5, 6], [7, 8] ]
- end
+describe "Matrix#each with an argument" do
+ before :all do
+ @m = Matrix[ [1, 2, 3, 4], [5, 6, 7, 8] ]
+ @t = Matrix[ [1, 2], [3, 4], [5, 6], [7, 8] ]
+ end
- it "raises an ArgumentError for unrecognized argument" do
- -> {
- @m.each("all"){}
- }.should raise_error(ArgumentError)
- -> {
- @m.each(nil){}
- }.should raise_error(ArgumentError)
- -> {
- @m.each(:left){}
- }.should raise_error(ArgumentError)
- end
+ it "raises an ArgumentError for unrecognized argument" do
+ -> {
+ @m.each("all"){}
+ }.should raise_error(ArgumentError)
+ -> {
+ @m.each(nil){}
+ }.should raise_error(ArgumentError)
+ -> {
+ @m.each(:left){}
+ }.should raise_error(ArgumentError)
+ end
- it "yields the rights elements when passed :diagonal" do
- @m.each(:diagonal).to_a.should == [1, 6]
- @t.each(:diagonal).to_a.should == [1, 4]
- end
+ it "yields the rights elements when passed :diagonal" do
+ @m.each(:diagonal).to_a.should == [1, 6]
+ @t.each(:diagonal).to_a.should == [1, 4]
+ end
- it "yields the rights elements when passed :off_diagonal" do
- @m.each(:off_diagonal).to_a.should == [2, 3, 4, 5, 7, 8]
- @t.each(:off_diagonal).to_a.should == [2, 3, 5, 6, 7, 8]
- end
+ it "yields the rights elements when passed :off_diagonal" do
+ @m.each(:off_diagonal).to_a.should == [2, 3, 4, 5, 7, 8]
+ @t.each(:off_diagonal).to_a.should == [2, 3, 5, 6, 7, 8]
+ end
- it "yields the rights elements when passed :lower" do
- @m.each(:lower).to_a.should == [1, 5, 6]
- @t.each(:lower).to_a.should == [1, 3, 4, 5, 6, 7, 8]
- end
+ it "yields the rights elements when passed :lower" do
+ @m.each(:lower).to_a.should == [1, 5, 6]
+ @t.each(:lower).to_a.should == [1, 3, 4, 5, 6, 7, 8]
+ end
- it "yields the rights elements when passed :strict_lower" do
- @m.each(:strict_lower).to_a.should == [5]
- @t.each(:strict_lower).to_a.should == [3, 5, 6, 7, 8]
- end
+ it "yields the rights elements when passed :strict_lower" do
+ @m.each(:strict_lower).to_a.should == [5]
+ @t.each(:strict_lower).to_a.should == [3, 5, 6, 7, 8]
+ end
- it "yields the rights elements when passed :strict_upper" do
- @m.each(:strict_upper).to_a.should == [2, 3, 4, 7, 8]
- @t.each(:strict_upper).to_a.should == [2]
- end
+ it "yields the rights elements when passed :strict_upper" do
+ @m.each(:strict_upper).to_a.should == [2, 3, 4, 7, 8]
+ @t.each(:strict_upper).to_a.should == [2]
+ end
- it "yields the rights elements when passed :upper" do
- @m.each(:upper).to_a.should == [1, 2, 3, 4, 6, 7, 8]
- @t.each(:upper).to_a.should == [1, 2, 4]
- end
+ it "yields the rights elements when passed :upper" do
+ @m.each(:upper).to_a.should == [1, 2, 3, 4, 6, 7, 8]
+ @t.each(:upper).to_a.should == [1, 2, 4]
end
end
diff --git a/spec/ruby/library/matrix/each_with_index_spec.rb b/spec/ruby/library/matrix/each_with_index_spec.rb
index 59549f77b7..a005b88621 100644
--- a/spec/ruby/library/matrix/each_with_index_spec.rb
+++ b/spec/ruby/library/matrix/each_with_index_spec.rb
@@ -1,84 +1,81 @@
require_relative '../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
-
- describe "Matrix#each_with_index" do
- before :all do
- @m = Matrix[ [1, 2, 3], [4, 5, 6] ]
- @result = [
- [1, 0, 0],
- [2, 0, 1],
- [3, 0, 2],
- [4, 1, 0],
- [5, 1, 1],
- [6, 1, 2]
- ]
- end
+describe "Matrix#each_with_index" do
+ before :all do
+ @m = Matrix[ [1, 2, 3], [4, 5, 6] ]
+ @result = [
+ [1, 0, 0],
+ [2, 0, 1],
+ [3, 0, 2],
+ [4, 1, 0],
+ [5, 1, 1],
+ [6, 1, 2]
+ ]
+ end
- it "returns an Enumerator when called without a block" do
- enum = @m.each_with_index
- enum.should be_an_instance_of(Enumerator)
- enum.to_a.should == @result
- end
+ it "returns an Enumerator when called without a block" do
+ enum = @m.each_with_index
+ enum.should be_an_instance_of(Enumerator)
+ enum.to_a.should == @result
+ end
- it "returns self" do
- @m.each_with_index{}.should equal(@m)
- end
+ it "returns self" do
+ @m.each_with_index{}.should equal(@m)
+ end
- it "yields the elements starting with the those of the first row" do
- a = []
- @m.each_with_index {|x, r, c| a << [x, r, c]}
- a.should == @result
- end
+ it "yields the elements starting with the those of the first row" do
+ a = []
+ @m.each_with_index {|x, r, c| a << [x, r, c]}
+ a.should == @result
end
+end
- describe "Matrix#each_with_index with an argument" do
- before :all do
- @m = Matrix[ [1, 2, 3, 4], [5, 6, 7, 8] ]
- @t = Matrix[ [1, 2], [3, 4], [5, 6], [7, 8] ]
- end
+describe "Matrix#each_with_index with an argument" do
+ before :all do
+ @m = Matrix[ [1, 2, 3, 4], [5, 6, 7, 8] ]
+ @t = Matrix[ [1, 2], [3, 4], [5, 6], [7, 8] ]
+ end
- it "raises an ArgumentError for unrecognized argument" do
- -> {
- @m.each_with_index("all"){}
- }.should raise_error(ArgumentError)
- -> {
- @m.each_with_index(nil){}
- }.should raise_error(ArgumentError)
- -> {
- @m.each_with_index(:left){}
- }.should raise_error(ArgumentError)
- end
+ it "raises an ArgumentError for unrecognized argument" do
+ -> {
+ @m.each_with_index("all"){}
+ }.should raise_error(ArgumentError)
+ -> {
+ @m.each_with_index(nil){}
+ }.should raise_error(ArgumentError)
+ -> {
+ @m.each_with_index(:left){}
+ }.should raise_error(ArgumentError)
+ end
- it "yields the rights elements when passed :diagonal" do
- @m.each_with_index(:diagonal).to_a.should == [[1, 0, 0], [6, 1, 1]]
- @t.each_with_index(:diagonal).to_a.should == [[1, 0, 0], [4, 1, 1]]
- end
+ it "yields the rights elements when passed :diagonal" do
+ @m.each_with_index(:diagonal).to_a.should == [[1, 0, 0], [6, 1, 1]]
+ @t.each_with_index(:diagonal).to_a.should == [[1, 0, 0], [4, 1, 1]]
+ end
- it "yields the rights elements when passed :off_diagonal" do
- @m.each_with_index(:off_diagonal).to_a.should == [[2, 0, 1], [3, 0, 2], [4, 0, 3], [5, 1, 0], [7, 1, 2], [8, 1, 3]]
- @t.each_with_index(:off_diagonal).to_a.should == [[2, 0, 1], [3, 1, 0], [5, 2, 0], [6, 2, 1], [7, 3, 0], [8, 3, 1]]
- end
+ it "yields the rights elements when passed :off_diagonal" do
+ @m.each_with_index(:off_diagonal).to_a.should == [[2, 0, 1], [3, 0, 2], [4, 0, 3], [5, 1, 0], [7, 1, 2], [8, 1, 3]]
+ @t.each_with_index(:off_diagonal).to_a.should == [[2, 0, 1], [3, 1, 0], [5, 2, 0], [6, 2, 1], [7, 3, 0], [8, 3, 1]]
+ end
- it "yields the rights elements when passed :lower" do
- @m.each_with_index(:lower).to_a.should == [[1, 0, 0], [5, 1, 0], [6, 1, 1]]
- @t.each_with_index(:lower).to_a.should == [[1, 0, 0], [3, 1, 0], [4, 1, 1], [5, 2, 0], [6, 2, 1], [7, 3, 0], [8, 3, 1]]
- end
+ it "yields the rights elements when passed :lower" do
+ @m.each_with_index(:lower).to_a.should == [[1, 0, 0], [5, 1, 0], [6, 1, 1]]
+ @t.each_with_index(:lower).to_a.should == [[1, 0, 0], [3, 1, 0], [4, 1, 1], [5, 2, 0], [6, 2, 1], [7, 3, 0], [8, 3, 1]]
+ end
- it "yields the rights elements when passed :strict_lower" do
- @m.each_with_index(:strict_lower).to_a.should == [[5, 1, 0]]
- @t.each_with_index(:strict_lower).to_a.should == [[3, 1, 0], [5, 2, 0], [6, 2, 1], [7, 3, 0], [8, 3, 1]]
- end
+ it "yields the rights elements when passed :strict_lower" do
+ @m.each_with_index(:strict_lower).to_a.should == [[5, 1, 0]]
+ @t.each_with_index(:strict_lower).to_a.should == [[3, 1, 0], [5, 2, 0], [6, 2, 1], [7, 3, 0], [8, 3, 1]]
+ end
- it "yields the rights elements when passed :strict_upper" do
- @m.each_with_index(:strict_upper).to_a.should == [[2, 0, 1], [3, 0, 2], [4, 0, 3], [7, 1, 2], [8, 1, 3]]
- @t.each_with_index(:strict_upper).to_a.should == [[2, 0, 1]]
- end
+ it "yields the rights elements when passed :strict_upper" do
+ @m.each_with_index(:strict_upper).to_a.should == [[2, 0, 1], [3, 0, 2], [4, 0, 3], [7, 1, 2], [8, 1, 3]]
+ @t.each_with_index(:strict_upper).to_a.should == [[2, 0, 1]]
+ end
- it "yields the rights elements when passed :upper" do
- @m.each_with_index(:upper).to_a.should == [[1, 0, 0], [2, 0, 1], [3, 0, 2], [4, 0, 3], [6, 1, 1], [7, 1, 2], [8, 1, 3]]
- @t.each_with_index(:upper).to_a.should == [[1, 0, 0], [2, 0, 1], [4, 1, 1]]
- end
+ it "yields the rights elements when passed :upper" do
+ @m.each_with_index(:upper).to_a.should == [[1, 0, 0], [2, 0, 1], [3, 0, 2], [4, 0, 3], [6, 1, 1], [7, 1, 2], [8, 1, 3]]
+ @t.each_with_index(:upper).to_a.should == [[1, 0, 0], [2, 0, 1], [4, 1, 1]]
end
end
diff --git a/spec/ruby/library/matrix/eigenvalue_decomposition/eigenvalue_matrix_spec.rb b/spec/ruby/library/matrix/eigenvalue_decomposition/eigenvalue_matrix_spec.rb
index f9ffca0123..67f9dd1c19 100644
--- a/spec/ruby/library/matrix/eigenvalue_decomposition/eigenvalue_matrix_spec.rb
+++ b/spec/ruby/library/matrix/eigenvalue_decomposition/eigenvalue_matrix_spec.rb
@@ -1,12 +1,9 @@
require_relative '../../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
-
- describe "Matrix::EigenvalueDecomposition#eigenvalue_matrix" do
- it "returns a diagonal matrix with the eigenvalues on the diagonal" do
- Matrix[[14, 16], [-6, -6]].eigensystem.eigenvalue_matrix.should == Matrix[[6, 0],[0, 2]]
- Matrix[[1, 1], [-1, 1]].eigensystem.eigenvalue_matrix.should == Matrix[[Complex(1,1), 0],[0, Complex(1,-1)]]
- end
+describe "Matrix::EigenvalueDecomposition#eigenvalue_matrix" do
+ it "returns a diagonal matrix with the eigenvalues on the diagonal" do
+ Matrix[[14, 16], [-6, -6]].eigensystem.eigenvalue_matrix.should == Matrix[[6, 0],[0, 2]]
+ Matrix[[1, 1], [-1, 1]].eigensystem.eigenvalue_matrix.should == Matrix[[Complex(1,1), 0],[0, Complex(1,-1)]]
end
end
diff --git a/spec/ruby/library/matrix/eigenvalue_decomposition/eigenvalues_spec.rb b/spec/ruby/library/matrix/eigenvalue_decomposition/eigenvalues_spec.rb
index 650d43d90f..7552b7616c 100644
--- a/spec/ruby/library/matrix/eigenvalue_decomposition/eigenvalues_spec.rb
+++ b/spec/ruby/library/matrix/eigenvalue_decomposition/eigenvalues_spec.rb
@@ -1,25 +1,22 @@
require_relative '../../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
-
- describe "Matrix::EigenvalueDecomposition#eigenvalues" do
- it "returns an array of complex eigenvalues for a rotation matrix" do
- Matrix[[ 1, 1],
- [-1, 1]].eigensystem.eigenvalues.sort_by{|v| v.imag}.should ==
- [ Complex(1, -1), Complex(1, 1)]
- end
+describe "Matrix::EigenvalueDecomposition#eigenvalues" do
+ it "returns an array of complex eigenvalues for a rotation matrix" do
+ Matrix[[ 1, 1],
+ [-1, 1]].eigensystem.eigenvalues.sort_by{|v| v.imag}.should ==
+ [ Complex(1, -1), Complex(1, 1)]
+ end
- it "returns an array of real eigenvalues for a symmetric matrix" do
- Matrix[[1, 2],
- [2, 1]].eigensystem.eigenvalues.sort.map!{|x| x.round(10)}.should ==
- [ -1, 3 ]
- end
+ it "returns an array of real eigenvalues for a symmetric matrix" do
+ Matrix[[1, 2],
+ [2, 1]].eigensystem.eigenvalues.sort.map!{|x| x.round(10)}.should ==
+ [ -1, 3 ]
+ end
- it "returns an array of real eigenvalues for a matrix" do
- Matrix[[14, 16],
- [-6, -6]].eigensystem.eigenvalues.sort.map!{|x| x.round(10)}.should ==
- [ 2, 6 ]
- end
+ it "returns an array of real eigenvalues for a matrix" do
+ Matrix[[14, 16],
+ [-6, -6]].eigensystem.eigenvalues.sort.map!{|x| x.round(10)}.should ==
+ [ 2, 6 ]
end
end
diff --git a/spec/ruby/library/matrix/eigenvalue_decomposition/eigenvector_matrix_spec.rb b/spec/ruby/library/matrix/eigenvalue_decomposition/eigenvector_matrix_spec.rb
index 57299ce69e..09f229ee15 100644
--- a/spec/ruby/library/matrix/eigenvalue_decomposition/eigenvector_matrix_spec.rb
+++ b/spec/ruby/library/matrix/eigenvalue_decomposition/eigenvector_matrix_spec.rb
@@ -1,23 +1,20 @@
require_relative '../../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
-
- describe "Matrix::EigenvalueDecomposition#eigenvector_matrix" do
- it "returns a complex eigenvector matrix given a rotation matrix" do
- # Fix me: should test for linearity, not for equality
- Matrix[[ 1, 1],
- [-1, 1]].eigensystem.eigenvector_matrix.should ==
- Matrix[[1, 1],
- [Complex(0, 1), Complex(0, -1)]]
- end
+describe "Matrix::EigenvalueDecomposition#eigenvector_matrix" do
+ it "returns a complex eigenvector matrix given a rotation matrix" do
+ # Fix me: should test for linearity, not for equality
+ Matrix[[ 1, 1],
+ [-1, 1]].eigensystem.eigenvector_matrix.should ==
+ Matrix[[1, 1],
+ [Complex(0, 1), Complex(0, -1)]]
+ end
- it "returns an real eigenvector matrix for a symmetric matrix" do
- # Fix me: should test for linearity, not for equality
- Matrix[[1, 2],
- [2, 1]].eigensystem.eigenvector_matrix.should ==
- Matrix[[0.7071067811865475, 0.7071067811865475],
- [-0.7071067811865475, 0.7071067811865475]]
- end
+ it "returns an real eigenvector matrix for a symmetric matrix" do
+ # Fix me: should test for linearity, not for equality
+ Matrix[[1, 2],
+ [2, 1]].eigensystem.eigenvector_matrix.should ==
+ Matrix[[0.7071067811865475, 0.7071067811865475],
+ [-0.7071067811865475, 0.7071067811865475]]
end
end
diff --git a/spec/ruby/library/matrix/eigenvalue_decomposition/eigenvectors_spec.rb b/spec/ruby/library/matrix/eigenvalue_decomposition/eigenvectors_spec.rb
index 54e6857bf3..2b6ce74ea8 100644
--- a/spec/ruby/library/matrix/eigenvalue_decomposition/eigenvectors_spec.rb
+++ b/spec/ruby/library/matrix/eigenvalue_decomposition/eigenvectors_spec.rb
@@ -1,25 +1,22 @@
require_relative '../../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
-
- describe "Matrix::EigenvalueDecomposition#eigenvectors" do
- it "returns an array of complex eigenvectors for a rotation matrix" do
- # Fix me: should test for linearity, not for equality
- Matrix[[ 1, 1],
- [-1, 1]].eigensystem.eigenvectors.should ==
- [ Vector[1, Complex(0, 1)],
- Vector[1, Complex(0, -1)]
- ]
- end
+describe "Matrix::EigenvalueDecomposition#eigenvectors" do
+ it "returns an array of complex eigenvectors for a rotation matrix" do
+ # Fix me: should test for linearity, not for equality
+ Matrix[[ 1, 1],
+ [-1, 1]].eigensystem.eigenvectors.should ==
+ [ Vector[1, Complex(0, 1)],
+ Vector[1, Complex(0, -1)]
+ ]
+ end
- it "returns an array of real eigenvectors for a symmetric matrix" do
- # Fix me: should test for linearity, not for equality
- Matrix[[1, 2],
- [2, 1]].eigensystem.eigenvectors.should ==
- [ Vector[0.7071067811865475, -0.7071067811865475],
- Vector[0.7071067811865475, 0.7071067811865475]
- ]
- end
+ it "returns an array of real eigenvectors for a symmetric matrix" do
+ # Fix me: should test for linearity, not for equality
+ Matrix[[1, 2],
+ [2, 1]].eigensystem.eigenvectors.should ==
+ [ Vector[0.7071067811865475, -0.7071067811865475],
+ Vector[0.7071067811865475, 0.7071067811865475]
+ ]
end
end
diff --git a/spec/ruby/library/matrix/eigenvalue_decomposition/initialize_spec.rb b/spec/ruby/library/matrix/eigenvalue_decomposition/initialize_spec.rb
index 02aad65c4b..8438f63133 100644
--- a/spec/ruby/library/matrix/eigenvalue_decomposition/initialize_spec.rb
+++ b/spec/ruby/library/matrix/eigenvalue_decomposition/initialize_spec.rb
@@ -1,27 +1,24 @@
require_relative '../../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
-
- describe "Matrix::EigenvalueDecomposition#initialize" do
- it "raises an error if argument is not a matrix" do
- -> {
- Matrix::EigenvalueDecomposition.new([[]])
- }.should raise_error(TypeError)
- -> {
- Matrix::EigenvalueDecomposition.new(42)
- }.should raise_error(TypeError)
- end
+describe "Matrix::EigenvalueDecomposition#initialize" do
+ it "raises an error if argument is not a matrix" do
+ -> {
+ Matrix::EigenvalueDecomposition.new([[]])
+ }.should raise_error(TypeError)
+ -> {
+ Matrix::EigenvalueDecomposition.new(42)
+ }.should raise_error(TypeError)
+ end
- it "raises an error if matrix is not square" do
- -> {
- Matrix::EigenvalueDecomposition.new(Matrix[[1, 2]])
- }.should raise_error(Matrix::ErrDimensionMismatch)
- end
+ it "raises an error if matrix is not square" do
+ -> {
+ Matrix::EigenvalueDecomposition.new(Matrix[[1, 2]])
+ }.should raise_error(Matrix::ErrDimensionMismatch)
+ end
- it "never hangs" do
- m = Matrix[ [0,0,0,0,0], [0,0,0,0,1], [0,0,0,1,0], [1,1,0,0,1], [1,0,1,0,1] ]
- Matrix::EigenvalueDecomposition.new(m).should_not == "infinite loop"
- end
+ it "never hangs" do
+ m = Matrix[ [0,0,0,0,0], [0,0,0,0,1], [0,0,0,1,0], [1,1,0,0,1], [1,0,1,0,1] ]
+ Matrix::EigenvalueDecomposition.new(m).should_not == "infinite loop"
end
end
diff --git a/spec/ruby/library/matrix/eigenvalue_decomposition/to_a_spec.rb b/spec/ruby/library/matrix/eigenvalue_decomposition/to_a_spec.rb
index 352ae274b4..8be41a5720 100644
--- a/spec/ruby/library/matrix/eigenvalue_decomposition/to_a_spec.rb
+++ b/spec/ruby/library/matrix/eigenvalue_decomposition/to_a_spec.rb
@@ -1,21 +1,18 @@
require_relative '../../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
-
- describe "Matrix::EigenvalueDecomposition#to_a" do
- before :each do
- @a = Matrix[[14, 16], [-6, -6]]
- @e = Matrix::EigenvalueDecomposition.new(@a)
- end
+describe "Matrix::EigenvalueDecomposition#to_a" do
+ before :each do
+ @a = Matrix[[14, 16], [-6, -6]]
+ @e = Matrix::EigenvalueDecomposition.new(@a)
+ end
- it "returns an array of with [V, D, V.inv]" do
- @e.to_a.should == [@e.v, @e.d, @e.v_inv]
- end
+ it "returns an array of with [V, D, V.inv]" do
+ @e.to_a.should == [@e.v, @e.d, @e.v_inv]
+ end
- it "returns a factorization" do
- v, d, v_inv = @e.to_a
- (v * d * v_inv).map{|e| e.round(10)}.should == @a
- end
+ it "returns a factorization" do
+ v, d, v_inv = @e.to_a
+ (v * d * v_inv).map{|e| e.round(10)}.should == @a
end
end
diff --git a/spec/ruby/library/matrix/element_reference_spec.rb b/spec/ruby/library/matrix/element_reference_spec.rb
index 286ab851bd..b950d1c391 100644
--- a/spec/ruby/library/matrix/element_reference_spec.rb
+++ b/spec/ruby/library/matrix/element_reference_spec.rb
@@ -1,26 +1,23 @@
require_relative '../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
+describe "Matrix#[]" do
- describe "Matrix#[]" do
-
- before :all do
- @m = Matrix[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]]
- end
+ before :all do
+ @m = Matrix[[0, 1, 2], [3, 4, 5], [6, 7, 8], [9, 10, 11]]
+ end
- it "returns element at (i, j)" do
- (0..3).each do |i|
- (0..2).each do |j|
- @m[i, j].should == (i * 3) + j
- end
+ it "returns element at (i, j)" do
+ (0..3).each do |i|
+ (0..2).each do |j|
+ @m[i, j].should == (i * 3) + j
end
end
+ end
- it "returns nil for an invalid index pair" do
- @m[8,1].should be_nil
- @m[1,8].should be_nil
- end
-
+ it "returns nil for an invalid index pair" do
+ @m[8,1].should be_nil
+ @m[1,8].should be_nil
end
+
end
diff --git a/spec/ruby/library/matrix/empty_spec.rb b/spec/ruby/library/matrix/empty_spec.rb
index 0b5d5ffe0f..5f294711db 100644
--- a/spec/ruby/library/matrix/empty_spec.rb
+++ b/spec/ruby/library/matrix/empty_spec.rb
@@ -1,71 +1,68 @@
require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require_relative 'fixtures/classes'
- require 'matrix'
-
- describe "Matrix#empty?" do
- it "returns true when the Matrix is empty" do
- Matrix[ ].empty?.should be_true
- Matrix[ [], [], [] ].empty?.should be_true
- Matrix[ [], [], [] ].transpose.empty?.should be_true
- end
-
- it "returns false when the Matrix has elements" do
- Matrix[ [1, 2] ].empty?.should be_false
- Matrix[ [1], [2] ].empty?.should be_false
- end
+describe "Matrix#empty?" do
+ it "returns true when the Matrix is empty" do
+ Matrix[ ].empty?.should be_true
+ Matrix[ [], [], [] ].empty?.should be_true
+ Matrix[ [], [], [] ].transpose.empty?.should be_true
+ end
- it "doesn't accept any parameter" do
- ->{
- Matrix[ [1, 2] ].empty?(42)
- }.should raise_error(ArgumentError)
- end
+ it "returns false when the Matrix has elements" do
+ Matrix[ [1, 2] ].empty?.should be_false
+ Matrix[ [1], [2] ].empty?.should be_false
end
- describe "Matrix.empty" do
- it "returns an empty matrix of the requested size" do
- m = Matrix.empty(3, 0)
- m.row_size.should == 3
- m.column_size.should == 0
+ it "doesn't accept any parameter" do
+ ->{
+ Matrix[ [1, 2] ].empty?(42)
+ }.should raise_error(ArgumentError)
+ end
+end
- m = Matrix.empty(0, 3)
- m.row_size.should == 0
- m.column_size.should == 3
- end
+describe "Matrix.empty" do
+ it "returns an empty matrix of the requested size" do
+ m = Matrix.empty(3, 0)
+ m.row_size.should == 3
+ m.column_size.should == 0
- it "has arguments defaulting to 0" do
- Matrix.empty.should == Matrix.empty(0, 0)
- Matrix.empty(42).should == Matrix.empty(42, 0)
- end
+ m = Matrix.empty(0, 3)
+ m.row_size.should == 0
+ m.column_size.should == 3
+ end
- it "does not accept more than two parameters" do
- ->{
- Matrix.empty(1, 2, 3)
- }.should raise_error(ArgumentError)
- end
+ it "has arguments defaulting to 0" do
+ Matrix.empty.should == Matrix.empty(0, 0)
+ Matrix.empty(42).should == Matrix.empty(42, 0)
+ end
- it "raises an error if both dimensions are > 0" do
- ->{
- Matrix.empty(1, 2)
- }.should raise_error(ArgumentError)
- end
+ it "does not accept more than two parameters" do
+ ->{
+ Matrix.empty(1, 2, 3)
+ }.should raise_error(ArgumentError)
+ end
- it "raises an error if any dimension is < 0" do
- ->{
- Matrix.empty(-2, 0)
- }.should raise_error(ArgumentError)
+ it "raises an error if both dimensions are > 0" do
+ ->{
+ Matrix.empty(1, 2)
+ }.should raise_error(ArgumentError)
+ end
- ->{
- Matrix.empty(0, -2)
- }.should raise_error(ArgumentError)
- end
+ it "raises an error if any dimension is < 0" do
+ ->{
+ Matrix.empty(-2, 0)
+ }.should raise_error(ArgumentError)
+ ->{
+ Matrix.empty(0, -2)
+ }.should raise_error(ArgumentError)
end
- describe "for a subclass of Matrix" do
- it "returns an instance of that subclass" do
- MatrixSub.empty(0, 1).should be_an_instance_of(MatrixSub)
- end
+end
+
+describe "for a subclass of Matrix" do
+ it "returns an instance of that subclass" do
+ MatrixSub.empty(0, 1).should be_an_instance_of(MatrixSub)
end
end
diff --git a/spec/ruby/library/matrix/eql_spec.rb b/spec/ruby/library/matrix/eql_spec.rb
index d3f03dd6f3..ea26c3320d 100644
--- a/spec/ruby/library/matrix/eql_spec.rb
+++ b/spec/ruby/library/matrix/eql_spec.rb
@@ -1,14 +1,11 @@
require_relative '../../spec_helper'
+require_relative 'shared/equal_value'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require_relative 'shared/equal_value'
- require 'matrix'
+describe "Matrix#eql?" do
+ it_behaves_like :equal, :eql?
- describe "Matrix#eql?" do
- it_behaves_like :equal, :eql?
-
- it "returns false if some elements are == but not eql?" do
- Matrix[[1, 2],[3, 4]].eql?(Matrix[[1, 2],[3, 4.0]]).should be_false
- end
+ it "returns false if some elements are == but not eql?" do
+ Matrix[[1, 2],[3, 4]].eql?(Matrix[[1, 2],[3, 4.0]]).should be_false
end
end
diff --git a/spec/ruby/library/matrix/equal_value_spec.rb b/spec/ruby/library/matrix/equal_value_spec.rb
index 0408a8ef3e..10cf1e6c29 100644
--- a/spec/ruby/library/matrix/equal_value_spec.rb
+++ b/spec/ruby/library/matrix/equal_value_spec.rb
@@ -1,14 +1,11 @@
require_relative '../../spec_helper'
+require_relative 'shared/equal_value'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require_relative 'shared/equal_value'
- require 'matrix'
+describe "Matrix#==" do
+ it_behaves_like :equal, :==
- describe "Matrix#==" do
- it_behaves_like :equal, :==
-
- it "returns true if some elements are == but not eql?" do
- Matrix[[1, 2],[3, 4]].should == Matrix[[1, 2],[3, 4.0]]
- end
+ it "returns true if some elements are == but not eql?" do
+ Matrix[[1, 2],[3, 4]].should == Matrix[[1, 2],[3, 4.0]]
end
end
diff --git a/spec/ruby/library/matrix/exponent_spec.rb b/spec/ruby/library/matrix/exponent_spec.rb
index 5262627fd5..b76e18b4cd 100644
--- a/spec/ruby/library/matrix/exponent_spec.rb
+++ b/spec/ruby/library/matrix/exponent_spec.rb
@@ -1,67 +1,64 @@
require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require_relative 'fixtures/classes'
- require 'matrix'
+describe "Matrix#**" do
- describe "Matrix#**" do
+ describe "given an integer _n_" do
+ it "multiples the Matrix by itself _n_ times" do
+ m = Matrix[ [7,6], [3,9] ]
+ (m ** 1).should == m
+ (m ** 2).should == Matrix[ [67, 96], [48,99] ]
+ (m ** 2).should == m * m
+ (m ** 3).should == m * m * m
+ (m ** 4).should == m * m * m * m
+ (m ** 5).should == m * m * m * m * m
+ end
- describe "given an integer _n_" do
- it "multiples the Matrix by itself _n_ times" do
- m = Matrix[ [7,6], [3,9] ]
- (m ** 1).should == m
- (m ** 2).should == Matrix[ [67, 96], [48,99] ]
- (m ** 2).should == m * m
- (m ** 3).should == m * m * m
- (m ** 4).should == m * m * m * m
- (m ** 5).should == m * m * m * m * m
- end
+ it "raises a ErrDimensionMismatch for non square matrices" do
+ m = Matrix[ [1, 1], [1, 2], [2, 3]]
+ -> { m ** 3 }.should raise_error(Matrix::ErrDimensionMismatch)
+ -> { m ** 0 }.should raise_error(Matrix::ErrDimensionMismatch)
+ end
- it "raises a ErrDimensionMismatch for non square matrices" do
- m = Matrix[ [1, 1], [1, 2], [2, 3]]
- -> { m ** 3 }.should raise_error(Matrix::ErrDimensionMismatch)
- -> { m ** 0 }.should raise_error(Matrix::ErrDimensionMismatch)
+ describe "that is < 0" do
+ it "returns the inverse of **(-n)" do
+ m = Matrix[ [1, 1], [1, 2] ]
+ (m ** -2).should == Matrix[ [5, -3], [-3, 2]]
+ (m ** -4).should == (m.inverse ** 4)
end
- describe "that is < 0" do
- it "returns the inverse of **(-n)" do
- m = Matrix[ [1, 1], [1, 2] ]
- (m ** -2).should == Matrix[ [5, -3], [-3, 2]]
- (m ** -4).should == (m.inverse ** 4)
- end
+ it "raises a ErrNotRegular for irregular matrices" do
+ m = Matrix[ [1, 1], [1, 1] ]
+ -> { m ** -2 }.should raise_error(Matrix::ErrNotRegular)
+ end
+ end
- it "raises a ErrNotRegular for irregular matrices" do
+ ruby_version_is '3.1.0' do # https://bugs.ruby-lang.org/issues/17521
+ describe "that is 0" do
+ it "returns the identity for square matrices" do
m = Matrix[ [1, 1], [1, 1] ]
- -> { m ** -2 }.should raise_error(Matrix::ErrNotRegular)
+ (m ** 0).should == Matrix.identity(2)
end
- end
-
- ruby_version_is '3.1.0' do # https://bugs.ruby-lang.org/issues/17521
- describe "that is 0" do
- it "returns the identity for square matrices" do
- m = Matrix[ [1, 1], [1, 1] ]
- (m ** 0).should == Matrix.identity(2)
- end
- it "raises an ErrDimensionMismatch for non-square matrices" do
- m = Matrix[ [1, 1] ]
- -> { m ** 0 }.should raise_error(Matrix::ErrDimensionMismatch)
- end
+ it "raises an ErrDimensionMismatch for non-square matrices" do
+ m = Matrix[ [1, 1] ]
+ -> { m ** 0 }.should raise_error(Matrix::ErrDimensionMismatch)
end
end
end
+ end
- it "returns the power for non integer powers" do
- a = Matrix[[5, 4], [4, 5]]
- ((a ** 0.5) ** 2).round(8).should == a
- a = Matrix[[7, 10], [15, 22]]
- ((a ** 0.25) ** 4).round(8).should == a
- end
+ it "returns the power for non integer powers" do
+ a = Matrix[[5, 4], [4, 5]]
+ ((a ** 0.5) ** 2).round(8).should == a
+ a = Matrix[[7, 10], [15, 22]]
+ ((a ** 0.25) ** 4).round(8).should == a
+ end
- describe "for a subclass of Matrix" do
- it "returns an instance of that subclass" do
- (MatrixSub.ins ** 1).should be_an_instance_of(MatrixSub)
- end
+ describe "for a subclass of Matrix" do
+ it "returns an instance of that subclass" do
+ (MatrixSub.ins ** 1).should be_an_instance_of(MatrixSub)
end
end
end
diff --git a/spec/ruby/library/matrix/find_index_spec.rb b/spec/ruby/library/matrix/find_index_spec.rb
index a0e3679aef..c2bfa6d61a 100644
--- a/spec/ruby/library/matrix/find_index_spec.rb
+++ b/spec/ruby/library/matrix/find_index_spec.rb
@@ -1,149 +1,146 @@
require_relative '../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
-
- describe "Matrix#find_index without any argument" do
- before :all do
- @m = Matrix[ [1, 2, 3, 4], [5, 6, 7, 8] ]
- end
+describe "Matrix#find_index without any argument" do
+ before :all do
+ @m = Matrix[ [1, 2, 3, 4], [5, 6, 7, 8] ]
+ end
- it "returns an Enumerator when called without a block" do
- enum = @m.find_index
- enum.should be_an_instance_of(Enumerator)
- enum.to_a.should == [1, 2, 3, 4, 5, 6, 7, 8]
- end
+ it "returns an Enumerator when called without a block" do
+ enum = @m.find_index
+ enum.should be_an_instance_of(Enumerator)
+ enum.to_a.should == [1, 2, 3, 4, 5, 6, 7, 8]
+ end
- it "returns nil if the block is always false" do
- @m.find_index{false}.should be_nil
- end
+ it "returns nil if the block is always false" do
+ @m.find_index{false}.should be_nil
+ end
- it "returns the first index for which the block is true" do
- @m.find_index{|x| x >= 3}.should == [0, 2]
- end
+ it "returns the first index for which the block is true" do
+ @m.find_index{|x| x >= 3}.should == [0, 2]
end
+end
- describe "Matrix#find_index with a subselection argument" do
- before :all do
- @tests = [
- [ Matrix[ [1, 2, 3, 4], [5, 6, 7, 8] ], {
- diagonal: [1, 6] ,
- off_diagonal: [2, 3, 4, 5, 7, 8],
- lower: [1, 5, 6] ,
- strict_lower: [5] ,
- strict_upper: [2, 3, 4, 7, 8] ,
- upper: [1, 2, 3, 4, 6, 7, 8] ,
- }
- ],
- [ Matrix[ [1, 2], [3, 4], [5, 6], [7, 8] ], {
- diagonal: [1, 4] ,
- off_diagonal: [2, 3, 5, 6, 7, 8],
- lower: [1, 3, 4, 5, 6, 7, 8] ,
- strict_lower: [3, 5, 6, 7, 8] ,
- strict_upper: [2] ,
- upper: [1, 2, 4] ,
- }
- ]]
- end
+describe "Matrix#find_index with a subselection argument" do
+ before :all do
+ @tests = [
+ [ Matrix[ [1, 2, 3, 4], [5, 6, 7, 8] ], {
+ diagonal: [1, 6] ,
+ off_diagonal: [2, 3, 4, 5, 7, 8],
+ lower: [1, 5, 6] ,
+ strict_lower: [5] ,
+ strict_upper: [2, 3, 4, 7, 8] ,
+ upper: [1, 2, 3, 4, 6, 7, 8] ,
+ }
+ ],
+ [ Matrix[ [1, 2], [3, 4], [5, 6], [7, 8] ], {
+ diagonal: [1, 4] ,
+ off_diagonal: [2, 3, 5, 6, 7, 8],
+ lower: [1, 3, 4, 5, 6, 7, 8] ,
+ strict_lower: [3, 5, 6, 7, 8] ,
+ strict_upper: [2] ,
+ upper: [1, 2, 4] ,
+ }
+ ]]
+ end
- describe "and no generic argument" do
- it "returns an Enumerator when called without a block" do
- @tests.each do |matrix, h|
- h.each do |selector, result|
- matrix.find_index(selector).should be_an_instance_of(Enumerator)
- end
+ describe "and no generic argument" do
+ it "returns an Enumerator when called without a block" do
+ @tests.each do |matrix, h|
+ h.each do |selector, result|
+ matrix.find_index(selector).should be_an_instance_of(Enumerator)
end
end
+ end
- it "yields the rights elements" do
- @tests.each do |matrix, h|
- h.each do |selector, result|
- matrix.find_index(selector).to_a.should == result
- end
+ it "yields the rights elements" do
+ @tests.each do |matrix, h|
+ h.each do |selector, result|
+ matrix.find_index(selector).to_a.should == result
end
end
+ end
- it "returns the first index for which the block returns true" do
- @tests.each do |matrix, h|
- h.each do |selector, result|
- cnt = result.size.div 2
- which = result[cnt]
- idx = matrix.find_index(selector){|x| cnt -= 1; x == which}
- matrix[*idx].should == which
- cnt.should == -1
- end
+ it "returns the first index for which the block returns true" do
+ @tests.each do |matrix, h|
+ h.each do |selector, result|
+ cnt = result.size.div 2
+ which = result[cnt]
+ idx = matrix.find_index(selector){|x| cnt -= 1; x == which}
+ matrix[*idx].should == which
+ cnt.should == -1
end
end
+ end
- it "returns nil if the block is always false" do
- @tests.each do |matrix, h|
- h.each do |selector, result|
- matrix.find_index(selector){ nil }.should == nil
- end
+ it "returns nil if the block is always false" do
+ @tests.each do |matrix, h|
+ h.each do |selector, result|
+ matrix.find_index(selector){ nil }.should == nil
end
end
-
end
- describe "and a generic argument" do
- it "ignores a block" do
- @m.find_index(42, :diagonal){raise "oups"}.should == nil
- end
+ end
+
+ describe "and a generic argument" do
+ it "ignores a block" do
+ @m.find_index(42, :diagonal){raise "oups"}.should == nil
+ end
- it "returns the index of the requested value" do
- @tests.each do |matrix, h|
- h.each do |selector, result|
- cnt = result.size / 2
- which = result[cnt]
- idx = matrix.find_index(which, selector)
- matrix[*idx].should == which
- end
+ it "returns the index of the requested value" do
+ @tests.each do |matrix, h|
+ h.each do |selector, result|
+ cnt = result.size / 2
+ which = result[cnt]
+ idx = matrix.find_index(which, selector)
+ matrix[*idx].should == which
end
end
+ end
- it "returns nil if the requested value is not found" do
- @tests.each do |matrix, h|
- h.each do |selector, result|
- matrix.find_index(42, selector).should == nil
- end
+ it "returns nil if the requested value is not found" do
+ @tests.each do |matrix, h|
+ h.each do |selector, result|
+ matrix.find_index(42, selector).should == nil
end
end
end
-
end
- describe "Matrix#find_index with only a generic argument" do
- before :all do
- @m = Matrix[ [1, 2, 3, 4], [1, 2, 3, 4] ]
- end
+end
- it "returns nil if the value is not found" do
- @m.find_index(42).should be_nil
- end
+describe "Matrix#find_index with only a generic argument" do
+ before :all do
+ @m = Matrix[ [1, 2, 3, 4], [1, 2, 3, 4] ]
+ end
- it "returns the first index for of the requested value" do
- @m.find_index(3).should == [0, 2]
- end
+ it "returns nil if the value is not found" do
+ @m.find_index(42).should be_nil
+ end
- it "ignores a block" do
- @m.find_index(4){raise "oups"}.should == [0, 3]
- end
+ it "returns the first index for of the requested value" do
+ @m.find_index(3).should == [0, 2]
end
- describe "Matrix#find_index with two arguments" do
- it "raises an ArgumentError for an unrecognized last argument" do
- -> {
- @m.find_index(1, "all"){}
- }.should raise_error(ArgumentError)
- -> {
- @m.find_index(1, nil){}
- }.should raise_error(ArgumentError)
- -> {
- @m.find_index(1, :left){}
- }.should raise_error(ArgumentError)
- -> {
- @m.find_index(:diagonal, 1){}
- }.should raise_error(ArgumentError)
- end
+ it "ignores a block" do
+ @m.find_index(4){raise "oups"}.should == [0, 3]
+ end
+end
+
+describe "Matrix#find_index with two arguments" do
+ it "raises an ArgumentError for an unrecognized last argument" do
+ -> {
+ @m.find_index(1, "all"){}
+ }.should raise_error(ArgumentError)
+ -> {
+ @m.find_index(1, nil){}
+ }.should raise_error(ArgumentError)
+ -> {
+ @m.find_index(1, :left){}
+ }.should raise_error(ArgumentError)
+ -> {
+ @m.find_index(:diagonal, 1){}
+ }.should raise_error(ArgumentError)
end
end
diff --git a/spec/ruby/library/matrix/hash_spec.rb b/spec/ruby/library/matrix/hash_spec.rb
index 7c1970511b..7dabcd3737 100644
--- a/spec/ruby/library/matrix/hash_spec.rb
+++ b/spec/ruby/library/matrix/hash_spec.rb
@@ -1,18 +1,15 @@
require_relative '../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
+describe "Matrix#hash" do
- describe "Matrix#hash" do
-
- it "returns an Integer" do
- Matrix[ [1,2] ].hash.should be_an_instance_of(Integer)
- end
-
- it "returns the same value for the same matrix" do
- data = [ [40,5], [2,7] ]
- Matrix[ *data ].hash.should == Matrix[ *data ].hash
- end
+ it "returns an Integer" do
+ Matrix[ [1,2] ].hash.should be_an_instance_of(Integer)
+ end
+ it "returns the same value for the same matrix" do
+ data = [ [40,5], [2,7] ]
+ Matrix[ *data ].hash.should == Matrix[ *data ].hash
end
+
end
diff --git a/spec/ruby/library/matrix/hermitian_spec.rb b/spec/ruby/library/matrix/hermitian_spec.rb
index 4038ee3fa9..177ca64d83 100644
--- a/spec/ruby/library/matrix/hermitian_spec.rb
+++ b/spec/ruby/library/matrix/hermitian_spec.rb
@@ -1,37 +1,34 @@
require_relative '../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
-
- describe "Matrix.hermitian?" do
- it "returns true for a hermitian Matrix" do
- Matrix[[1, 2, Complex(0, 3)], [2, 4, 5], [Complex(0, -3), 5, 6]].hermitian?.should be_true
- end
+describe "Matrix.hermitian?" do
+ it "returns true for a hermitian Matrix" do
+ Matrix[[1, 2, Complex(0, 3)], [2, 4, 5], [Complex(0, -3), 5, 6]].hermitian?.should be_true
+ end
- it "returns true for a 0x0 empty matrix" do
- Matrix.empty.hermitian?.should be_true
- end
+ it "returns true for a 0x0 empty matrix" do
+ Matrix.empty.hermitian?.should be_true
+ end
- it "returns false for an asymmetric Matrix" do
- Matrix[[1, 2],[-2, 1]].hermitian?.should be_false
- end
+ it "returns false for an asymmetric Matrix" do
+ Matrix[[1, 2],[-2, 1]].hermitian?.should be_false
+ end
- it "raises an error for rectangular matrices" do
- [
- Matrix[[0], [0]],
- Matrix[[0, 0]],
- Matrix.empty(0, 2),
- Matrix.empty(2, 0),
- ].each do |rectangular_matrix|
- -> {
- rectangular_matrix.hermitian?
- }.should raise_error(Matrix::ErrDimensionMismatch)
- end
+ it "raises an error for rectangular matrices" do
+ [
+ Matrix[[0], [0]],
+ Matrix[[0, 0]],
+ Matrix.empty(0, 2),
+ Matrix.empty(2, 0),
+ ].each do |rectangular_matrix|
+ -> {
+ rectangular_matrix.hermitian?
+ }.should raise_error(Matrix::ErrDimensionMismatch)
end
+ end
- it "returns false for a matrix with complex values on the diagonal" do
- Matrix[[Complex(1,1)]].hermitian?.should be_false
- Matrix[[Complex(1,0)]].hermitian?.should be_true
- end
+ it "returns false for a matrix with complex values on the diagonal" do
+ Matrix[[Complex(1,1)]].hermitian?.should be_false
+ Matrix[[Complex(1,0)]].hermitian?.should be_true
end
end
diff --git a/spec/ruby/library/matrix/identity_spec.rb b/spec/ruby/library/matrix/identity_spec.rb
index 14f51c402e..646462bc47 100644
--- a/spec/ruby/library/matrix/identity_spec.rb
+++ b/spec/ruby/library/matrix/identity_spec.rb
@@ -1,9 +1,6 @@
require_relative '../../spec_helper'
+require_relative 'shared/identity'
-ruby_version_is ""..."3.1" do
- require_relative 'shared/identity'
-
- describe "Matrix.identity" do
- it_behaves_like :matrix_identity, :identity
- end
+describe "Matrix.identity" do
+ it_behaves_like :matrix_identity, :identity
end
diff --git a/spec/ruby/library/matrix/imag_spec.rb b/spec/ruby/library/matrix/imag_spec.rb
index a89186ec02..1c988753d8 100644
--- a/spec/ruby/library/matrix/imag_spec.rb
+++ b/spec/ruby/library/matrix/imag_spec.rb
@@ -1,9 +1,6 @@
require_relative '../../spec_helper'
+require_relative 'shared/imaginary'
-ruby_version_is ""..."3.1" do
- require_relative 'shared/imaginary'
-
- describe "Matrix#imag" do
- it_behaves_like :matrix_imaginary, :imag
- end
+describe "Matrix#imag" do
+ it_behaves_like :matrix_imaginary, :imag
end
diff --git a/spec/ruby/library/matrix/imaginary_spec.rb b/spec/ruby/library/matrix/imaginary_spec.rb
index e7f0e49d31..ceae4bbe8d 100644
--- a/spec/ruby/library/matrix/imaginary_spec.rb
+++ b/spec/ruby/library/matrix/imaginary_spec.rb
@@ -1,9 +1,6 @@
require_relative '../../spec_helper'
+require_relative 'shared/imaginary'
-ruby_version_is ""..."3.1" do
- require_relative 'shared/imaginary'
-
- describe "Matrix#imaginary" do
- it_behaves_like :matrix_imaginary, :imaginary
- end
+describe "Matrix#imaginary" do
+ it_behaves_like :matrix_imaginary, :imaginary
end
diff --git a/spec/ruby/library/matrix/inspect_spec.rb b/spec/ruby/library/matrix/inspect_spec.rb
index d754c0fe7f..508f478252 100644
--- a/spec/ruby/library/matrix/inspect_spec.rb
+++ b/spec/ruby/library/matrix/inspect_spec.rb
@@ -1,30 +1,27 @@
require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require_relative 'fixtures/classes'
- require 'matrix'
+describe "Matrix#inspect" do
- describe "Matrix#inspect" do
-
- it "returns a stringified representation of the Matrix" do
- Matrix[ [1,2], [2,1] ].inspect.should == "Matrix[[1, 2], [2, 1]]"
- end
+ it "returns a stringified representation of the Matrix" do
+ Matrix[ [1,2], [2,1] ].inspect.should == "Matrix[[1, 2], [2, 1]]"
+ end
- it "returns 'Matrix.empty(...)' for empty matrices" do
- Matrix[ [], [], [] ].inspect.should == "Matrix.empty(3, 0)"
- Matrix.columns([ [], [], [] ]).inspect.should == "Matrix.empty(0, 3)"
- end
+ it "returns 'Matrix.empty(...)' for empty matrices" do
+ Matrix[ [], [], [] ].inspect.should == "Matrix.empty(3, 0)"
+ Matrix.columns([ [], [], [] ]).inspect.should == "Matrix.empty(0, 3)"
+ end
- it "calls inspect on its contents" do
- obj = mock("some_value")
- obj.should_receive(:inspect).and_return("some_value")
- Matrix[ [1, 2], [3, obj] ].inspect.should == "Matrix[[1, 2], [3, some_value]]"
- end
+ it "calls inspect on its contents" do
+ obj = mock("some_value")
+ obj.should_receive(:inspect).and_return("some_value")
+ Matrix[ [1, 2], [3, obj] ].inspect.should == "Matrix[[1, 2], [3, some_value]]"
+ end
- describe "for a subclass of Matrix" do
- it "returns a string using the subclass' name" do
- MatrixSub.ins.inspect.should == "MatrixSub[[1, 0], [0, 1]]"
- end
+ describe "for a subclass of Matrix" do
+ it "returns a string using the subclass' name" do
+ MatrixSub.ins.inspect.should == "MatrixSub[[1, 0], [0, 1]]"
end
end
end
diff --git a/spec/ruby/library/matrix/inv_spec.rb b/spec/ruby/library/matrix/inv_spec.rb
index 0ad817a253..82879a6d82 100644
--- a/spec/ruby/library/matrix/inv_spec.rb
+++ b/spec/ruby/library/matrix/inv_spec.rb
@@ -1,10 +1,7 @@
require_relative '../../spec_helper'
+require_relative 'spec_helper'
+require_relative 'shared/inverse'
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
- require_relative 'shared/inverse'
-
- describe "Matrix#inv" do
- it_behaves_like :inverse, :inv
- end
+describe "Matrix#inv" do
+ it_behaves_like :inverse, :inv
end
diff --git a/spec/ruby/library/matrix/inverse_from_spec.rb b/spec/ruby/library/matrix/inverse_from_spec.rb
index bca40542f6..651d56a244 100644
--- a/spec/ruby/library/matrix/inverse_from_spec.rb
+++ b/spec/ruby/library/matrix/inverse_from_spec.rb
@@ -1,9 +1,6 @@
require_relative '../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
-
- describe "Matrix#inverse_from" do
- it "needs to be reviewed for spec completeness"
- end
+describe "Matrix#inverse_from" do
+ it "needs to be reviewed for spec completeness"
end
diff --git a/spec/ruby/library/matrix/inverse_spec.rb b/spec/ruby/library/matrix/inverse_spec.rb
index dd9099bec5..fa3fa7de8a 100644
--- a/spec/ruby/library/matrix/inverse_spec.rb
+++ b/spec/ruby/library/matrix/inverse_spec.rb
@@ -1,10 +1,7 @@
require_relative '../../spec_helper'
+require_relative 'spec_helper'
+require_relative 'shared/inverse'
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
- require_relative 'shared/inverse'
-
- describe "Matrix#inverse" do
- it_behaves_like :inverse, :inverse
- end
+describe "Matrix#inverse" do
+ it_behaves_like :inverse, :inverse
end
diff --git a/spec/ruby/library/matrix/lower_triangular_spec.rb b/spec/ruby/library/matrix/lower_triangular_spec.rb
index 0223b8b619..f3aa4501f4 100644
--- a/spec/ruby/library/matrix/lower_triangular_spec.rb
+++ b/spec/ruby/library/matrix/lower_triangular_spec.rb
@@ -1,27 +1,24 @@
require_relative '../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
-
- describe "Matrix.lower_triangular?" do
- it "returns true for a square lower triangular Matrix" do
- Matrix[[1, 0, 0], [1, 2, 0], [1, 2, 3]].lower_triangular?.should be_true
- Matrix.diagonal([1, 2, 3]).lower_triangular?.should be_true
- Matrix[[1, 0], [1, 2], [1, 2], [1, 2]].lower_triangular?.should be_true
- Matrix[[1, 0, 0, 0], [1, 2, 0, 0]].lower_triangular?.should be_true
- end
+describe "Matrix.lower_triangular?" do
+ it "returns true for a square lower triangular Matrix" do
+ Matrix[[1, 0, 0], [1, 2, 0], [1, 2, 3]].lower_triangular?.should be_true
+ Matrix.diagonal([1, 2, 3]).lower_triangular?.should be_true
+ Matrix[[1, 0], [1, 2], [1, 2], [1, 2]].lower_triangular?.should be_true
+ Matrix[[1, 0, 0, 0], [1, 2, 0, 0]].lower_triangular?.should be_true
+ end
- it "returns true for an empty Matrix" do
- Matrix.empty(3, 0).lower_triangular?.should be_true
- Matrix.empty(0, 3).lower_triangular?.should be_true
- Matrix.empty(0, 0).lower_triangular?.should be_true
- end
+ it "returns true for an empty Matrix" do
+ Matrix.empty(3, 0).lower_triangular?.should be_true
+ Matrix.empty(0, 3).lower_triangular?.should be_true
+ Matrix.empty(0, 0).lower_triangular?.should be_true
+ end
- it "returns false for a non lower triangular square Matrix" do
- Matrix[[0, 1], [0, 0]].lower_triangular?.should be_false
- Matrix[[1, 2, 3], [1, 2, 3], [1, 2, 3]].lower_triangular?.should be_false
- Matrix[[0, 1], [0, 0], [0, 0], [0, 0]].lower_triangular?.should be_false
- Matrix[[0, 0, 0, 1], [0, 0, 0, 0]].lower_triangular?.should be_false
- end
+ it "returns false for a non lower triangular square Matrix" do
+ Matrix[[0, 1], [0, 0]].lower_triangular?.should be_false
+ Matrix[[1, 2, 3], [1, 2, 3], [1, 2, 3]].lower_triangular?.should be_false
+ Matrix[[0, 1], [0, 0], [0, 0], [0, 0]].lower_triangular?.should be_false
+ Matrix[[0, 0, 0, 1], [0, 0, 0, 0]].lower_triangular?.should be_false
end
end
diff --git a/spec/ruby/library/matrix/lup_decomposition/determinant_spec.rb b/spec/ruby/library/matrix/lup_decomposition/determinant_spec.rb
index 1ac4bc971e..9d733066c1 100644
--- a/spec/ruby/library/matrix/lup_decomposition/determinant_spec.rb
+++ b/spec/ruby/library/matrix/lup_decomposition/determinant_spec.rb
@@ -1,24 +1,21 @@
require_relative '../../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
-
- describe "Matrix::LUPDecomposition#determinant" do
- it "returns the determinant when the matrix is square" do
- a = Matrix[[7, 8, 9], [14, 46, 51], [28, 82, 163]]
- a.lup.determinant.should == 15120 # == a.determinant
- end
+describe "Matrix::LUPDecomposition#determinant" do
+ it "returns the determinant when the matrix is square" do
+ a = Matrix[[7, 8, 9], [14, 46, 51], [28, 82, 163]]
+ a.lup.determinant.should == 15120 # == a.determinant
+ end
- it "raises an error for rectangular matrices" do
- [
- Matrix[[7, 8, 9], [14, 46, 51]],
- Matrix[[7, 8], [14, 46], [28, 82]],
- ].each do |m|
- lup = m.lup
- -> {
- lup.determinant
- }.should raise_error(Matrix::ErrDimensionMismatch)
- end
+ it "raises an error for rectangular matrices" do
+ [
+ Matrix[[7, 8, 9], [14, 46, 51]],
+ Matrix[[7, 8], [14, 46], [28, 82]],
+ ].each do |m|
+ lup = m.lup
+ -> {
+ lup.determinant
+ }.should raise_error(Matrix::ErrDimensionMismatch)
end
end
end
diff --git a/spec/ruby/library/matrix/lup_decomposition/initialize_spec.rb b/spec/ruby/library/matrix/lup_decomposition/initialize_spec.rb
index 42f78c7540..36afb349e6 100644
--- a/spec/ruby/library/matrix/lup_decomposition/initialize_spec.rb
+++ b/spec/ruby/library/matrix/lup_decomposition/initialize_spec.rb
@@ -1,16 +1,13 @@
require_relative '../../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
-
- describe "Matrix::LUPDecomposition#initialize" do
- it "raises an error if argument is not a matrix" do
- -> {
- Matrix::LUPDecomposition.new([[]])
- }.should raise_error(TypeError)
- -> {
- Matrix::LUPDecomposition.new(42)
- }.should raise_error(TypeError)
- end
+describe "Matrix::LUPDecomposition#initialize" do
+ it "raises an error if argument is not a matrix" do
+ -> {
+ Matrix::LUPDecomposition.new([[]])
+ }.should raise_error(TypeError)
+ -> {
+ Matrix::LUPDecomposition.new(42)
+ }.should raise_error(TypeError)
end
end
diff --git a/spec/ruby/library/matrix/lup_decomposition/l_spec.rb b/spec/ruby/library/matrix/lup_decomposition/l_spec.rb
index 6c751f12b7..9514ab5d06 100644
--- a/spec/ruby/library/matrix/lup_decomposition/l_spec.rb
+++ b/spec/ruby/library/matrix/lup_decomposition/l_spec.rb
@@ -1,21 +1,18 @@
require_relative '../../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
-
- describe "Matrix::LUPDecomposition#l" do
- before :each do
- @a = Matrix[[7, 8, 9], [14, 46, 51], [28, 82, 163]]
- @lu = Matrix::LUPDecomposition.new(@a)
- @l = @lu.l
- end
+describe "Matrix::LUPDecomposition#l" do
+ before :each do
+ @a = Matrix[[7, 8, 9], [14, 46, 51], [28, 82, 163]]
+ @lu = Matrix::LUPDecomposition.new(@a)
+ @l = @lu.l
+ end
- it "returns the first element of to_a" do
- @l.should == @lu.to_a[0]
- end
+ it "returns the first element of to_a" do
+ @l.should == @lu.to_a[0]
+ end
- it "returns a lower triangular matrix" do
- @l.lower_triangular?.should be_true
- end
+ it "returns a lower triangular matrix" do
+ @l.lower_triangular?.should be_true
end
end
diff --git a/spec/ruby/library/matrix/lup_decomposition/p_spec.rb b/spec/ruby/library/matrix/lup_decomposition/p_spec.rb
index 481f8a17d5..c7b5e9196e 100644
--- a/spec/ruby/library/matrix/lup_decomposition/p_spec.rb
+++ b/spec/ruby/library/matrix/lup_decomposition/p_spec.rb
@@ -1,21 +1,18 @@
require_relative '../../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
-
- describe "Matrix::LUPDecomposition#p" do
- before :each do
- @a = Matrix[[7, 8, 9], [14, 46, 51], [28, 82, 163]]
- @lu = Matrix::LUPDecomposition.new(@a)
- @p = @lu.p
- end
+describe "Matrix::LUPDecomposition#p" do
+ before :each do
+ @a = Matrix[[7, 8, 9], [14, 46, 51], [28, 82, 163]]
+ @lu = Matrix::LUPDecomposition.new(@a)
+ @p = @lu.p
+ end
- it "returns the third element of to_a" do
- @p.should == @lu.to_a[2]
- end
+ it "returns the third element of to_a" do
+ @p.should == @lu.to_a[2]
+ end
- it "returns a permutation matrix" do
- @p.permutation?.should be_true
- end
+ it "returns a permutation matrix" do
+ @p.permutation?.should be_true
end
end
diff --git a/spec/ruby/library/matrix/lup_decomposition/solve_spec.rb b/spec/ruby/library/matrix/lup_decomposition/solve_spec.rb
index 773fcb3e65..66242627e9 100644
--- a/spec/ruby/library/matrix/lup_decomposition/solve_spec.rb
+++ b/spec/ruby/library/matrix/lup_decomposition/solve_spec.rb
@@ -1,55 +1,52 @@
require_relative '../../../spec_helper'
+require 'matrix'
+
+describe "Matrix::LUPDecomposition#solve" do
+ describe "for rectangular matrices" do
+ it "raises an error for singular matrices" do
+ a = Matrix[[1, 2, 3], [1, 3, 5], [2, 5, 8]]
+ lu = Matrix::LUPDecomposition.new(a)
+ -> {
+ lu.solve(a)
+ }.should raise_error(Matrix::ErrNotRegular)
+ end
-ruby_version_is ""..."3.1" do
- require 'matrix'
-
- describe "Matrix::LUPDecomposition#solve" do
- describe "for rectangular matrices" do
- it "raises an error for singular matrices" do
- a = Matrix[[1, 2, 3], [1, 3, 5], [2, 5, 8]]
- lu = Matrix::LUPDecomposition.new(a)
- -> {
- lu.solve(a)
- }.should raise_error(Matrix::ErrNotRegular)
+ describe "for non singular matrices" do
+ before :each do
+ @a = Matrix[[7, 8, 9], [14, 46, 51], [28, 82, 163]]
+ @lu = Matrix::LUPDecomposition.new(@a)
end
- describe "for non singular matrices" do
- before :each do
- @a = Matrix[[7, 8, 9], [14, 46, 51], [28, 82, 163]]
- @lu = Matrix::LUPDecomposition.new(@a)
- end
-
- it "returns the appropriate empty matrix when given an empty matrix" do
- @lu.solve(Matrix.empty(3,0)).should == Matrix.empty(3,0)
- empty = Matrix::LUPDecomposition.new(Matrix.empty(0, 0))
- empty.solve(Matrix.empty(0,3)).should == Matrix.empty(0,3)
- end
+ it "returns the appropriate empty matrix when given an empty matrix" do
+ @lu.solve(Matrix.empty(3,0)).should == Matrix.empty(3,0)
+ empty = Matrix::LUPDecomposition.new(Matrix.empty(0, 0))
+ empty.solve(Matrix.empty(0,3)).should == Matrix.empty(0,3)
+ end
- it "returns the right matrix when given a matrix of the appropriate size" do
- solution = Matrix[[1, 2, 3, 4], [0, 1, 2, 3], [-1, -2, -3, -4]]
- values = Matrix[[-2, 4, 10, 16], [-37, -28, -19, -10], [-135, -188, -241, -294]] # == @a * solution
- @lu.solve(values).should == solution
- end
+ it "returns the right matrix when given a matrix of the appropriate size" do
+ solution = Matrix[[1, 2, 3, 4], [0, 1, 2, 3], [-1, -2, -3, -4]]
+ values = Matrix[[-2, 4, 10, 16], [-37, -28, -19, -10], [-135, -188, -241, -294]] # == @a * solution
+ @lu.solve(values).should == solution
+ end
- it "raises an error when given a matrix of the wrong size" do
- values = Matrix[[1, 2, 3, 4], [0, 1, 2, 3]]
- -> {
- @lu.solve(values)
- }.should raise_error(Matrix::ErrDimensionMismatch)
- end
+ it "raises an error when given a matrix of the wrong size" do
+ values = Matrix[[1, 2, 3, 4], [0, 1, 2, 3]]
+ -> {
+ @lu.solve(values)
+ }.should raise_error(Matrix::ErrDimensionMismatch)
+ end
- it "returns the right vector when given a vector of the appropriate size" do
- solution = Vector[1, 2, -1]
- values = Vector[14, 55, 29] # == @a * solution
- @lu.solve(values).should == solution
- end
+ it "returns the right vector when given a vector of the appropriate size" do
+ solution = Vector[1, 2, -1]
+ values = Vector[14, 55, 29] # == @a * solution
+ @lu.solve(values).should == solution
+ end
- it "raises an error when given a vector of the wrong size" do
- values = Vector[14, 55]
- -> {
- @lu.solve(values)
- }.should raise_error(Matrix::ErrDimensionMismatch)
- end
+ it "raises an error when given a vector of the wrong size" do
+ values = Vector[14, 55]
+ -> {
+ @lu.solve(values)
+ }.should raise_error(Matrix::ErrDimensionMismatch)
end
end
end
diff --git a/spec/ruby/library/matrix/lup_decomposition/to_a_spec.rb b/spec/ruby/library/matrix/lup_decomposition/to_a_spec.rb
index 8702292865..9b1dccbbac 100644
--- a/spec/ruby/library/matrix/lup_decomposition/to_a_spec.rb
+++ b/spec/ruby/library/matrix/lup_decomposition/to_a_spec.rb
@@ -1,36 +1,33 @@
require_relative '../../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
-
- describe "Matrix::LUPDecomposition#to_a" do
- before :each do
- @a = Matrix[[7, 8, 9], [14, 46, 51], [28, 82, 163]]
- @lu = Matrix::LUPDecomposition.new(@a)
- @to_a = @lu.to_a
- @l, @u, @p = @to_a
- end
+describe "Matrix::LUPDecomposition#to_a" do
+ before :each do
+ @a = Matrix[[7, 8, 9], [14, 46, 51], [28, 82, 163]]
+ @lu = Matrix::LUPDecomposition.new(@a)
+ @to_a = @lu.to_a
+ @l, @u, @p = @to_a
+ end
- it "returns an array of three matrices" do
- @to_a.should be_kind_of(Array)
- @to_a.length.should == 3
- @to_a.each{|m| m.should be_kind_of(Matrix)}
- end
+ it "returns an array of three matrices" do
+ @to_a.should be_kind_of(Array)
+ @to_a.length.should == 3
+ @to_a.each{|m| m.should be_kind_of(Matrix)}
+ end
- it "returns [l, u, p] such that l*u == a*p" do
- (@l * @u).should == (@p * @a)
- end
+ it "returns [l, u, p] such that l*u == a*p" do
+ (@l * @u).should == (@p * @a)
+ end
- it "returns the right values for rectangular matrices" do
- [
- Matrix[[7, 8, 9], [14, 46, 51]],
- Matrix[[4, 11], [5, 8], [3, 4]],
- ].each do |a|
- l, u, p = Matrix::LUPDecomposition.new(a).to_a
- (l * u).should == (p * a)
- end
+ it "returns the right values for rectangular matrices" do
+ [
+ Matrix[[7, 8, 9], [14, 46, 51]],
+ Matrix[[4, 11], [5, 8], [3, 4]],
+ ].each do |a|
+ l, u, p = Matrix::LUPDecomposition.new(a).to_a
+ (l * u).should == (p * a)
end
-
- it "has other properties implied by the specs of #l, #u and #p"
end
+
+ it "has other properties implied by the specs of #l, #u and #p"
end
diff --git a/spec/ruby/library/matrix/lup_decomposition/u_spec.rb b/spec/ruby/library/matrix/lup_decomposition/u_spec.rb
index cd884b88ec..ca3dfc1f00 100644
--- a/spec/ruby/library/matrix/lup_decomposition/u_spec.rb
+++ b/spec/ruby/library/matrix/lup_decomposition/u_spec.rb
@@ -1,21 +1,18 @@
require_relative '../../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
-
- describe "Matrix::LUPDecomposition#u" do
- before :each do
- @a = Matrix[[7, 8, 9], [14, 46, 51], [28, 82, 163]]
- @lu = Matrix::LUPDecomposition.new(@a)
- @u = @lu.u
- end
+describe "Matrix::LUPDecomposition#u" do
+ before :each do
+ @a = Matrix[[7, 8, 9], [14, 46, 51], [28, 82, 163]]
+ @lu = Matrix::LUPDecomposition.new(@a)
+ @u = @lu.u
+ end
- it "returns the second element of to_a" do
- @u.should == @lu.to_a[1]
- end
+ it "returns the second element of to_a" do
+ @u.should == @lu.to_a[1]
+ end
- it "returns an upper triangular matrix" do
- @u.upper_triangular?.should be_true
- end
+ it "returns an upper triangular matrix" do
+ @u.upper_triangular?.should be_true
end
end
diff --git a/spec/ruby/library/matrix/map_spec.rb b/spec/ruby/library/matrix/map_spec.rb
index cde0df5441..bc07c48cda 100644
--- a/spec/ruby/library/matrix/map_spec.rb
+++ b/spec/ruby/library/matrix/map_spec.rb
@@ -1,9 +1,6 @@
require_relative '../../spec_helper'
+require_relative 'shared/collect'
-ruby_version_is ""..."3.1" do
- require_relative 'shared/collect'
-
- describe "Matrix#map" do
- it_behaves_like :collect, :map
- end
+describe "Matrix#map" do
+ it_behaves_like :collect, :map
end
diff --git a/spec/ruby/library/matrix/minor_spec.rb b/spec/ruby/library/matrix/minor_spec.rb
index 0a6b0823c8..009826c3d6 100644
--- a/spec/ruby/library/matrix/minor_spec.rb
+++ b/spec/ruby/library/matrix/minor_spec.rb
@@ -1,88 +1,85 @@
require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require_relative 'fixtures/classes'
- require 'matrix'
+describe "Matrix#minor" do
+ before :each do
+ @matrix = Matrix[ [1,2], [3,4], [5,6] ]
+ end
- describe "Matrix#minor" do
- before :each do
- @matrix = Matrix[ [1,2], [3,4], [5,6] ]
+ describe "with start_row, nrows, start_col, ncols" do
+ it "returns the given portion of the Matrix" do
+ @matrix.minor(0,1,0,2).should == Matrix[ [1, 2] ]
+ @matrix.minor(1,2,1,1).should == Matrix[ [4], [6] ]
end
- describe "with start_row, nrows, start_col, ncols" do
- it "returns the given portion of the Matrix" do
- @matrix.minor(0,1,0,2).should == Matrix[ [1, 2] ]
- @matrix.minor(1,2,1,1).should == Matrix[ [4], [6] ]
- end
-
- it "returns an empty Matrix if nrows or ncols is 0" do
- @matrix.minor(0,0,0,0).should == Matrix[]
- @matrix.minor(1,0,1,0).should == Matrix[]
- @matrix.minor(1,0,1,1).should == Matrix.columns([[]])
- @matrix.minor(1,1,1,0).should == Matrix[[]]
- end
+ it "returns an empty Matrix if nrows or ncols is 0" do
+ @matrix.minor(0,0,0,0).should == Matrix[]
+ @matrix.minor(1,0,1,0).should == Matrix[]
+ @matrix.minor(1,0,1,1).should == Matrix.columns([[]])
+ @matrix.minor(1,1,1,0).should == Matrix[[]]
+ end
- it "returns nil for out-of-bounds start_row/col" do
- r = @matrix.row_size + 1
- c = @matrix.column_size + 1
- @matrix.minor(r,0,0,10).should == nil
- @matrix.minor(0,10,c,9).should == nil
- @matrix.minor(-r,0,0,10).should == nil
- @matrix.minor(0,10,-c,9).should == nil
- end
+ it "returns nil for out-of-bounds start_row/col" do
+ r = @matrix.row_size + 1
+ c = @matrix.column_size + 1
+ @matrix.minor(r,0,0,10).should == nil
+ @matrix.minor(0,10,c,9).should == nil
+ @matrix.minor(-r,0,0,10).should == nil
+ @matrix.minor(0,10,-c,9).should == nil
+ end
- it "returns nil for negative nrows or ncols" do
- @matrix.minor(0,1,0,-1).should == nil
- @matrix.minor(0,-1,0,1).should == nil
- end
+ it "returns nil for negative nrows or ncols" do
+ @matrix.minor(0,1,0,-1).should == nil
+ @matrix.minor(0,-1,0,1).should == nil
+ end
- it "start counting backwards for start_row or start_col below zero" do
- @matrix.minor(0, 1, -1, 1).should == @matrix.minor(0, 1, 1, 1)
- @matrix.minor(-1, 1, 0, 1).should == @matrix.minor(2, 1, 0, 1)
- end
+ it "start counting backwards for start_row or start_col below zero" do
+ @matrix.minor(0, 1, -1, 1).should == @matrix.minor(0, 1, 1, 1)
+ @matrix.minor(-1, 1, 0, 1).should == @matrix.minor(2, 1, 0, 1)
+ end
- it "returns empty matrices for extreme start_row/col" do
- @matrix.minor(3,10,1,10).should == Matrix.columns([[]])
- @matrix.minor(1,10,2,10).should == Matrix[[], []]
- @matrix.minor(3,0,0,10).should == Matrix.columns([[], []])
- end
+ it "returns empty matrices for extreme start_row/col" do
+ @matrix.minor(3,10,1,10).should == Matrix.columns([[]])
+ @matrix.minor(1,10,2,10).should == Matrix[[], []]
+ @matrix.minor(3,0,0,10).should == Matrix.columns([[], []])
+ end
- it "ignores big nrows or ncols" do
- @matrix.minor(0,1,0,20).should == Matrix[ [1, 2] ]
- @matrix.minor(1,20,1,1).should == Matrix[ [4], [6] ]
- end
+ it "ignores big nrows or ncols" do
+ @matrix.minor(0,1,0,20).should == Matrix[ [1, 2] ]
+ @matrix.minor(1,20,1,1).should == Matrix[ [4], [6] ]
end
+ end
- describe "with col_range, row_range" do
- it "returns the given portion of the Matrix" do
- @matrix.minor(0..0, 0..1).should == Matrix[ [1, 2] ]
- @matrix.minor(1..2, 1..2).should == Matrix[ [4], [6] ]
- @matrix.minor(1...3, 1...3).should == Matrix[ [4], [6] ]
- end
+ describe "with col_range, row_range" do
+ it "returns the given portion of the Matrix" do
+ @matrix.minor(0..0, 0..1).should == Matrix[ [1, 2] ]
+ @matrix.minor(1..2, 1..2).should == Matrix[ [4], [6] ]
+ @matrix.minor(1...3, 1...3).should == Matrix[ [4], [6] ]
+ end
- it "returns nil if col_range or row_range is out of range" do
- r = @matrix.row_size + 1
- c = @matrix.column_size + 1
- @matrix.minor(r..6, c..6).should == nil
- @matrix.minor(0..1, c..6).should == nil
- @matrix.minor(r..6, 0..1).should == nil
- @matrix.minor(-r..6, -c..6).should == nil
- @matrix.minor(0..1, -c..6).should == nil
- @matrix.minor(-r..6, 0..1).should == nil
- end
+ it "returns nil if col_range or row_range is out of range" do
+ r = @matrix.row_size + 1
+ c = @matrix.column_size + 1
+ @matrix.minor(r..6, c..6).should == nil
+ @matrix.minor(0..1, c..6).should == nil
+ @matrix.minor(r..6, 0..1).should == nil
+ @matrix.minor(-r..6, -c..6).should == nil
+ @matrix.minor(0..1, -c..6).should == nil
+ @matrix.minor(-r..6, 0..1).should == nil
+ end
- it "start counting backwards for col_range or row_range below zero" do
- @matrix.minor(0..1, -2..-1).should == @matrix.minor(0..1, 0..1)
- @matrix.minor(0..1, -2..1).should == @matrix.minor(0..1, 0..1)
- @matrix.minor(-2..-1, 0..1).should == @matrix.minor(1..2, 0..1)
- @matrix.minor(-2..2, 0..1).should == @matrix.minor(1..2, 0..1)
- end
+ it "start counting backwards for col_range or row_range below zero" do
+ @matrix.minor(0..1, -2..-1).should == @matrix.minor(0..1, 0..1)
+ @matrix.minor(0..1, -2..1).should == @matrix.minor(0..1, 0..1)
+ @matrix.minor(-2..-1, 0..1).should == @matrix.minor(1..2, 0..1)
+ @matrix.minor(-2..2, 0..1).should == @matrix.minor(1..2, 0..1)
end
+ end
- describe "for a subclass of Matrix" do
- it "returns an instance of that subclass" do
- MatrixSub.ins.minor(0, 1, 0, 1).should be_an_instance_of(MatrixSub)
- end
+ describe "for a subclass of Matrix" do
+ it "returns an instance of that subclass" do
+ MatrixSub.ins.minor(0, 1, 0, 1).should be_an_instance_of(MatrixSub)
end
end
end
diff --git a/spec/ruby/library/matrix/minus_spec.rb b/spec/ruby/library/matrix/minus_spec.rb
index 27dfbeaea5..95cf4a6072 100644
--- a/spec/ruby/library/matrix/minus_spec.rb
+++ b/spec/ruby/library/matrix/minus_spec.rb
@@ -1,45 +1,42 @@
require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require_relative 'fixtures/classes'
- require 'matrix'
-
- describe "Matrix#-" do
- before :each do
- @a = Matrix[ [1, 2], [3, 4] ]
- @b = Matrix[ [4, 5], [6, 7] ]
- end
+describe "Matrix#-" do
+ before :each do
+ @a = Matrix[ [1, 2], [3, 4] ]
+ @b = Matrix[ [4, 5], [6, 7] ]
+ end
- it "returns the result of subtracting the corresponding elements of other from self" do
- (@a - @b).should == Matrix[ [-3,-3], [-3,-3] ]
- end
+ it "returns the result of subtracting the corresponding elements of other from self" do
+ (@a - @b).should == Matrix[ [-3,-3], [-3,-3] ]
+ end
- it "returns an instance of Matrix" do
- (@a - @b).should be_kind_of(Matrix)
- end
+ it "returns an instance of Matrix" do
+ (@a - @b).should be_kind_of(Matrix)
+ end
- it "raises a Matrix::ErrDimensionMismatch if the matrices are different sizes" do
- -> { @a - Matrix[ [1] ] }.should raise_error(Matrix::ErrDimensionMismatch)
- end
+ it "raises a Matrix::ErrDimensionMismatch if the matrices are different sizes" do
+ -> { @a - Matrix[ [1] ] }.should raise_error(Matrix::ErrDimensionMismatch)
+ end
- it "raises a ExceptionForMatrix::ErrOperationNotDefined if other is a Numeric Type" do
- -> { @a - 2 }.should raise_error(Matrix::ErrOperationNotDefined)
- -> { @a - 1.2 }.should raise_error(Matrix::ErrOperationNotDefined)
- -> { @a - bignum_value }.should raise_error(Matrix::ErrOperationNotDefined)
- end
+ it "raises a ExceptionForMatrix::ErrOperationNotDefined if other is a Numeric Type" do
+ -> { @a - 2 }.should raise_error(Matrix::ErrOperationNotDefined)
+ -> { @a - 1.2 }.should raise_error(Matrix::ErrOperationNotDefined)
+ -> { @a - bignum_value }.should raise_error(Matrix::ErrOperationNotDefined)
+ end
- it "raises a TypeError if other is of wrong type" do
- -> { @a - nil }.should raise_error(TypeError)
- -> { @a - "a" }.should raise_error(TypeError)
- -> { @a - [ [1, 2] ] }.should raise_error(TypeError)
- -> { @a - Object.new }.should raise_error(TypeError)
- end
+ it "raises a TypeError if other is of wrong type" do
+ -> { @a - nil }.should raise_error(TypeError)
+ -> { @a - "a" }.should raise_error(TypeError)
+ -> { @a - [ [1, 2] ] }.should raise_error(TypeError)
+ -> { @a - Object.new }.should raise_error(TypeError)
+ end
- describe "for a subclass of Matrix" do
- it "returns an instance of that subclass" do
- m = MatrixSub.ins
- (m-m).should be_an_instance_of(MatrixSub)
- end
+ describe "for a subclass of Matrix" do
+ it "returns an instance of that subclass" do
+ m = MatrixSub.ins
+ (m-m).should be_an_instance_of(MatrixSub)
end
end
end
diff --git a/spec/ruby/library/matrix/multiply_spec.rb b/spec/ruby/library/matrix/multiply_spec.rb
index 841d9d95b7..206868af92 100644
--- a/spec/ruby/library/matrix/multiply_spec.rb
+++ b/spec/ruby/library/matrix/multiply_spec.rb
@@ -1,71 +1,69 @@
require_relative '../../spec_helper'
-ruby_version_is ""..."3.1" do
- require_relative 'fixtures/classes'
- require 'matrix'
+require_relative 'fixtures/classes'
+require 'matrix'
- describe "Matrix#*" do
- before :each do
- @a = Matrix[ [1, 2], [3, 4] ]
- @b = Matrix[ [4, 5], [6, 7] ]
- end
+describe "Matrix#*" do
+ before :each do
+ @a = Matrix[ [1, 2], [3, 4] ]
+ @b = Matrix[ [4, 5], [6, 7] ]
+ end
- it "returns the result of multiplying the corresponding elements of self and a Matrix" do
- (@a * @b).should == Matrix[ [16,19], [36,43] ]
- end
+ it "returns the result of multiplying the corresponding elements of self and a Matrix" do
+ (@a * @b).should == Matrix[ [16,19], [36,43] ]
+ end
- it "returns the result of multiplying the corresponding elements of self and a Vector" do
- (@a * Vector[1,2]).should == Vector[5, 11]
- end
+ it "returns the result of multiplying the corresponding elements of self and a Vector" do
+ (@a * Vector[1,2]).should == Vector[5, 11]
+ end
- it "returns the result of multiplying the elements of self and a Fixnum" do
- (@a * 2).should == Matrix[ [2, 4], [6, 8] ]
- end
+ it "returns the result of multiplying the elements of self and a Fixnum" do
+ (@a * 2).should == Matrix[ [2, 4], [6, 8] ]
+ end
- it "returns the result of multiplying the elements of self and a Bignum" do
- (@a * bignum_value).should == Matrix[
- [9223372036854775808, 18446744073709551616],
- [27670116110564327424, 36893488147419103232]
- ]
- end
+ it "returns the result of multiplying the elements of self and a Bignum" do
+ (@a * bignum_value).should == Matrix[
+ [18446744073709551616, 36893488147419103232],
+ [55340232221128654848, 73786976294838206464]
+ ]
+ end
- it "returns the result of multiplying the elements of self and a Float" do
- (@a * 2.0).should == Matrix[ [2.0, 4.0], [6.0, 8.0] ]
- end
+ it "returns the result of multiplying the elements of self and a Float" do
+ (@a * 2.0).should == Matrix[ [2.0, 4.0], [6.0, 8.0] ]
+ end
- it "raises a Matrix::ErrDimensionMismatch if the matrices are different sizes" do
- -> { @a * Matrix[ [1] ] }.should raise_error(Matrix::ErrDimensionMismatch)
- end
+ it "raises a Matrix::ErrDimensionMismatch if the matrices are different sizes" do
+ -> { @a * Matrix[ [1] ] }.should raise_error(Matrix::ErrDimensionMismatch)
+ end
- it "returns a zero matrix if (nx0) * (0xn)" do
- (Matrix[[],[],[]] * Matrix.columns([[],[],[]])).should == Matrix.zero(3)
- end
+ it "returns a zero matrix if (nx0) * (0xn)" do
+ (Matrix[[],[],[]] * Matrix.columns([[],[],[]])).should == Matrix.zero(3)
+ end
- it "returns an empty matrix if (0xn) * (nx0)" do
- (Matrix.columns([[],[],[]]) * Matrix[[],[],[]]).should == Matrix[]
- end
+ it "returns an empty matrix if (0xn) * (nx0)" do
+ (Matrix.columns([[],[],[]]) * Matrix[[],[],[]]).should == Matrix[]
+ end
- it "returns a mx0 matrix if (mxn) * (nx0)" do
- (Matrix[[1,2],[3,4],[5,6]] * Matrix[[],[]]).should == Matrix[[],[],[]]
- end
+ it "returns a mx0 matrix if (mxn) * (nx0)" do
+ (Matrix[[1,2],[3,4],[5,6]] * Matrix[[],[]]).should == Matrix[[],[],[]]
+ end
- it "returns a 0xm matrix if (0xm) * (mxn)" do
- (Matrix.columns([[], [], []]) * Matrix[[1,2],[3,4],[5,6]]).should == Matrix.columns([[],[]])
- end
+ it "returns a 0xm matrix if (0xm) * (mxn)" do
+ (Matrix.columns([[], [], []]) * Matrix[[1,2],[3,4],[5,6]]).should == Matrix.columns([[],[]])
+ end
- it "raises a TypeError if other is of wrong type" do
- -> { @a * nil }.should raise_error(TypeError)
- -> { @a * "a" }.should raise_error(TypeError)
- -> { @a * [ [1, 2] ] }.should raise_error(TypeError)
- -> { @a * Object.new }.should raise_error(TypeError)
- end
+ it "raises a TypeError if other is of wrong type" do
+ -> { @a * nil }.should raise_error(TypeError)
+ -> { @a * "a" }.should raise_error(TypeError)
+ -> { @a * [ [1, 2] ] }.should raise_error(TypeError)
+ -> { @a * Object.new }.should raise_error(TypeError)
+ end
- describe "for a subclass of Matrix" do
- it "returns an instance of that subclass" do
- m = MatrixSub.ins
- (m*m).should be_an_instance_of(MatrixSub)
- (m*1).should be_an_instance_of(MatrixSub)
- end
+ describe "for a subclass of Matrix" do
+ it "returns an instance of that subclass" do
+ m = MatrixSub.ins
+ (m*m).should be_an_instance_of(MatrixSub)
+ (m*1).should be_an_instance_of(MatrixSub)
end
end
end
diff --git a/spec/ruby/library/matrix/new_spec.rb b/spec/ruby/library/matrix/new_spec.rb
index 4be2e17116..3005066846 100644
--- a/spec/ruby/library/matrix/new_spec.rb
+++ b/spec/ruby/library/matrix/new_spec.rb
@@ -1,11 +1,8 @@
require_relative '../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
-
- describe "Matrix.new" do
- it "is private" do
- Matrix.should have_private_method(:new)
- end
+describe "Matrix.new" do
+ it "is private" do
+ Matrix.should have_private_method(:new)
end
end
diff --git a/spec/ruby/library/matrix/normal_spec.rb b/spec/ruby/library/matrix/normal_spec.rb
index 2f2e138c1b..a9e6c645fa 100644
--- a/spec/ruby/library/matrix/normal_spec.rb
+++ b/spec/ruby/library/matrix/normal_spec.rb
@@ -1,29 +1,26 @@
require_relative '../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
+describe "Matrix.normal?" do
+ # it "returns false for non normal matrices" do
+ # Matrix[[0, 1], [1, 2]].should_not.normal?
+ # end
- describe "Matrix.normal?" do
- # it "returns false for non normal matrices" do
- # Matrix[[0, 1], [1, 2]].should_not.normal?
- # end
-
- it "returns true for normal matrices" do
- Matrix[[1, 1, 0], [0, 1, 1], [1, 0, 1]].should.normal?
- Matrix[[0, Complex(0, 2)], [Complex(0, -2), 0]].should.normal?
- end
+ it "returns true for normal matrices" do
+ Matrix[[1, 1, 0], [0, 1, 1], [1, 0, 1]].should.normal?
+ Matrix[[0, Complex(0, 2)], [Complex(0, -2), 0]].should.normal?
+ end
- it "raises an error for rectangular matrices" do
- [
- Matrix[[0], [0]],
- Matrix[[0, 0]],
- Matrix.empty(0, 2),
- Matrix.empty(2, 0),
- ].each do |rectangular_matrix|
- -> {
- rectangular_matrix.normal?
- }.should raise_error(Matrix::ErrDimensionMismatch)
- end
+ it "raises an error for rectangular matrices" do
+ [
+ Matrix[[0], [0]],
+ Matrix[[0, 0]],
+ Matrix.empty(0, 2),
+ Matrix.empty(2, 0),
+ ].each do |rectangular_matrix|
+ -> {
+ rectangular_matrix.normal?
+ }.should raise_error(Matrix::ErrDimensionMismatch)
end
end
end
diff --git a/spec/ruby/library/matrix/orthogonal_spec.rb b/spec/ruby/library/matrix/orthogonal_spec.rb
index eb06305040..26afe89ff0 100644
--- a/spec/ruby/library/matrix/orthogonal_spec.rb
+++ b/spec/ruby/library/matrix/orthogonal_spec.rb
@@ -1,29 +1,26 @@
require_relative '../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
-
- describe "Matrix.orthogonal?" do
- it "returns false for non orthogonal matrices" do
- Matrix[[0, 1], [1, 2]].should_not.orthogonal?
- Matrix[[1, 1, 0], [0, 1, 1], [1, 0, 1]].should_not.orthogonal?
- end
+describe "Matrix.orthogonal?" do
+ it "returns false for non orthogonal matrices" do
+ Matrix[[0, 1], [1, 2]].should_not.orthogonal?
+ Matrix[[1, 1, 0], [0, 1, 1], [1, 0, 1]].should_not.orthogonal?
+ end
- it "returns true for orthogonal matrices" do
- Matrix[[0, 1], [1, 0]].should.orthogonal?
- end
+ it "returns true for orthogonal matrices" do
+ Matrix[[0, 1], [1, 0]].should.orthogonal?
+ end
- it "raises an error for rectangular matrices" do
- [
- Matrix[[0], [0]],
- Matrix[[0, 0]],
- Matrix.empty(0, 2),
- Matrix.empty(2, 0),
- ].each do |rectangular_matrix|
- -> {
- rectangular_matrix.orthogonal?
- }.should raise_error(Matrix::ErrDimensionMismatch)
- end
+ it "raises an error for rectangular matrices" do
+ [
+ Matrix[[0], [0]],
+ Matrix[[0, 0]],
+ Matrix.empty(0, 2),
+ Matrix.empty(2, 0),
+ ].each do |rectangular_matrix|
+ -> {
+ rectangular_matrix.orthogonal?
+ }.should raise_error(Matrix::ErrDimensionMismatch)
end
end
end
diff --git a/spec/ruby/library/matrix/permutation_spec.rb b/spec/ruby/library/matrix/permutation_spec.rb
index ed8edad755..825a9d982c 100644
--- a/spec/ruby/library/matrix/permutation_spec.rb
+++ b/spec/ruby/library/matrix/permutation_spec.rb
@@ -1,35 +1,32 @@
require_relative '../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
-
- describe "Matrix#permutation?" do
- it "returns true for a permutation Matrix" do
- Matrix[[0, 1, 0], [0, 0, 1], [1, 0, 0]].permutation?.should be_true
- end
+describe "Matrix#permutation?" do
+ it "returns true for a permutation Matrix" do
+ Matrix[[0, 1, 0], [0, 0, 1], [1, 0, 0]].permutation?.should be_true
+ end
- it "returns false for a non permutation square Matrix" do
- Matrix[[0, 1], [0, 0]].permutation?.should be_false
- Matrix[[-1, 0], [0, -1]].permutation?.should be_false
- Matrix[[1, 0], [1, 0]].permutation?.should be_false
- Matrix[[1, 0], [1, 1]].permutation?.should be_false
- end
+ it "returns false for a non permutation square Matrix" do
+ Matrix[[0, 1], [0, 0]].permutation?.should be_false
+ Matrix[[-1, 0], [0, -1]].permutation?.should be_false
+ Matrix[[1, 0], [1, 0]].permutation?.should be_false
+ Matrix[[1, 0], [1, 1]].permutation?.should be_false
+ end
- it "returns true for an empty 0x0 matrix" do
- Matrix.empty(0,0).permutation?.should be_true
- end
+ it "returns true for an empty 0x0 matrix" do
+ Matrix.empty(0,0).permutation?.should be_true
+ end
- it "raises an error for rectangular matrices" do
- [
- Matrix[[0], [0]],
- Matrix[[0, 0]],
- Matrix.empty(0, 2),
- Matrix.empty(2, 0),
- ].each do |rectangular_matrix|
- -> {
- rectangular_matrix.permutation?
- }.should raise_error(Matrix::ErrDimensionMismatch)
- end
+ it "raises an error for rectangular matrices" do
+ [
+ Matrix[[0], [0]],
+ Matrix[[0, 0]],
+ Matrix.empty(0, 2),
+ Matrix.empty(2, 0),
+ ].each do |rectangular_matrix|
+ -> {
+ rectangular_matrix.permutation?
+ }.should raise_error(Matrix::ErrDimensionMismatch)
end
end
end
diff --git a/spec/ruby/library/matrix/plus_spec.rb b/spec/ruby/library/matrix/plus_spec.rb
index 99e6615778..2706bad060 100644
--- a/spec/ruby/library/matrix/plus_spec.rb
+++ b/spec/ruby/library/matrix/plus_spec.rb
@@ -1,45 +1,42 @@
require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require_relative 'fixtures/classes'
- require 'matrix'
-
- describe "Matrix#+" do
- before :each do
- @a = Matrix[ [1,2], [3,4] ]
- @b = Matrix[ [4,5], [6,7] ]
- end
+describe "Matrix#+" do
+ before :each do
+ @a = Matrix[ [1,2], [3,4] ]
+ @b = Matrix[ [4,5], [6,7] ]
+ end
- it "returns the result of adding the corresponding elements of self and other" do
- (@a + @b).should == Matrix[ [5,7], [9,11] ]
- end
+ it "returns the result of adding the corresponding elements of self and other" do
+ (@a + @b).should == Matrix[ [5,7], [9,11] ]
+ end
- it "returns an instance of Matrix" do
- (@a + @b).should be_kind_of(Matrix)
- end
+ it "returns an instance of Matrix" do
+ (@a + @b).should be_kind_of(Matrix)
+ end
- it "raises a Matrix::ErrDimensionMismatch if the matrices are different sizes" do
- -> { @a + Matrix[ [1] ] }.should raise_error(Matrix::ErrDimensionMismatch)
- end
+ it "raises a Matrix::ErrDimensionMismatch if the matrices are different sizes" do
+ -> { @a + Matrix[ [1] ] }.should raise_error(Matrix::ErrDimensionMismatch)
+ end
- it "raises a ExceptionForMatrix::ErrOperationNotDefined if other is a Numeric Type" do
- -> { @a + 2 }.should raise_error(ExceptionForMatrix::ErrOperationNotDefined)
- -> { @a + 1.2 }.should raise_error(ExceptionForMatrix::ErrOperationNotDefined)
- -> { @a + bignum_value }.should raise_error(ExceptionForMatrix::ErrOperationNotDefined)
- end
+ it "raises a ExceptionForMatrix::ErrOperationNotDefined if other is a Numeric Type" do
+ -> { @a + 2 }.should raise_error(ExceptionForMatrix::ErrOperationNotDefined)
+ -> { @a + 1.2 }.should raise_error(ExceptionForMatrix::ErrOperationNotDefined)
+ -> { @a + bignum_value }.should raise_error(ExceptionForMatrix::ErrOperationNotDefined)
+ end
- it "raises a TypeError if other is of wrong type" do
- -> { @a + nil }.should raise_error(TypeError)
- -> { @a + "a" }.should raise_error(TypeError)
- -> { @a + [ [1, 2] ] }.should raise_error(TypeError)
- -> { @a + Object.new }.should raise_error(TypeError)
- end
+ it "raises a TypeError if other is of wrong type" do
+ -> { @a + nil }.should raise_error(TypeError)
+ -> { @a + "a" }.should raise_error(TypeError)
+ -> { @a + [ [1, 2] ] }.should raise_error(TypeError)
+ -> { @a + Object.new }.should raise_error(TypeError)
+ end
- describe "for a subclass of Matrix" do
- it "returns an instance of that subclass" do
- m = MatrixSub.ins
- (m+m).should be_an_instance_of(MatrixSub)
- end
+ describe "for a subclass of Matrix" do
+ it "returns an instance of that subclass" do
+ m = MatrixSub.ins
+ (m+m).should be_an_instance_of(MatrixSub)
end
end
end
diff --git a/spec/ruby/library/matrix/rank_spec.rb b/spec/ruby/library/matrix/rank_spec.rb
index fc795b58c1..d4403d23ed 100644
--- a/spec/ruby/library/matrix/rank_spec.rb
+++ b/spec/ruby/library/matrix/rank_spec.rb
@@ -1,22 +1,19 @@
require_relative '../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
-
- describe "Matrix#rank" do
- it "returns the rank of the Matrix" do
- Matrix[ [7,6], [3,9] ].rank.should == 2
- end
+describe "Matrix#rank" do
+ it "returns the rank of the Matrix" do
+ Matrix[ [7,6], [3,9] ].rank.should == 2
+ end
- it "doesn't loop forever" do
- Matrix[ [1,2,3], [4,5,6], [7,8,9] ].rank.should == 2
- Matrix[ [1, 2, 0, 3], [1, -2, 3, 0], [0, 0, 4, 8], [2, 4, 0, 6] ].rank.
- should == 3
- end
+ it "doesn't loop forever" do
+ Matrix[ [1,2,3], [4,5,6], [7,8,9] ].rank.should == 2
+ Matrix[ [1, 2, 0, 3], [1, -2, 3, 0], [0, 0, 4, 8], [2, 4, 0, 6] ].rank.
+ should == 3
+ end
- it "works for some easy rectangular matrices" do
- Matrix[[0,0],[0,0],[1,0]].rank.should == 1
- Matrix[[0,1],[0,0],[1,0]].rank.should == 2
- end
+ it "works for some easy rectangular matrices" do
+ Matrix[[0,0],[0,0],[1,0]].rank.should == 1
+ Matrix[[0,1],[0,0],[1,0]].rank.should == 2
end
end
diff --git a/spec/ruby/library/matrix/real_spec.rb b/spec/ruby/library/matrix/real_spec.rb
index 63a6bde923..38033c63c8 100644
--- a/spec/ruby/library/matrix/real_spec.rb
+++ b/spec/ruby/library/matrix/real_spec.rb
@@ -1,46 +1,43 @@
require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require_relative 'fixtures/classes'
- require 'matrix'
-
- describe "Matrix#real?" do
- it "returns true for matrices with all real entries" do
- Matrix[ [1, 2], [3, 4] ].real?.should be_true
- Matrix[ [1.9, 2], [3, 4] ].real?.should be_true
- end
+describe "Matrix#real?" do
+ it "returns true for matrices with all real entries" do
+ Matrix[ [1, 2], [3, 4] ].real?.should be_true
+ Matrix[ [1.9, 2], [3, 4] ].real?.should be_true
+ end
- it "returns true for empty matrices" do
- Matrix.empty.real?.should be_true
- end
+ it "returns true for empty matrices" do
+ Matrix.empty.real?.should be_true
+ end
- it "returns false if one element is a Complex" do
- Matrix[ [Complex(1,1), 2], [3, 4] ].real?.should be_false
- end
+ it "returns false if one element is a Complex" do
+ Matrix[ [Complex(1,1), 2], [3, 4] ].real?.should be_false
+ end
- # Guard against the Mathn library
- guard -> { !defined?(Math.rsqrt) } do
- it "returns false if one element is a Complex whose imaginary part is 0" do
- Matrix[ [Complex(1,0), 2], [3, 4] ].real?.should be_false
- end
+ # Guard against the Mathn library
+ guard -> { !defined?(Math.rsqrt) } do
+ it "returns false if one element is a Complex whose imaginary part is 0" do
+ Matrix[ [Complex(1,0), 2], [3, 4] ].real?.should be_false
end
end
+end
- describe "Matrix#real" do
- it "returns a matrix with the real part of the elements of the receiver" do
- Matrix[ [1, 2], [3, 4] ].real.should == Matrix[ [1, 2], [3, 4] ]
- Matrix[ [1.9, Complex(1,1)], [Complex(-0.42, 0), 4] ].real.should == Matrix[ [1.9, 1], [-0.42, 4] ]
- end
+describe "Matrix#real" do
+ it "returns a matrix with the real part of the elements of the receiver" do
+ Matrix[ [1, 2], [3, 4] ].real.should == Matrix[ [1, 2], [3, 4] ]
+ Matrix[ [1.9, Complex(1,1)], [Complex(-0.42, 0), 4] ].real.should == Matrix[ [1.9, 1], [-0.42, 4] ]
+ end
- it "returns empty matrices on the same size if empty" do
- Matrix.empty(0, 3).real.should == Matrix.empty(0, 3)
- Matrix.empty(3, 0).real.should == Matrix.empty(3, 0)
- end
+ it "returns empty matrices on the same size if empty" do
+ Matrix.empty(0, 3).real.should == Matrix.empty(0, 3)
+ Matrix.empty(3, 0).real.should == Matrix.empty(3, 0)
+ end
- describe "for a subclass of Matrix" do
- it "returns an instance of that subclass" do
- MatrixSub.ins.real.should be_an_instance_of(MatrixSub)
- end
+ describe "for a subclass of Matrix" do
+ it "returns an instance of that subclass" do
+ MatrixSub.ins.real.should be_an_instance_of(MatrixSub)
end
end
end
diff --git a/spec/ruby/library/matrix/rect_spec.rb b/spec/ruby/library/matrix/rect_spec.rb
index b3b7ac05c9..83a0404e47 100644
--- a/spec/ruby/library/matrix/rect_spec.rb
+++ b/spec/ruby/library/matrix/rect_spec.rb
@@ -1,9 +1,6 @@
require_relative '../../spec_helper'
+require_relative 'shared/rectangular'
-ruby_version_is ""..."3.1" do
- require_relative 'shared/rectangular'
-
- describe "Matrix#rect" do
- it_behaves_like :matrix_rectangular, :rect
- end
+describe "Matrix#rect" do
+ it_behaves_like :matrix_rectangular, :rect
end
diff --git a/spec/ruby/library/matrix/rectangular_spec.rb b/spec/ruby/library/matrix/rectangular_spec.rb
index 1fc2e0e60d..a235fac640 100644
--- a/spec/ruby/library/matrix/rectangular_spec.rb
+++ b/spec/ruby/library/matrix/rectangular_spec.rb
@@ -1,9 +1,6 @@
require_relative '../../spec_helper'
+require_relative 'shared/rectangular'
-ruby_version_is ""..."3.1" do
- require_relative 'shared/rectangular'
-
- describe "Matrix#rectangular" do
- it_behaves_like :matrix_rectangular, :rectangular
- end
+describe "Matrix#rectangular" do
+ it_behaves_like :matrix_rectangular, :rectangular
end
diff --git a/spec/ruby/library/matrix/regular_spec.rb b/spec/ruby/library/matrix/regular_spec.rb
index f6688bba30..3699d0ef8b 100644
--- a/spec/ruby/library/matrix/regular_spec.rb
+++ b/spec/ruby/library/matrix/regular_spec.rb
@@ -1,34 +1,31 @@
require_relative '../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
+describe "Matrix#regular?" do
- describe "Matrix#regular?" do
+ it "returns false for singular matrices" do
+ m = Matrix[ [1,2,3], [3,4,3], [0,0,0] ]
+ m.regular?.should be_false
- it "returns false for singular matrices" do
- m = Matrix[ [1,2,3], [3,4,3], [0,0,0] ]
- m.regular?.should be_false
-
- m = Matrix[ [1,2,9], [3,4,9], [1,2,9] ]
- m.regular?.should be_false
- end
+ m = Matrix[ [1,2,9], [3,4,9], [1,2,9] ]
+ m.regular?.should be_false
+ end
- it "returns true if the Matrix is regular" do
- Matrix[ [0,1], [1,0] ].regular?.should be_true
- end
+ it "returns true if the Matrix is regular" do
+ Matrix[ [0,1], [1,0] ].regular?.should be_true
+ end
- it "returns true for an empty 0x0 matrix" do
- Matrix.empty(0,0).regular?.should be_true
- end
+ it "returns true for an empty 0x0 matrix" do
+ Matrix.empty(0,0).regular?.should be_true
+ end
- it "raises an error for rectangular matrices" do
- -> {
- Matrix[[1], [2], [3]].regular?
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ it "raises an error for rectangular matrices" do
+ -> {
+ Matrix[[1], [2], [3]].regular?
+ }.should raise_error(Matrix::ErrDimensionMismatch)
- -> {
- Matrix.empty(3,0).regular?
- }.should raise_error(Matrix::ErrDimensionMismatch)
- end
+ -> {
+ Matrix.empty(3,0).regular?
+ }.should raise_error(Matrix::ErrDimensionMismatch)
end
end
diff --git a/spec/ruby/library/matrix/round_spec.rb b/spec/ruby/library/matrix/round_spec.rb
index db33268414..1dc29df890 100644
--- a/spec/ruby/library/matrix/round_spec.rb
+++ b/spec/ruby/library/matrix/round_spec.rb
@@ -1,24 +1,21 @@
require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require_relative 'fixtures/classes'
- require 'matrix'
-
- describe "Matrix#round" do
- it "returns a matrix with all entries rounded" do
- Matrix[ [1, 2.34], [5.67, 8] ].round.should == Matrix[ [1, 2], [6, 8] ]
- Matrix[ [1, 2.34], [5.67, 8] ].round(1).should == Matrix[ [1, 2.3], [5.7, 8] ]
- end
+describe "Matrix#round" do
+ it "returns a matrix with all entries rounded" do
+ Matrix[ [1, 2.34], [5.67, 8] ].round.should == Matrix[ [1, 2], [6, 8] ]
+ Matrix[ [1, 2.34], [5.67, 8] ].round(1).should == Matrix[ [1, 2.3], [5.7, 8] ]
+ end
- it "returns empty matrices on the same size if empty" do
- Matrix.empty(0, 3).round.should == Matrix.empty(0, 3)
- Matrix.empty(3, 0).round(42).should == Matrix.empty(3, 0)
- end
+ it "returns empty matrices on the same size if empty" do
+ Matrix.empty(0, 3).round.should == Matrix.empty(0, 3)
+ Matrix.empty(3, 0).round(42).should == Matrix.empty(3, 0)
+ end
- describe "for a subclass of Matrix" do
- it "returns an instance of that subclass" do
- MatrixSub.ins.round.should be_an_instance_of(MatrixSub)
- end
+ describe "for a subclass of Matrix" do
+ it "returns an instance of that subclass" do
+ MatrixSub.ins.round.should be_an_instance_of(MatrixSub)
end
end
end
diff --git a/spec/ruby/library/matrix/row_size_spec.rb b/spec/ruby/library/matrix/row_size_spec.rb
index fca5a846ab..eb3aef2e2f 100644
--- a/spec/ruby/library/matrix/row_size_spec.rb
+++ b/spec/ruby/library/matrix/row_size_spec.rb
@@ -1,16 +1,13 @@
require_relative '../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
-
- describe "Matrix#row_size" do
- it "returns the number rows" do
- Matrix[ [1,2], [3, 4], [5, 6] ].row_size.should == 3
- end
-
- it "returns the number rows even for some empty matrices" do
- Matrix[ [], [], [] ].row_size.should == 3
- end
+describe "Matrix#row_size" do
+ it "returns the number rows" do
+ Matrix[ [1,2], [3, 4], [5, 6] ].row_size.should == 3
+ end
+ it "returns the number rows even for some empty matrices" do
+ Matrix[ [], [], [] ].row_size.should == 3
end
+
end
diff --git a/spec/ruby/library/matrix/row_spec.rb b/spec/ruby/library/matrix/row_spec.rb
index eb05cd9273..00b1f02a8e 100644
--- a/spec/ruby/library/matrix/row_spec.rb
+++ b/spec/ruby/library/matrix/row_spec.rb
@@ -1,39 +1,36 @@
require_relative '../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
-
- describe "Matrix#row" do
- before :all do
- @m = Matrix[ [1, 2], [2, 3], [3, 4] ]
- end
+describe "Matrix#row" do
+ before :all do
+ @m = Matrix[ [1, 2], [2, 3], [3, 4] ]
+ end
- it "returns a Vector when called without a block" do
- @m.row(0).should == Vector[1,2]
- end
+ it "returns a Vector when called without a block" do
+ @m.row(0).should == Vector[1,2]
+ end
- it "yields the elements of the row when called with a block" do
- a = []
- @m.row(0) {|x| a << x}
- a.should == [1,2]
- end
+ it "yields the elements of the row when called with a block" do
+ a = []
+ @m.row(0) {|x| a << x}
+ a.should == [1,2]
+ end
- it "counts backwards for negative argument" do
- @m.row(-1).should == Vector[3, 4]
- end
+ it "counts backwards for negative argument" do
+ @m.row(-1).should == Vector[3, 4]
+ end
- it "returns self when called with a block" do
- @m.row(0) { |x| x }.should equal(@m)
- end
+ it "returns self when called with a block" do
+ @m.row(0) { |x| x }.should equal(@m)
+ end
- it "returns nil when out of bounds" do
- @m.row(3).should == nil
- @m.row(-4).should == nil
- end
+ it "returns nil when out of bounds" do
+ @m.row(3).should == nil
+ @m.row(-4).should == nil
+ end
- it "never yields when out of bounds" do
- -> { @m.row(3){ raise } }.should_not raise_error
- -> { @m.row(-4){ raise } }.should_not raise_error
- end
+ it "never yields when out of bounds" do
+ -> { @m.row(3){ raise } }.should_not raise_error
+ -> { @m.row(-4){ raise } }.should_not raise_error
end
end
diff --git a/spec/ruby/library/matrix/row_vector_spec.rb b/spec/ruby/library/matrix/row_vector_spec.rb
index 4c97d6013a..341437ee05 100644
--- a/spec/ruby/library/matrix/row_vector_spec.rb
+++ b/spec/ruby/library/matrix/row_vector_spec.rb
@@ -1,27 +1,24 @@
require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require_relative 'fixtures/classes'
- require 'matrix'
+describe "Matrix.row_vector" do
- describe "Matrix.row_vector" do
-
- it "returns a Matrix" do
- Matrix.row_vector([]).should be_an_instance_of(Matrix)
- end
+ it "returns a Matrix" do
+ Matrix.row_vector([]).should be_an_instance_of(Matrix)
+ end
- it "returns a single-row Matrix with the specified values" do
- Matrix.row_vector([1,2]).should == Matrix[ [1,2] ]
- end
+ it "returns a single-row Matrix with the specified values" do
+ Matrix.row_vector([1,2]).should == Matrix[ [1,2] ]
+ end
- it "returns a 1x0 matrix when called with an empty Array" do
- Matrix.row_vector([]).should == Matrix[ [] ]
- end
+ it "returns a 1x0 matrix when called with an empty Array" do
+ Matrix.row_vector([]).should == Matrix[ [] ]
+ end
- describe "for a subclass of Matrix" do
- it "returns an instance of that subclass" do
- MatrixSub.row_vector([1]).should be_an_instance_of(MatrixSub)
- end
+ describe "for a subclass of Matrix" do
+ it "returns an instance of that subclass" do
+ MatrixSub.row_vector([1]).should be_an_instance_of(MatrixSub)
end
end
end
diff --git a/spec/ruby/library/matrix/row_vectors_spec.rb b/spec/ruby/library/matrix/row_vectors_spec.rb
index d01a4ca10d..6f99c439a6 100644
--- a/spec/ruby/library/matrix/row_vectors_spec.rb
+++ b/spec/ruby/library/matrix/row_vectors_spec.rb
@@ -1,29 +1,26 @@
require_relative '../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
+describe "Matrix#row_vectors" do
- describe "Matrix#row_vectors" do
-
- before :each do
- @vectors = Matrix[ [1,2], [3,4] ].row_vectors
- end
+ before :each do
+ @vectors = Matrix[ [1,2], [3,4] ].row_vectors
+ end
- it "returns an Array" do
- Matrix[ [1,2], [3,4] ].row_vectors.should be_an_instance_of(Array)
- end
+ it "returns an Array" do
+ Matrix[ [1,2], [3,4] ].row_vectors.should be_an_instance_of(Array)
+ end
- it "returns an Array of Vectors" do
- @vectors.all? {|v| v.should be_an_instance_of(Vector)}
- end
+ it "returns an Array of Vectors" do
+ @vectors.all? {|v| v.should be_an_instance_of(Vector)}
+ end
- it "returns each row as a Vector" do
- @vectors.should == [Vector[1,2], Vector[3,4]]
- end
+ it "returns each row as a Vector" do
+ @vectors.should == [Vector[1,2], Vector[3,4]]
+ end
- it "returns an empty Array for empty matrices" do
- Matrix[].row_vectors.should == []
- Matrix[ [] ].row_vectors.should == [ Vector[] ]
- end
+ it "returns an empty Array for empty matrices" do
+ Matrix[].row_vectors.should == []
+ Matrix[ [] ].row_vectors.should == [ Vector[] ]
end
end
diff --git a/spec/ruby/library/matrix/rows_spec.rb b/spec/ruby/library/matrix/rows_spec.rb
index 5f0515a37b..41ba635775 100644
--- a/spec/ruby/library/matrix/rows_spec.rb
+++ b/spec/ruby/library/matrix/rows_spec.rb
@@ -1,44 +1,41 @@
require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require_relative 'fixtures/classes'
- require 'matrix'
-
- describe "Matrix.rows" do
- before :each do
- @a = [1, 2]
- @b = [3, 4]
- @m = Matrix.rows([@a, @b])
- end
+describe "Matrix.rows" do
+ before :each do
+ @a = [1, 2]
+ @b = [3, 4]
+ @m = Matrix.rows([@a, @b])
+ end
- it "returns a Matrix" do
- @m.should be_kind_of(Matrix)
- end
+ it "returns a Matrix" do
+ @m.should be_kind_of(Matrix)
+ end
- it "creates a matrix from argument rows" do
- @m.row(0).to_a.should == @a
- @m.row(1).to_a.should == @b
- end
+ it "creates a matrix from argument rows" do
+ @m.row(0).to_a.should == @a
+ @m.row(1).to_a.should == @b
+ end
- it "copies the original rows by default" do
- @a << 3
- @b << 6
- @m.row(0).should_not equal(@a)
- @m.row(1).should_not equal(@b)
- end
+ it "copies the original rows by default" do
+ @a << 3
+ @b << 6
+ @m.row(0).should_not equal(@a)
+ @m.row(1).should_not equal(@b)
+ end
- it "references the original rows if copy is false" do
- @m_ref = Matrix.rows([@a, @b], false)
- @a << 3
- @b << 6
- @m_ref.row(0).to_a.should == @a
- @m_ref.row(1).to_a.should == @b
- end
+ it "references the original rows if copy is false" do
+ @m_ref = Matrix.rows([@a, @b], false)
+ @a << 3
+ @b << 6
+ @m_ref.row(0).to_a.should == @a
+ @m_ref.row(1).to_a.should == @b
+ end
- describe "for a subclass of Matrix" do
- it "returns an instance of that subclass" do
- MatrixSub.rows([[0, 1], [0, 1]]).should be_an_instance_of(MatrixSub)
- end
+ describe "for a subclass of Matrix" do
+ it "returns an instance of that subclass" do
+ MatrixSub.rows([[0, 1], [0, 1]]).should be_an_instance_of(MatrixSub)
end
end
end
diff --git a/spec/ruby/library/matrix/scalar/Fail_spec.rb b/spec/ruby/library/matrix/scalar/Fail_spec.rb
index 4f774eda28..9d8f9bd5e8 100644
--- a/spec/ruby/library/matrix/scalar/Fail_spec.rb
+++ b/spec/ruby/library/matrix/scalar/Fail_spec.rb
@@ -1,9 +1,6 @@
require_relative '../../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
-
- describe "Matrix::Scalar#Fail" do
- it "needs to be reviewed for spec completeness"
- end
+describe "Matrix::Scalar#Fail" do
+ it "needs to be reviewed for spec completeness"
end
diff --git a/spec/ruby/library/matrix/scalar/Raise_spec.rb b/spec/ruby/library/matrix/scalar/Raise_spec.rb
index b405b6d6c5..27e11c1f77 100644
--- a/spec/ruby/library/matrix/scalar/Raise_spec.rb
+++ b/spec/ruby/library/matrix/scalar/Raise_spec.rb
@@ -1,9 +1,6 @@
require_relative '../../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
-
- describe "Matrix::Scalar#Raise" do
- it "needs to be reviewed for spec completeness"
- end
+describe "Matrix::Scalar#Raise" do
+ it "needs to be reviewed for spec completeness"
end
diff --git a/spec/ruby/library/matrix/scalar/divide_spec.rb b/spec/ruby/library/matrix/scalar/divide_spec.rb
index 0ef2206bf6..5d726943fe 100644
--- a/spec/ruby/library/matrix/scalar/divide_spec.rb
+++ b/spec/ruby/library/matrix/scalar/divide_spec.rb
@@ -1,9 +1,6 @@
require_relative '../../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
-
- describe "Matrix::Scalar#/" do
- it "needs to be reviewed for spec completeness"
- end
+describe "Matrix::Scalar#/" do
+ it "needs to be reviewed for spec completeness"
end
diff --git a/spec/ruby/library/matrix/scalar/exponent_spec.rb b/spec/ruby/library/matrix/scalar/exponent_spec.rb
index 87eea283d1..8e9ef52ff2 100644
--- a/spec/ruby/library/matrix/scalar/exponent_spec.rb
+++ b/spec/ruby/library/matrix/scalar/exponent_spec.rb
@@ -1,9 +1,6 @@
require_relative '../../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
-
- describe "Matrix::Scalar#**" do
- it "needs to be reviewed for spec completeness"
- end
+describe "Matrix::Scalar#**" do
+ it "needs to be reviewed for spec completeness"
end
diff --git a/spec/ruby/library/matrix/scalar/included_spec.rb b/spec/ruby/library/matrix/scalar/included_spec.rb
index bab80e5120..cb3beb2ecd 100644
--- a/spec/ruby/library/matrix/scalar/included_spec.rb
+++ b/spec/ruby/library/matrix/scalar/included_spec.rb
@@ -1,9 +1,6 @@
require_relative '../../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
-
- describe "Matrix::Scalar.included" do
- it "needs to be reviewed for spec completeness"
- end
+describe "Matrix::Scalar.included" do
+ it "needs to be reviewed for spec completeness"
end
diff --git a/spec/ruby/library/matrix/scalar/initialize_spec.rb b/spec/ruby/library/matrix/scalar/initialize_spec.rb
index af51562b43..23145ad0de 100644
--- a/spec/ruby/library/matrix/scalar/initialize_spec.rb
+++ b/spec/ruby/library/matrix/scalar/initialize_spec.rb
@@ -1,9 +1,6 @@
require_relative '../../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
-
- describe "Matrix::Scalar#initialize" do
- it "needs to be reviewed for spec completeness"
- end
+describe "Matrix::Scalar#initialize" do
+ it "needs to be reviewed for spec completeness"
end
diff --git a/spec/ruby/library/matrix/scalar/minus_spec.rb b/spec/ruby/library/matrix/scalar/minus_spec.rb
index 966db1d75b..c727ea1659 100644
--- a/spec/ruby/library/matrix/scalar/minus_spec.rb
+++ b/spec/ruby/library/matrix/scalar/minus_spec.rb
@@ -1,9 +1,6 @@
require_relative '../../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
-
- describe "Matrix::Scalar#-" do
- it "needs to be reviewed for spec completeness"
- end
+describe "Matrix::Scalar#-" do
+ it "needs to be reviewed for spec completeness"
end
diff --git a/spec/ruby/library/matrix/scalar/multiply_spec.rb b/spec/ruby/library/matrix/scalar/multiply_spec.rb
index 21caac478b..1a2a83d83e 100644
--- a/spec/ruby/library/matrix/scalar/multiply_spec.rb
+++ b/spec/ruby/library/matrix/scalar/multiply_spec.rb
@@ -1,9 +1,6 @@
require_relative '../../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
-
- describe "Matrix::Scalar#*" do
- it "needs to be reviewed for spec completeness"
- end
+describe "Matrix::Scalar#*" do
+ it "needs to be reviewed for spec completeness"
end
diff --git a/spec/ruby/library/matrix/scalar/plus_spec.rb b/spec/ruby/library/matrix/scalar/plus_spec.rb
index 78cdf9367f..c94689a702 100644
--- a/spec/ruby/library/matrix/scalar/plus_spec.rb
+++ b/spec/ruby/library/matrix/scalar/plus_spec.rb
@@ -1,9 +1,6 @@
require_relative '../../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
-
- describe "Matrix::Scalar#+" do
- it "needs to be reviewed for spec completeness"
- end
+describe "Matrix::Scalar#+" do
+ it "needs to be reviewed for spec completeness"
end
diff --git a/spec/ruby/library/matrix/scalar_spec.rb b/spec/ruby/library/matrix/scalar_spec.rb
index 1ec64d2d78..7fdd64c9d9 100644
--- a/spec/ruby/library/matrix/scalar_spec.rb
+++ b/spec/ruby/library/matrix/scalar_spec.rb
@@ -1,68 +1,65 @@
require_relative '../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
+describe "Matrix.scalar" do
- describe "Matrix.scalar" do
-
- before :each do
- @side = 3
- @value = 8
- @a = Matrix.scalar(@side, @value)
- end
+ before :each do
+ @side = 3
+ @value = 8
+ @a = Matrix.scalar(@side, @value)
+ end
- it "returns a Matrix" do
- @a.should be_kind_of(Matrix)
- end
+ it "returns a Matrix" do
+ @a.should be_kind_of(Matrix)
+ end
- it "returns a n x n matrix" do
- @a.row_size.should == @side
- @a.column_size.should == @side
- end
+ it "returns a n x n matrix" do
+ @a.row_size.should == @side
+ @a.column_size.should == @side
+ end
- it "initializes diagonal to value" do
- (0...@a.row_size).each do |i|
- @a[i, i].should == @value
- end
+ it "initializes diagonal to value" do
+ (0...@a.row_size).each do |i|
+ @a[i, i].should == @value
end
+ end
- it "initializes all non-diagonal values to 0" do
- (0...@a.row_size).each do |i|
- (0...@a.column_size).each do |j|
- if i != j
- @a[i, j].should == 0
- end
+ it "initializes all non-diagonal values to 0" do
+ (0...@a.row_size).each do |i|
+ (0...@a.column_size).each do |j|
+ if i != j
+ @a[i, j].should == 0
end
end
end
+ end
- before :each do
- @side = 3
- @value = 8
- @a = Matrix.scalar(@side, @value)
- end
+ before :each do
+ @side = 3
+ @value = 8
+ @a = Matrix.scalar(@side, @value)
+ end
- it "returns a Matrix" do
- @a.should be_kind_of(Matrix)
- end
+ it "returns a Matrix" do
+ @a.should be_kind_of(Matrix)
+ end
- it "returns a square matrix, where the first argument specifies the side of the square" do
- @a.row_size.should == @side
- @a.column_size.should == @side
- end
+ it "returns a square matrix, where the first argument specifies the side of the square" do
+ @a.row_size.should == @side
+ @a.column_size.should == @side
+ end
- it "puts the second argument in all diagonal values" do
- (0...@a.row_size).each do |i|
- @a[i, i].should == @value
- end
+ it "puts the second argument in all diagonal values" do
+ (0...@a.row_size).each do |i|
+ @a[i, i].should == @value
end
+ end
- it "fills all values not on the main diagonal with 0" do
- (0...@a.row_size).each do |i|
- (0...@a.column_size).each do |j|
- if i != j
- @a[i, j].should == 0
- end
+ it "fills all values not on the main diagonal with 0" do
+ (0...@a.row_size).each do |i|
+ (0...@a.column_size).each do |j|
+ if i != j
+ @a[i, j].should == 0
end
end
end
diff --git a/spec/ruby/library/matrix/singular_spec.rb b/spec/ruby/library/matrix/singular_spec.rb
index 341c2675a8..7bba36a54a 100644
--- a/spec/ruby/library/matrix/singular_spec.rb
+++ b/spec/ruby/library/matrix/singular_spec.rb
@@ -1,34 +1,31 @@
require_relative '../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
+describe "Matrix#singular?" do
+ it "returns true for singular matrices" do
+ m = Matrix[ [1,2,3], [3,4,3], [0,0,0] ]
+ m.singular?.should be_true
- describe "Matrix#singular?" do
- it "returns true for singular matrices" do
- m = Matrix[ [1,2,3], [3,4,3], [0,0,0] ]
- m.singular?.should be_true
-
- m = Matrix[ [1,2,9], [3,4,9], [1,2,9] ]
- m.singular?.should be_true
- end
-
- it "returns false if the Matrix is regular" do
- Matrix[ [0,1], [1,0] ].singular?.should be_false
- end
+ m = Matrix[ [1,2,9], [3,4,9], [1,2,9] ]
+ m.singular?.should be_true
+ end
- it "returns false for an empty 0x0 matrix" do
- Matrix.empty(0,0).singular?.should be_false
- end
+ it "returns false if the Matrix is regular" do
+ Matrix[ [0,1], [1,0] ].singular?.should be_false
+ end
- it "raises an error for rectangular matrices" do
- -> {
- Matrix[[1], [2], [3]].singular?
- }.should raise_error(Matrix::ErrDimensionMismatch)
+ it "returns false for an empty 0x0 matrix" do
+ Matrix.empty(0,0).singular?.should be_false
+ end
- -> {
- Matrix.empty(3,0).singular?
- }.should raise_error(Matrix::ErrDimensionMismatch)
- end
+ it "raises an error for rectangular matrices" do
+ -> {
+ Matrix[[1], [2], [3]].singular?
+ }.should raise_error(Matrix::ErrDimensionMismatch)
+ -> {
+ Matrix.empty(3,0).singular?
+ }.should raise_error(Matrix::ErrDimensionMismatch)
end
+
end
diff --git a/spec/ruby/library/matrix/square_spec.rb b/spec/ruby/library/matrix/square_spec.rb
index e678f1c702..25d2d1ad9c 100644
--- a/spec/ruby/library/matrix/square_spec.rb
+++ b/spec/ruby/library/matrix/square_spec.rb
@@ -1,31 +1,28 @@
require_relative '../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
+describe "Matrix#square?" do
- describe "Matrix#square?" do
-
- it "returns true when the Matrix is square" do
- Matrix[ [1,2], [2,4] ].square?.should be_true
- Matrix[ [100,3,5], [9.5, 4.9, 8], [2,0,77] ].square?.should be_true
- end
+ it "returns true when the Matrix is square" do
+ Matrix[ [1,2], [2,4] ].square?.should be_true
+ Matrix[ [100,3,5], [9.5, 4.9, 8], [2,0,77] ].square?.should be_true
+ end
- it "returns true when the Matrix has only one element" do
- Matrix[ [9] ].square?.should be_true
- end
+ it "returns true when the Matrix has only one element" do
+ Matrix[ [9] ].square?.should be_true
+ end
- it "returns false when the Matrix is rectangular" do
- Matrix[ [1, 2] ].square?.should be_false
- end
+ it "returns false when the Matrix is rectangular" do
+ Matrix[ [1, 2] ].square?.should be_false
+ end
- it "returns false when the Matrix is rectangular" do
- Matrix[ [1], [2] ].square?.should be_false
- end
+ it "returns false when the Matrix is rectangular" do
+ Matrix[ [1], [2] ].square?.should be_false
+ end
- it "returns handles empty matrices" do
- Matrix[].square?.should be_true
- Matrix[[]].square?.should be_false
- Matrix.columns([[]]).square?.should be_false
- end
+ it "returns handles empty matrices" do
+ Matrix[].square?.should be_true
+ Matrix[[]].square?.should be_false
+ Matrix.columns([[]]).square?.should be_false
end
end
diff --git a/spec/ruby/library/matrix/symmetric_spec.rb b/spec/ruby/library/matrix/symmetric_spec.rb
index 9eed28ac0d..6f2a99276a 100644
--- a/spec/ruby/library/matrix/symmetric_spec.rb
+++ b/spec/ruby/library/matrix/symmetric_spec.rb
@@ -1,32 +1,29 @@
require_relative '../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
-
- describe "Matrix.symmetric?" do
- it "returns true for a symmetric Matrix" do
- Matrix[[1, 2, Complex(0, 3)], [2, 4, 5], [Complex(0, 3), 5, 6]].symmetric?.should be_true
- end
+describe "Matrix.symmetric?" do
+ it "returns true for a symmetric Matrix" do
+ Matrix[[1, 2, Complex(0, 3)], [2, 4, 5], [Complex(0, 3), 5, 6]].symmetric?.should be_true
+ end
- it "returns true for a 0x0 empty matrix" do
- Matrix.empty.symmetric?.should be_true
- end
+ it "returns true for a 0x0 empty matrix" do
+ Matrix.empty.symmetric?.should be_true
+ end
- it "returns false for an asymmetric Matrix" do
- Matrix[[1, 2],[-2, 1]].symmetric?.should be_false
- end
+ it "returns false for an asymmetric Matrix" do
+ Matrix[[1, 2],[-2, 1]].symmetric?.should be_false
+ end
- it "raises an error for rectangular matrices" do
- [
- Matrix[[0], [0]],
- Matrix[[0, 0]],
- Matrix.empty(0, 2),
- Matrix.empty(2, 0),
- ].each do |rectangular_matrix|
- -> {
- rectangular_matrix.symmetric?
- }.should raise_error(Matrix::ErrDimensionMismatch)
- end
+ it "raises an error for rectangular matrices" do
+ [
+ Matrix[[0], [0]],
+ Matrix[[0, 0]],
+ Matrix.empty(0, 2),
+ Matrix.empty(2, 0),
+ ].each do |rectangular_matrix|
+ -> {
+ rectangular_matrix.symmetric?
+ }.should raise_error(Matrix::ErrDimensionMismatch)
end
end
end
diff --git a/spec/ruby/library/matrix/t_spec.rb b/spec/ruby/library/matrix/t_spec.rb
index 6eb54371ee..6f1a5178e0 100644
--- a/spec/ruby/library/matrix/t_spec.rb
+++ b/spec/ruby/library/matrix/t_spec.rb
@@ -1,9 +1,6 @@
require_relative '../../spec_helper'
+require_relative 'shared/transpose'
-ruby_version_is ""..."3.1" do
- require_relative 'shared/transpose'
-
- describe "Matrix#transpose" do
- it_behaves_like :matrix_transpose, :t
- end
+describe "Matrix#transpose" do
+ it_behaves_like :matrix_transpose, :t
end
diff --git a/spec/ruby/library/matrix/to_a_spec.rb b/spec/ruby/library/matrix/to_a_spec.rb
index 0222a663ac..b5d55c5d67 100644
--- a/spec/ruby/library/matrix/to_a_spec.rb
+++ b/spec/ruby/library/matrix/to_a_spec.rb
@@ -1,14 +1,11 @@
require_relative '../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
-
- describe "Matrix#to_a" do
- it "returns the array of arrays that describe the rows of the matrix" do
- Matrix[].to_a.should == []
- Matrix[[]].to_a.should == [[]]
- Matrix[[1]].to_a.should == [[1]]
- Matrix[[1, 2], [3, 4]].to_a.should == [[1, 2],[3, 4]]
- end
+describe "Matrix#to_a" do
+ it "returns the array of arrays that describe the rows of the matrix" do
+ Matrix[].to_a.should == []
+ Matrix[[]].to_a.should == [[]]
+ Matrix[[1]].to_a.should == [[1]]
+ Matrix[[1, 2], [3, 4]].to_a.should == [[1, 2],[3, 4]]
end
end
diff --git a/spec/ruby/library/matrix/to_s_spec.rb b/spec/ruby/library/matrix/to_s_spec.rb
index 7d38655e0d..f529fe3bcd 100644
--- a/spec/ruby/library/matrix/to_s_spec.rb
+++ b/spec/ruby/library/matrix/to_s_spec.rb
@@ -1,9 +1,6 @@
require_relative '../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
-
- describe "Matrix#to_s" do
- it "needs to be reviewed for spec completeness"
- end
+describe "Matrix#to_s" do
+ it "needs to be reviewed for spec completeness"
end
diff --git a/spec/ruby/library/matrix/tr_spec.rb b/spec/ruby/library/matrix/tr_spec.rb
index bbf274bb5e..e17bd790d7 100644
--- a/spec/ruby/library/matrix/tr_spec.rb
+++ b/spec/ruby/library/matrix/tr_spec.rb
@@ -1,10 +1,7 @@
require_relative '../../spec_helper'
+require_relative 'shared/trace'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require_relative 'shared/trace'
- require 'matrix'
-
- describe "Matrix#tr" do
- it_behaves_like :trace, :tr
- end
+describe "Matrix#tr" do
+ it_behaves_like :trace, :tr
end
diff --git a/spec/ruby/library/matrix/trace_spec.rb b/spec/ruby/library/matrix/trace_spec.rb
index ac6ce7927d..290e7cb1f7 100644
--- a/spec/ruby/library/matrix/trace_spec.rb
+++ b/spec/ruby/library/matrix/trace_spec.rb
@@ -1,10 +1,7 @@
require_relative '../../spec_helper'
+require_relative 'shared/trace'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require_relative 'shared/trace'
- require 'matrix'
-
- describe "Matrix#trace" do
- it_behaves_like :trace, :trace
- end
+describe "Matrix#trace" do
+ it_behaves_like :trace, :trace
end
diff --git a/spec/ruby/library/matrix/transpose_spec.rb b/spec/ruby/library/matrix/transpose_spec.rb
index d7f495b946..79600dd439 100644
--- a/spec/ruby/library/matrix/transpose_spec.rb
+++ b/spec/ruby/library/matrix/transpose_spec.rb
@@ -1,9 +1,6 @@
require_relative '../../spec_helper'
+require_relative 'shared/transpose'
-ruby_version_is ""..."3.1" do
- require_relative 'shared/transpose'
-
- describe "Matrix#transpose" do
- it_behaves_like :matrix_transpose, :transpose
- end
+describe "Matrix#transpose" do
+ it_behaves_like :matrix_transpose, :transpose
end
diff --git a/spec/ruby/library/matrix/unit_spec.rb b/spec/ruby/library/matrix/unit_spec.rb
index 439e0d616b..6a41d729c7 100644
--- a/spec/ruby/library/matrix/unit_spec.rb
+++ b/spec/ruby/library/matrix/unit_spec.rb
@@ -1,9 +1,6 @@
require_relative '../../spec_helper'
+require_relative 'shared/identity'
-ruby_version_is ""..."3.1" do
- require_relative 'shared/identity'
-
- describe "Matrix.unit" do
- it_behaves_like :matrix_identity, :unit
- end
+describe "Matrix.unit" do
+ it_behaves_like :matrix_identity, :unit
end
diff --git a/spec/ruby/library/matrix/unitary_spec.rb b/spec/ruby/library/matrix/unitary_spec.rb
index b579cb244d..c214ee9b2f 100644
--- a/spec/ruby/library/matrix/unitary_spec.rb
+++ b/spec/ruby/library/matrix/unitary_spec.rb
@@ -1,36 +1,32 @@
require_relative '../../spec_helper'
-ruby_version_is ""..."3.1" do
- require 'matrix'
+require 'matrix'
- describe "Matrix.unitary?" do
- it "returns false for non unitary matrices" do
- Matrix[[0, 1], [1, 2]].should_not.unitary?
- Matrix[[0, Complex(0, 2)], [Complex(0, 2), 0]].should_not.unitary?
- Matrix[[1, 1, 0], [0, 1, 1], [1, 0, 1]].should_not.unitary?
- end
+describe "Matrix.unitary?" do
+ it "returns false for non unitary matrices" do
+ Matrix[[0, 1], [1, 2]].should_not.unitary?
+ Matrix[[0, Complex(0, 2)], [Complex(0, 2), 0]].should_not.unitary?
+ Matrix[[1, 1, 0], [0, 1, 1], [1, 0, 1]].should_not.unitary?
+ end
- it "returns true for unitary matrices" do
- Matrix[[0, Complex(0, 1)], [Complex(0, 1), 0]].should.unitary?
- end
+ it "returns true for unitary matrices" do
+ Matrix[[0, Complex(0, 1)], [Complex(0, 1), 0]].should.unitary?
+ end
- version_is((Matrix::const_defined?(:VERSION) ? Matrix::VERSION : "0.1.0"), "0.3.0") do
- it "returns true for unitary matrices with a Complex and a negative #imag" do
- Matrix[[0, Complex(0, 1)], [Complex(0, -1), 0]].should.unitary?
- end
- end
+ it "returns true for unitary matrices with a Complex and a negative #imag" do
+ Matrix[[0, Complex(0, 1)], [Complex(0, -1), 0]].should.unitary?
+ end
- it "raises an error for rectangular matrices" do
- [
- Matrix[[0], [0]],
- Matrix[[0, 0]],
- Matrix.empty(0, 2),
- Matrix.empty(2, 0),
- ].each do |rectangular_matrix|
- -> {
- rectangular_matrix.unitary?
- }.should raise_error(Matrix::ErrDimensionMismatch)
- end
+ it "raises an error for rectangular matrices" do
+ [
+ Matrix[[0], [0]],
+ Matrix[[0, 0]],
+ Matrix.empty(0, 2),
+ Matrix.empty(2, 0),
+ ].each do |rectangular_matrix|
+ -> {
+ rectangular_matrix.unitary?
+ }.should raise_error(Matrix::ErrDimensionMismatch)
end
end
end
diff --git a/spec/ruby/library/matrix/upper_triangular_spec.rb b/spec/ruby/library/matrix/upper_triangular_spec.rb
index cc2aeb7233..2514294a80 100644
--- a/spec/ruby/library/matrix/upper_triangular_spec.rb
+++ b/spec/ruby/library/matrix/upper_triangular_spec.rb
@@ -1,27 +1,24 @@
require_relative '../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
-
- describe "Matrix.upper_triangular?" do
- it "returns true for an upper triangular Matrix" do
- Matrix[[1, 2, 3], [0, 2, 3], [0, 0, 3]].upper_triangular?.should be_true
- Matrix.diagonal([1, 2, 3]).upper_triangular?.should be_true
- Matrix[[1, 2], [0, 2], [0, 0], [0, 0]].upper_triangular?.should be_true
- Matrix[[1, 2, 3, 4], [0, 2, 3, 4]].upper_triangular?.should be_true
- end
+describe "Matrix.upper_triangular?" do
+ it "returns true for an upper triangular Matrix" do
+ Matrix[[1, 2, 3], [0, 2, 3], [0, 0, 3]].upper_triangular?.should be_true
+ Matrix.diagonal([1, 2, 3]).upper_triangular?.should be_true
+ Matrix[[1, 2], [0, 2], [0, 0], [0, 0]].upper_triangular?.should be_true
+ Matrix[[1, 2, 3, 4], [0, 2, 3, 4]].upper_triangular?.should be_true
+ end
- it "returns false for a non upper triangular square Matrix" do
- Matrix[[0, 0], [1, 0]].upper_triangular?.should be_false
- Matrix[[1, 2, 3], [1, 2, 3], [1, 2, 3]].upper_triangular?.should be_false
- Matrix[[0, 0], [0, 0], [0, 0], [0, 1]].upper_triangular?.should be_false
- Matrix[[0, 0, 0, 0], [1, 0, 0, 0]].upper_triangular?.should be_false
- end
+ it "returns false for a non upper triangular square Matrix" do
+ Matrix[[0, 0], [1, 0]].upper_triangular?.should be_false
+ Matrix[[1, 2, 3], [1, 2, 3], [1, 2, 3]].upper_triangular?.should be_false
+ Matrix[[0, 0], [0, 0], [0, 0], [0, 1]].upper_triangular?.should be_false
+ Matrix[[0, 0, 0, 0], [1, 0, 0, 0]].upper_triangular?.should be_false
+ end
- it "returns true for an empty matrix" do
- Matrix.empty(3,0).upper_triangular?.should be_true
- Matrix.empty(0,3).upper_triangular?.should be_true
- Matrix.empty(0,0).upper_triangular?.should be_true
- end
+ it "returns true for an empty matrix" do
+ Matrix.empty(3,0).upper_triangular?.should be_true
+ Matrix.empty(0,3).upper_triangular?.should be_true
+ Matrix.empty(0,0).upper_triangular?.should be_true
end
end
diff --git a/spec/ruby/library/matrix/vector/cross_product_spec.rb b/spec/ruby/library/matrix/vector/cross_product_spec.rb
index 88523824cd..c2698ade4c 100644
--- a/spec/ruby/library/matrix/vector/cross_product_spec.rb
+++ b/spec/ruby/library/matrix/vector/cross_product_spec.rb
@@ -1,17 +1,14 @@
require_relative '../../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
-
- describe "Vector#cross_product" do
- it "returns the cross product of a vector" do
- Vector[1, 2, 3].cross_product(Vector[0, -4, 5]).should == Vector[22, -5, -4]
- end
+describe "Vector#cross_product" do
+ it "returns the cross product of a vector" do
+ Vector[1, 2, 3].cross_product(Vector[0, -4, 5]).should == Vector[22, -5, -4]
+ end
- it "raises an error unless both vectors have dimension 3" do
- -> {
- Vector[1, 2, 3].cross_product(Vector[0, -4])
- }.should raise_error(Vector::ErrDimensionMismatch)
- end
+ it "raises an error unless both vectors have dimension 3" do
+ -> {
+ Vector[1, 2, 3].cross_product(Vector[0, -4])
+ }.should raise_error(Vector::ErrDimensionMismatch)
end
end
diff --git a/spec/ruby/library/matrix/vector/each2_spec.rb b/spec/ruby/library/matrix/vector/each2_spec.rb
index bdd6966472..10d2fc404d 100644
--- a/spec/ruby/library/matrix/vector/each2_spec.rb
+++ b/spec/ruby/library/matrix/vector/each2_spec.rb
@@ -1,52 +1,49 @@
require_relative '../../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
+describe "Vector.each2" do
+ before :all do
+ @v = Vector[1, 2, 3]
+ @v2 = Vector[4, 5, 6]
+ end
+
+ it "requires one argument" do
+ -> { @v.each2(@v2, @v2){} }.should raise_error(ArgumentError)
+ -> { @v.each2(){} }.should raise_error(ArgumentError)
+ end
+
+ describe "given one argument" do
+ it "accepts an Array argument" do
+ a = []
+ @v.each2([7, 8, 9]){|x, y| a << x << y}
+ a.should == [1, 7, 2, 8, 3, 9]
+ end
+
+ it "raises a DimensionMismatch error if the Vector size is different" do
+ -> { @v.each2(Vector[1,2]){} }.should raise_error(Vector::ErrDimensionMismatch)
+ -> { @v.each2(Vector[1,2,3,4]){} }.should raise_error(Vector::ErrDimensionMismatch)
+ end
+
+ it "yields arguments in sequence" do
+ a = []
+ @v.each2(@v2){|first, second| a << [first, second]}
+ a.should == [[1, 4], [2, 5], [3, 6]]
+ end
- describe "Vector.each2" do
- before :all do
- @v = Vector[1, 2, 3]
- @v2 = Vector[4, 5, 6]
+ it "yield arguments in pairs" do
+ a = []
+ @v.each2(@v2){|*pair| a << pair}
+ a.should == [[1, 4], [2, 5], [3, 6]]
end
- it "requires one argument" do
- -> { @v.each2(@v2, @v2){} }.should raise_error(ArgumentError)
- -> { @v.each2(){} }.should raise_error(ArgumentError)
+ it "returns self when given a block" do
+ @v.each2(@v2){}.should equal(@v)
end
- describe "given one argument" do
- it "accepts an Array argument" do
- a = []
- @v.each2([7, 8, 9]){|x, y| a << x << y}
- a.should == [1, 7, 2, 8, 3, 9]
- end
-
- it "raises a DimensionMismatch error if the Vector size is different" do
- -> { @v.each2(Vector[1,2]){} }.should raise_error(Vector::ErrDimensionMismatch)
- -> { @v.each2(Vector[1,2,3,4]){} }.should raise_error(Vector::ErrDimensionMismatch)
- end
-
- it "yields arguments in sequence" do
- a = []
- @v.each2(@v2){|first, second| a << [first, second]}
- a.should == [[1, 4], [2, 5], [3, 6]]
- end
-
- it "yield arguments in pairs" do
- a = []
- @v.each2(@v2){|*pair| a << pair}
- a.should == [[1, 4], [2, 5], [3, 6]]
- end
-
- it "returns self when given a block" do
- @v.each2(@v2){}.should equal(@v)
- end
-
- it "returns an enumerator if no block given" do
- enum = @v.each2(@v2)
- enum.should be_an_instance_of(Enumerator)
- enum.to_a.should == [[1, 4], [2, 5], [3, 6]]
- end
+ it "returns an enumerator if no block given" do
+ enum = @v.each2(@v2)
+ enum.should be_an_instance_of(Enumerator)
+ enum.to_a.should == [[1, 4], [2, 5], [3, 6]]
end
end
end
diff --git a/spec/ruby/library/matrix/vector/eql_spec.rb b/spec/ruby/library/matrix/vector/eql_spec.rb
index fa086bd33a..eb2451b550 100644
--- a/spec/ruby/library/matrix/vector/eql_spec.rb
+++ b/spec/ruby/library/matrix/vector/eql_spec.rb
@@ -1,19 +1,16 @@
require_relative '../../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
-
- describe "Vector#eql?" do
- before do
- @vector = Vector[1, 2, 3, 4, 5]
- end
+describe "Vector#eql?" do
+ before do
+ @vector = Vector[1, 2, 3, 4, 5]
+ end
- it "returns true for self" do
- @vector.eql?(@vector).should be_true
- end
+ it "returns true for self" do
+ @vector.eql?(@vector).should be_true
+ end
- it "returns false when there are a pair corresponding elements which are not equal in the sense of Kernel#eql?" do
- @vector.eql?(Vector[1, 2, 3, 4, 5.0]).should be_false
- end
+ it "returns false when there are a pair corresponding elements which are not equal in the sense of Kernel#eql?" do
+ @vector.eql?(Vector[1, 2, 3, 4, 5.0]).should be_false
end
end
diff --git a/spec/ruby/library/matrix/vector/inner_product_spec.rb b/spec/ruby/library/matrix/vector/inner_product_spec.rb
index 95dc4806b5..1cf8771e04 100644
--- a/spec/ruby/library/matrix/vector/inner_product_spec.rb
+++ b/spec/ruby/library/matrix/vector/inner_product_spec.rb
@@ -1,25 +1,22 @@
require_relative '../../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
-
- describe "Vector#inner_product" do
- it "returns the inner product of a vector" do
- Vector[1, 2, 3].inner_product(Vector[0, -4, 5]).should == 7
- end
+describe "Vector#inner_product" do
+ it "returns the inner product of a vector" do
+ Vector[1, 2, 3].inner_product(Vector[0, -4, 5]).should == 7
+ end
- it "returns 0 for empty vectors" do
- Vector[].inner_product(Vector[]).should == 0
- end
+ it "returns 0 for empty vectors" do
+ Vector[].inner_product(Vector[]).should == 0
+ end
- it "raises an error for mismatched vectors" do
- -> {
- Vector[1, 2, 3].inner_product(Vector[0, -4])
- }.should raise_error(Vector::ErrDimensionMismatch)
- end
+ it "raises an error for mismatched vectors" do
+ -> {
+ Vector[1, 2, 3].inner_product(Vector[0, -4])
+ }.should raise_error(Vector::ErrDimensionMismatch)
+ end
- it "uses the conjugate of its argument" do
- Vector[Complex(1,2)].inner_product(Vector[Complex(3,4)]).should == Complex(11, 2)
- end
+ it "uses the conjugate of its argument" do
+ Vector[Complex(1,2)].inner_product(Vector[Complex(3,4)]).should == Complex(11, 2)
end
end
diff --git a/spec/ruby/library/matrix/vector/normalize_spec.rb b/spec/ruby/library/matrix/vector/normalize_spec.rb
index 7345e11fa4..527c9260de 100644
--- a/spec/ruby/library/matrix/vector/normalize_spec.rb
+++ b/spec/ruby/library/matrix/vector/normalize_spec.rb
@@ -1,21 +1,18 @@
require_relative '../../../spec_helper'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require 'matrix'
-
- describe "Vector#normalize" do
- it "returns a normalized copy of the vector" do
- x = 0.2672612419124244
- Vector[1, 2, 3].normalize.should == Vector[x, x * 2, x * 3]
- end
+describe "Vector#normalize" do
+ it "returns a normalized copy of the vector" do
+ x = 0.2672612419124244
+ Vector[1, 2, 3].normalize.should == Vector[x, x * 2, x * 3]
+ end
- it "raises an error for zero vectors" do
- -> {
- Vector[].normalize
- }.should raise_error(Vector::ZeroVectorError)
- -> {
- Vector[0, 0, 0].normalize
- }.should raise_error(Vector::ZeroVectorError)
- end
+ it "raises an error for zero vectors" do
+ -> {
+ Vector[].normalize
+ }.should raise_error(Vector::ZeroVectorError)
+ -> {
+ Vector[0, 0, 0].normalize
+ }.should raise_error(Vector::ZeroVectorError)
end
end
diff --git a/spec/ruby/library/matrix/zero_spec.rb b/spec/ruby/library/matrix/zero_spec.rb
index 80162a03d0..68e8567c26 100644
--- a/spec/ruby/library/matrix/zero_spec.rb
+++ b/spec/ruby/library/matrix/zero_spec.rb
@@ -1,55 +1,52 @@
require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+require 'matrix'
-ruby_version_is ""..."3.1" do
- require_relative 'fixtures/classes'
- require 'matrix'
-
- describe "Matrix.zero" do
- it "returns an object of type Matrix" do
- Matrix.zero(3).should be_kind_of(Matrix)
- end
+describe "Matrix.zero" do
+ it "returns an object of type Matrix" do
+ Matrix.zero(3).should be_kind_of(Matrix)
+ end
- it "creates a n x n matrix" do
- m3 = Matrix.zero(3)
- m3.row_size.should == 3
- m3.column_size.should == 3
+ it "creates a n x n matrix" do
+ m3 = Matrix.zero(3)
+ m3.row_size.should == 3
+ m3.column_size.should == 3
- m8 = Matrix.zero(8)
- m8.row_size.should == 8
- m8.column_size.should == 8
- end
+ m8 = Matrix.zero(8)
+ m8.row_size.should == 8
+ m8.column_size.should == 8
+ end
- it "initializes all cells to 0" do
- size = 10
- m = Matrix.zero(size)
+ it "initializes all cells to 0" do
+ size = 10
+ m = Matrix.zero(size)
- (0...size).each do |i|
- (0...size).each do |j|
- m[i, j].should == 0
- end
+ (0...size).each do |i|
+ (0...size).each do |j|
+ m[i, j].should == 0
end
end
+ end
- describe "for a subclass of Matrix" do
- it "returns an instance of that subclass" do
- MatrixSub.zero(3).should be_an_instance_of(MatrixSub)
- end
+ describe "for a subclass of Matrix" do
+ it "returns an instance of that subclass" do
+ MatrixSub.zero(3).should be_an_instance_of(MatrixSub)
end
end
+end
- describe "Matrix.zero?" do
- it "returns true for empty matrices" do
- Matrix.empty.should.zero?
- Matrix.empty(3,0).should.zero?
- Matrix.empty(0,3).should.zero?
- end
+describe "Matrix.zero?" do
+ it "returns true for empty matrices" do
+ Matrix.empty.should.zero?
+ Matrix.empty(3,0).should.zero?
+ Matrix.empty(0,3).should.zero?
+ end
- it "returns true for matrices with zero entries" do
- Matrix.zero(2,3).should.zero?
- end
+ it "returns true for matrices with zero entries" do
+ Matrix.zero(2,3).should.zero?
+ end
- it "returns false for matrices with non zero entries" do
- Matrix[[1]].should_not.zero?
- end
+ it "returns false for matrices with non zero entries" do
+ Matrix[[1]].should_not.zero?
end
end
diff --git a/spec/ruby/library/monitor/exit_spec.rb b/spec/ruby/library/monitor/exit_spec.rb
new file mode 100644
index 0000000000..952ad9525d
--- /dev/null
+++ b/spec/ruby/library/monitor/exit_spec.rb
@@ -0,0 +1,10 @@
+require_relative '../../spec_helper'
+require 'monitor'
+
+describe "Monitor#exit" do
+ it "raises ThreadError when monitor is not entered" do
+ m = Monitor.new
+
+ -> { m.exit }.should raise_error(ThreadError)
+ end
+end
diff --git a/spec/ruby/library/net-ftp/FTPError_spec.rb b/spec/ruby/library/net-ftp/FTPError_spec.rb
new file mode 100644
index 0000000000..0c31b65dcc
--- /dev/null
+++ b/spec/ruby/library/net-ftp/FTPError_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../spec_helper'
+require 'net/ftp'
+
+describe "Net::FTPError" do
+ it "is an Exception" do
+ Net::FTPError.should < Exception
+ end
+end
diff --git a/spec/ruby/library/net-ftp/FTPPermError_spec.rb b/spec/ruby/library/net-ftp/FTPPermError_spec.rb
new file mode 100644
index 0000000000..b43e12c503
--- /dev/null
+++ b/spec/ruby/library/net-ftp/FTPPermError_spec.rb
@@ -0,0 +1,12 @@
+require_relative '../../spec_helper'
+require 'net/ftp'
+
+describe "Net::FTPPermError" do
+ it "is an Exception" do
+ Net::FTPPermError.should < Exception
+ end
+
+ it "is a subclass of Net::FTPError" do
+ Net::FTPPermError.should < Net::FTPError
+ end
+end
diff --git a/spec/ruby/library/net-ftp/FTPProtoError_spec.rb b/spec/ruby/library/net-ftp/FTPProtoError_spec.rb
new file mode 100644
index 0000000000..e7abbc0dd8
--- /dev/null
+++ b/spec/ruby/library/net-ftp/FTPProtoError_spec.rb
@@ -0,0 +1,12 @@
+require_relative '../../spec_helper'
+require 'net/ftp'
+
+describe "Net::FTPProtoError" do
+ it "is an Exception" do
+ Net::FTPProtoError.should < Exception
+ end
+
+ it "is a subclass of Net::FTPError" do
+ Net::FTPPermError.should < Net::FTPError
+ end
+end
diff --git a/spec/ruby/library/net-ftp/FTPReplyError_spec.rb b/spec/ruby/library/net-ftp/FTPReplyError_spec.rb
new file mode 100644
index 0000000000..fcc7501fc1
--- /dev/null
+++ b/spec/ruby/library/net-ftp/FTPReplyError_spec.rb
@@ -0,0 +1,12 @@
+require_relative '../../spec_helper'
+require 'net/ftp'
+
+describe "Net::FTPReplyError" do
+ it "is an Exception" do
+ Net::FTPReplyError.should < Exception
+ end
+
+ it "is a subclass of Net::FTPError" do
+ Net::FTPPermError.should < Net::FTPError
+ end
+end
diff --git a/spec/ruby/library/net-ftp/FTPTempError_spec.rb b/spec/ruby/library/net-ftp/FTPTempError_spec.rb
new file mode 100644
index 0000000000..f4b045dfb5
--- /dev/null
+++ b/spec/ruby/library/net-ftp/FTPTempError_spec.rb
@@ -0,0 +1,12 @@
+require_relative '../../spec_helper'
+require 'net/ftp'
+
+describe "Net::FTPTempError" do
+ it "is an Exception" do
+ Net::FTPTempError.should < Exception
+ end
+
+ it "is a subclass of Net::FTPError" do
+ Net::FTPPermError.should < Net::FTPError
+ end
+end
diff --git a/spec/ruby/library/net-ftp/abort_spec.rb b/spec/ruby/library/net-ftp/abort_spec.rb
new file mode 100644
index 0000000000..335d056512
--- /dev/null
+++ b/spec/ruby/library/net-ftp/abort_spec.rb
@@ -0,0 +1,62 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+require_relative 'fixtures/server'
+
+describe "Net::FTP#abort" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "sends the ABOR command to the server" do
+ -> { @ftp.abort }.should_not raise_error
+ end
+
+ it "ignores the response" do
+ @ftp.abort
+ @ftp.last_response.should == "220 Dummy FTP Server ready!\n"
+ end
+
+ it "returns the full response" do
+ @ftp.abort.should == "226 Closing data connection. (ABOR)\n"
+ end
+
+ it "does not raise any error when the response code is 225" do
+ @server.should_receive(:abor).and_respond("225 Data connection open; no transfer in progress.")
+ -> { @ftp.abort }.should_not raise_error
+ end
+
+ it "does not raise any error when the response code is 226" do
+ @server.should_receive(:abor).and_respond("226 Closing data connection.")
+ -> { @ftp.abort }.should_not raise_error
+ end
+
+ it "raises a Net::FTPProtoError when the response code is 500" do
+ @server.should_receive(:abor).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.abort }.should raise_error(Net::FTPProtoError)
+ end
+
+ it "raises a Net::FTPProtoError when the response code is 501" do
+ @server.should_receive(:abor).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.abort }.should raise_error(Net::FTPProtoError)
+ end
+
+ it "raises a Net::FTPProtoError when the response code is 502" do
+ @server.should_receive(:abor).and_respond("502 Command not implemented.")
+ -> { @ftp.abort }.should raise_error(Net::FTPProtoError)
+ end
+
+ it "raises a Net::FTPProtoError when the response code is 421" do
+ @server.should_receive(:abor).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.abort }.should raise_error(Net::FTPProtoError)
+ end
+end
diff --git a/spec/ruby/library/net-ftp/acct_spec.rb b/spec/ruby/library/net-ftp/acct_spec.rb
new file mode 100644
index 0000000000..ab093448a2
--- /dev/null
+++ b/spec/ruby/library/net-ftp/acct_spec.rb
@@ -0,0 +1,58 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+require_relative 'fixtures/server'
+
+describe "Net::FTP#acct" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "writes the ACCT command to the server" do
+ @ftp.acct("my_account")
+ @ftp.last_response.should == "230 User 'my_account' logged in, proceed. (ACCT)\n"
+ end
+
+ it "returns nil" do
+ @ftp.acct("my_account").should == nil
+ end
+
+ it "does not raise any error when the response code is 230" do
+ @server.should_receive(:acct).and_respond("230 User logged in, proceed.")
+ -> { @ftp.acct("my_account") }.should_not raise_error
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:acct).and_respond("530 Not logged in.")
+ -> { @ftp.acct("my_account") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:acct).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.acct("my_account") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:acct).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.acct("my_account") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 503" do
+ @server.should_receive(:acct).and_respond("503 Bad sequence of commands.")
+ -> { @ftp.acct("my_account") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:acct).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.acct("my_account") }.should raise_error(Net::FTPTempError)
+ end
+end
diff --git a/spec/ruby/library/net-ftp/binary_spec.rb b/spec/ruby/library/net-ftp/binary_spec.rb
new file mode 100644
index 0000000000..1e0585b795
--- /dev/null
+++ b/spec/ruby/library/net-ftp/binary_spec.rb
@@ -0,0 +1,24 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+
+describe "Net::FTP#binary" do
+ it "returns true when self is in binary mode" do
+ ftp = Net::FTP.new
+ ftp.binary.should be_true
+
+ ftp.binary = false
+ ftp.binary.should be_false
+ end
+end
+
+describe "Net::FTP#binary=" do
+ it "sets self to binary mode when passed true" do
+ ftp = Net::FTP.new
+
+ ftp.binary = true
+ ftp.binary.should be_true
+
+ ftp.binary = false
+ ftp.binary.should be_false
+ end
+end
diff --git a/spec/ruby/library/net-ftp/chdir_spec.rb b/spec/ruby/library/net-ftp/chdir_spec.rb
new file mode 100644
index 0000000000..cc129b5e42
--- /dev/null
+++ b/spec/ruby/library/net-ftp/chdir_spec.rb
@@ -0,0 +1,99 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+require_relative 'fixtures/server'
+
+describe "Net::FTP#chdir" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ describe "when switching to the parent directory" do
+ it "sends the 'CDUP' command to the server" do
+ @ftp.chdir("..")
+ @ftp.last_response.should == "200 Command okay. (CDUP)\n"
+ end
+
+ it "returns nil" do
+ @ftp.chdir("..").should be_nil
+ end
+
+ it "does not raise a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:cdup).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.chdir("..") }.should_not raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:cdup).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.chdir("..") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:cdup).and_respond("502 Command not implemented.")
+ -> { @ftp.chdir("..") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:cdup).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.chdir("..") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:cdup).and_respond("530 Not logged in.")
+ -> { @ftp.chdir("..") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 550" do
+ @server.should_receive(:cdup).and_respond("550 Requested action not taken.")
+ -> { @ftp.chdir("..") }.should raise_error(Net::FTPPermError)
+ end
+ end
+
+ it "writes the 'CWD' command with the passed directory to the socket" do
+ @ftp.chdir("test")
+ @ftp.last_response.should == "200 Command okay. (CWD test)\n"
+ end
+
+ it "returns nil" do
+ @ftp.chdir("test").should be_nil
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:cwd).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.chdir("test") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:cwd).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.chdir("test") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:cwd).and_respond("502 Command not implemented.")
+ -> { @ftp.chdir("test") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:cwd).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.chdir("test") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:cwd).and_respond("530 Not logged in.")
+ -> { @ftp.chdir("test") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 550" do
+ @server.should_receive(:cwd).and_respond("550 Requested action not taken.")
+ -> { @ftp.chdir("test") }.should raise_error(Net::FTPPermError)
+ end
+end
diff --git a/spec/ruby/library/net-ftp/close_spec.rb b/spec/ruby/library/net-ftp/close_spec.rb
new file mode 100644
index 0000000000..183f14a84b
--- /dev/null
+++ b/spec/ruby/library/net-ftp/close_spec.rb
@@ -0,0 +1,30 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+
+describe "Net::FTP#close" do
+ before :each do
+ @socket = mock("Socket")
+ @socket.stub!(:closed?).and_return(false)
+ @socket.stub!(:read_timeout).and_return(60)
+ @socket.stub!(:read_timeout=).and_return(3)
+
+ @ftp = Net::FTP.new
+ @ftp.instance_variable_set(:@sock, @socket)
+ end
+
+ it "closes the socket" do
+ @socket.should_receive(:close)
+ @ftp.close.should be_nil
+ end
+
+ it "does not try to close the socket if it has already been closed" do
+ @socket.should_receive(:closed?).and_return(true)
+ @socket.should_not_receive(:close)
+ @ftp.close.should be_nil
+ end
+
+ it "does not try to close the socket if it is nil" do
+ @ftp.instance_variable_set(:@sock, nil)
+ @ftp.close.should be_nil
+ end
+end
diff --git a/spec/ruby/library/net-ftp/closed_spec.rb b/spec/ruby/library/net-ftp/closed_spec.rb
new file mode 100644
index 0000000000..84001cdc0f
--- /dev/null
+++ b/spec/ruby/library/net-ftp/closed_spec.rb
@@ -0,0 +1,21 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+
+describe "Net::FTP#closed?" do
+ before :each do
+ @socket = mock("Socket")
+
+ @ftp = Net::FTP.new
+ @ftp.instance_variable_set(:@sock, @socket)
+ end
+
+ it "returns true when the socket is closed" do
+ @socket.should_receive(:closed?).and_return(true)
+ @ftp.closed?.should be_true
+ end
+
+ it "returns true when the socket is nil" do
+ @ftp.instance_variable_set(:@sock, nil)
+ @ftp.closed?.should be_true
+ end
+end
diff --git a/spec/ruby/library/net-ftp/connect_spec.rb b/spec/ruby/library/net-ftp/connect_spec.rb
new file mode 100644
index 0000000000..4330d430b4
--- /dev/null
+++ b/spec/ruby/library/net-ftp/connect_spec.rb
@@ -0,0 +1,51 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+require_relative 'fixtures/server'
+
+# TODO: Add specs for using the SOCKSSocket
+describe "Net::FTP#connect" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ end
+
+ after :each do
+ @server.connect_message = nil
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "tries to connect to the FTP Server on the given host and port" do
+ -> { @ftp.connect(@server.hostname, @server.server_port) }.should_not raise_error
+ end
+
+ it "returns nil" do
+ @ftp.connect(@server.hostname, @server.server_port).should be_nil
+ end
+
+ ruby_version_is ""..."3.1" do
+ it "prints a small debug line when in debug mode" do
+ @ftp.debug_mode = true
+ -> { @ftp.connect(@server.hostname, @server.server_port) }.should output(/connect: #{@server.hostname}, #{@server.server_port}\nget: 220 Dummy FTP Server ready!/)
+ @ftp.debug_mode = false
+ end
+ end
+
+ it "does not raise any error when the response code is 220" do
+ @server.connect_message = "220 Dummy FTP Server ready!"
+ -> { @ftp.connect(@server.hostname, @server.server_port) }.should_not raise_error
+ end
+
+ it "raises a Net::FTPReplyError when the response code is 120" do
+ @server.connect_message = "120 Service ready in nnn minutes."
+ -> { @ftp.connect(@server.hostname, @server.server_port) }.should raise_error(Net::FTPReplyError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.connect_message = "421 Service not available, closing control connection."
+ -> { @ftp.connect(@server.hostname, @server.server_port) }.should raise_error(Net::FTPTempError)
+ end
+end
diff --git a/spec/ruby/library/net-ftp/debug_mode_spec.rb b/spec/ruby/library/net-ftp/debug_mode_spec.rb
new file mode 100644
index 0000000000..f2ef53c089
--- /dev/null
+++ b/spec/ruby/library/net-ftp/debug_mode_spec.rb
@@ -0,0 +1,23 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+
+describe "Net::FTP#debug_mode" do
+ it "returns true when self is in debug mode" do
+ ftp = Net::FTP.new
+ ftp.debug_mode.should be_false
+
+ ftp.debug_mode = true
+ ftp.debug_mode.should be_true
+ end
+end
+
+describe "Net::FTP#debug_mode=" do
+ it "sets self into debug mode when passed true" do
+ ftp = Net::FTP.new
+ ftp.debug_mode = true
+ ftp.debug_mode.should be_true
+
+ ftp.debug_mode = false
+ ftp.debug_mode.should be_false
+ end
+end
diff --git a/spec/ruby/library/net-ftp/default_passive_spec.rb b/spec/ruby/library/net-ftp/default_passive_spec.rb
new file mode 100644
index 0000000000..3f14f6187e
--- /dev/null
+++ b/spec/ruby/library/net-ftp/default_passive_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+
+describe "Net::FTP#default_passive" do
+ it "is true by default" do
+ ruby_exe(fixture(__FILE__, "default_passive.rb")).should == "true\ntrue\n"
+ end
+end
diff --git a/spec/ruby/library/net-ftp/delete_spec.rb b/spec/ruby/library/net-ftp/delete_spec.rb
new file mode 100644
index 0000000000..bfb7da1ffe
--- /dev/null
+++ b/spec/ruby/library/net-ftp/delete_spec.rb
@@ -0,0 +1,59 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+require_relative 'fixtures/server'
+
+describe "Net::FTP#delete" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "sends the DELE command with the passed filename to the server" do
+ @ftp.delete("test.file")
+ @ftp.last_response.should == "250 Requested file action okay, completed. (DELE test.file)\n"
+ end
+
+ it "raises a Net::FTPTempError when the response code is 450" do
+ @server.should_receive(:dele).and_respond("450 Requested file action not taken.")
+ -> { @ftp.delete("test.file") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 550" do
+ @server.should_receive(:dele).and_respond("550 Requested action not taken.")
+ -> { @ftp.delete("test.file") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:dele).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.delete("test.file") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:dele).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.delete("test.file") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:dele).and_respond("502 Command not implemented.")
+ -> { @ftp.delete("test.file") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:dele).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.delete("test.file") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:dele).and_respond("530 Not logged in.")
+ -> { @ftp.delete("test.file") }.should raise_error(Net::FTPPermError)
+ end
+end
diff --git a/spec/ruby/library/net-ftp/dir_spec.rb b/spec/ruby/library/net-ftp/dir_spec.rb
new file mode 100644
index 0000000000..894f03dd7b
--- /dev/null
+++ b/spec/ruby/library/net-ftp/dir_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+require_relative 'fixtures/server'
+require_relative 'shared/list'
+
+describe "Net::FTP#dir" do
+ it_behaves_like :net_ftp_list, :dir
+end
diff --git a/spec/ruby/library/net/ftp/fixtures/default_passive.rb b/spec/ruby/library/net-ftp/fixtures/default_passive.rb
index b6995d6f34..b6995d6f34 100644
--- a/spec/ruby/library/net/ftp/fixtures/default_passive.rb
+++ b/spec/ruby/library/net-ftp/fixtures/default_passive.rb
diff --git a/spec/ruby/library/net/ftp/fixtures/passive.rb b/spec/ruby/library/net-ftp/fixtures/passive.rb
index 6b5cde82df..6b5cde82df 100644
--- a/spec/ruby/library/net/ftp/fixtures/passive.rb
+++ b/spec/ruby/library/net-ftp/fixtures/passive.rb
diff --git a/spec/ruby/library/net/ftp/fixtures/putbinaryfile b/spec/ruby/library/net-ftp/fixtures/putbinaryfile
index f3130c6e43..f3130c6e43 100644
--- a/spec/ruby/library/net/ftp/fixtures/putbinaryfile
+++ b/spec/ruby/library/net-ftp/fixtures/putbinaryfile
diff --git a/spec/ruby/library/net/ftp/fixtures/puttextfile b/spec/ruby/library/net-ftp/fixtures/puttextfile
index b4f3b2b62d..b4f3b2b62d 100644
--- a/spec/ruby/library/net/ftp/fixtures/puttextfile
+++ b/spec/ruby/library/net-ftp/fixtures/puttextfile
diff --git a/spec/ruby/library/net/ftp/fixtures/server.rb b/spec/ruby/library/net-ftp/fixtures/server.rb
index ecbed591d5..ecbed591d5 100644
--- a/spec/ruby/library/net/ftp/fixtures/server.rb
+++ b/spec/ruby/library/net-ftp/fixtures/server.rb
diff --git a/spec/ruby/library/net-ftp/get_spec.rb b/spec/ruby/library/net-ftp/get_spec.rb
new file mode 100644
index 0000000000..1bc1bd744b
--- /dev/null
+++ b/spec/ruby/library/net-ftp/get_spec.rb
@@ -0,0 +1,21 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+require_relative 'fixtures/server'
+require_relative 'shared/gettextfile'
+require_relative 'shared/getbinaryfile'
+
+describe "Net::FTP#get (binary mode)" do
+ before :each do
+ @binary_mode = true
+ end
+
+ it_behaves_like :net_ftp_getbinaryfile, :get
+end
+
+describe "Net::FTP#get (text mode)" do
+ before :each do
+ @binary_mode = false
+ end
+
+ it_behaves_like :net_ftp_gettextfile, :get
+end
diff --git a/spec/ruby/library/net-ftp/getbinaryfile_spec.rb b/spec/ruby/library/net-ftp/getbinaryfile_spec.rb
new file mode 100644
index 0000000000..e9898fccc7
--- /dev/null
+++ b/spec/ruby/library/net-ftp/getbinaryfile_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+require_relative 'fixtures/server'
+require_relative 'shared/getbinaryfile'
+
+describe "Net::FTP#getbinaryfile" do
+ it_behaves_like :net_ftp_getbinaryfile, :getbinaryfile
+end
diff --git a/spec/ruby/library/net-ftp/getdir_spec.rb b/spec/ruby/library/net-ftp/getdir_spec.rb
new file mode 100644
index 0000000000..756d6a23af
--- /dev/null
+++ b/spec/ruby/library/net-ftp/getdir_spec.rb
@@ -0,0 +1,7 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+require_relative 'shared/pwd'
+
+describe "Net::FTP#getdir" do
+ it_behaves_like :net_ftp_pwd, :getdir
+end
diff --git a/spec/ruby/library/net-ftp/gettextfile_spec.rb b/spec/ruby/library/net-ftp/gettextfile_spec.rb
new file mode 100644
index 0000000000..cdd1b4c797
--- /dev/null
+++ b/spec/ruby/library/net-ftp/gettextfile_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+require_relative 'fixtures/server'
+require_relative 'shared/gettextfile'
+
+describe "Net::FTP#gettextfile" do
+ it_behaves_like :net_ftp_gettextfile, :gettextfile
+end
diff --git a/spec/ruby/library/net-ftp/help_spec.rb b/spec/ruby/library/net-ftp/help_spec.rb
new file mode 100644
index 0000000000..c562be50b2
--- /dev/null
+++ b/spec/ruby/library/net-ftp/help_spec.rb
@@ -0,0 +1,66 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+require_relative 'fixtures/server'
+
+describe "Net::FTP#help" do
+ def with_connection
+ yield
+ end
+
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "writes the HELP command to the server" do
+ @ftp.help
+ @ftp.last_response.should == "211 System status, or system help reply. (HELP)\n"
+ end
+
+ it "returns the server's response" do
+ @ftp.help.should == "211 System status, or system help reply. (HELP)\n"
+ end
+
+ it "writes the HELP command with an optional parameter to the socket" do
+ @ftp.help("some parameter").should == "211 System status, or system help reply. (HELP some parameter)\n"
+ end
+
+ it "does not raise any error when the response code is 211" do
+ @server.should_receive(:help).and_respond("211 System status, or system help reply.")
+ -> { @ftp.help }.should_not raise_error
+ end
+
+ it "does not raise any error when the response code is 214" do
+ @server.should_receive(:help).and_respond("214 Help message.")
+ -> { @ftp.help }.should_not raise_error
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:help).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.help }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:help).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.help }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:help).and_respond("502 Command not implemented.")
+ -> { @ftp.help }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:help).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.help }.should raise_error(Net::FTPTempError)
+ end
+end
diff --git a/spec/ruby/library/net-ftp/initialize_spec.rb b/spec/ruby/library/net-ftp/initialize_spec.rb
new file mode 100644
index 0000000000..4d775e8dc1
--- /dev/null
+++ b/spec/ruby/library/net-ftp/initialize_spec.rb
@@ -0,0 +1,405 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+
+describe "Net::FTP#initialize" do
+ before :each do
+ @ftp = Net::FTP.allocate
+ @ftp.stub!(:connect)
+ @port_args = []
+ @port_args << 21
+ end
+
+ it "is private" do
+ Net::FTP.should have_private_instance_method(:initialize)
+ end
+
+ it "sets self into binary mode" do
+ @ftp.binary.should be_nil
+ @ftp.send(:initialize)
+ @ftp.binary.should be_true
+ end
+
+ it "sets self into active mode" do
+ @ftp.passive.should be_nil
+ @ftp.send(:initialize)
+ @ftp.passive.should be_false
+ end
+
+ it "sets self into non-debug mode" do
+ @ftp.debug_mode.should be_nil
+ @ftp.send(:initialize)
+ @ftp.debug_mode.should be_false
+ end
+
+ it "sets self to not resume file uploads/downloads" do
+ @ftp.resume.should be_nil
+ @ftp.send(:initialize)
+ @ftp.resume.should be_false
+ end
+
+ describe "when passed no arguments" do
+ it "does not try to connect" do
+ @ftp.should_not_receive(:connect)
+ @ftp.send(:initialize)
+ end
+ end
+
+ describe "when passed host" do
+ it "tries to connect to the passed host" do
+ @ftp.should_receive(:connect).with("localhost", *@port_args)
+ @ftp.send(:initialize, "localhost")
+ end
+ end
+
+ describe "when passed host, user" do
+ it "tries to connect to the passed host" do
+ @ftp.should_receive(:connect).with("localhost", *@port_args)
+ @ftp.send(:initialize, "localhost")
+ end
+
+ it "tries to login with the passed username" do
+ @ftp.should_receive(:login).with("rubyspec", nil, nil)
+ @ftp.send(:initialize, "localhost", "rubyspec")
+ end
+ end
+
+ describe "when passed host, user, password" do
+ it "tries to connect to the passed host" do
+ @ftp.should_receive(:connect).with("localhost", *@port_args)
+ @ftp.send(:initialize, "localhost")
+ end
+
+ it "tries to login with the passed username and password" do
+ @ftp.should_receive(:login).with("rubyspec", "rocks", nil)
+ @ftp.send(:initialize, "localhost", "rubyspec", "rocks")
+ end
+ end
+
+ describe "when passed host, user" do
+ it "tries to connect to the passed host" do
+ @ftp.should_receive(:connect).with("localhost", *@port_args)
+ @ftp.send(:initialize, "localhost")
+ end
+
+ it "tries to login with the passed username, password and account" do
+ @ftp.should_receive(:login).with("rubyspec", "rocks", "account")
+ @ftp.send(:initialize, "localhost", "rubyspec", "rocks", "account")
+ end
+ end
+
+ before :each do
+ @ftp.stub!(:login)
+ end
+
+ describe 'when the host' do
+ describe 'is set' do
+ describe 'and port option' do
+ describe 'is set' do
+ it 'tries to connect to the host on the specified port' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ port: 8080 })
+ @ftp.should_receive(:connect).with('localhost', 8080)
+
+ @ftp.send(:initialize, 'localhost', options)
+ end
+ end
+
+ describe 'is not set' do
+ it 'tries to connect to the host without a port' do
+ @ftp.should_receive(:connect).with("localhost", *@port_args)
+
+ @ftp.send(:initialize, 'localhost')
+ end
+ end
+ end
+
+ describe 'when the username option' do
+ describe 'is set' do
+ describe 'and the password option' do
+ describe 'is set' do
+ describe 'and the account option' do
+ describe 'is set' do
+ it 'tries to log in with the supplied parameters' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ username: 'a', password: 'topsecret', account: 'b' })
+ @ftp.should_receive(:login).with('a', 'topsecret', 'b')
+
+ @ftp.send(:initialize, 'localhost', options)
+ end
+ end
+
+ describe 'is unset' do
+ it 'tries to log in with the supplied parameters' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ username: 'a', password: 'topsecret' })
+ @ftp.should_receive(:login).with('a', 'topsecret', nil)
+
+ @ftp.send(:initialize, 'localhost', options)
+ end
+ end
+ end
+ end
+
+ describe 'is unset' do
+ describe 'and the account option' do
+ describe 'is set' do
+ it 'tries to log in with the supplied parameters' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ username: 'a', account: 'b' })
+ @ftp.should_receive(:login).with('a', nil, 'b')
+
+ @ftp.send(:initialize, 'localhost', options)
+ end
+ end
+
+ describe 'is unset' do
+ it 'tries to log in with the supplied parameters' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ username: 'a'})
+ @ftp.should_receive(:login).with('a', nil, nil)
+
+ @ftp.send(:initialize, 'localhost', options)
+ end
+ end
+ end
+ end
+ end
+ end
+
+ describe 'is not set' do
+ it 'does not try to log in' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({})
+ @ftp.should_not_receive(:login)
+
+ @ftp.send(:initialize, 'localhost', options)
+ end
+ end
+ end
+ end
+
+ describe 'is unset' do
+ it 'does not try to connect' do
+ @ftp.should_not_receive(:connect)
+
+ @ftp.send(:initialize)
+ end
+
+ it 'does not try to log in' do
+ @ftp.should_not_receive(:login)
+
+ @ftp.send(:initialize)
+ end
+ end
+ end
+
+ describe 'when the passive option' do
+ describe 'is set' do
+ describe 'to true' do
+ it 'sets passive to true' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ passive: true })
+
+ @ftp.send(:initialize, nil, options)
+ @ftp.passive.should == true
+ end
+ end
+
+ describe 'to false' do
+ it 'sets passive to false' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ passive: false })
+
+ @ftp.send(:initialize, nil, options)
+ @ftp.passive.should == false
+ end
+ end
+ end
+
+ describe 'is unset' do
+ it 'sets passive to false' do
+ @ftp.send(:initialize)
+ @ftp.passive.should == false
+ end
+ end
+ end
+
+ describe 'when the debug_mode option' do
+ describe 'is set' do
+ describe 'to true' do
+ it 'sets debug_mode to true' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ debug_mode: true })
+
+ @ftp.send(:initialize, nil, options)
+ @ftp.debug_mode.should == true
+ end
+ end
+
+ describe 'to false' do
+ it 'sets debug_mode to false' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ debug_mode: false })
+
+ @ftp.send(:initialize, nil, options)
+ @ftp.debug_mode.should == false
+ end
+ end
+ end
+
+ describe 'is unset' do
+ it 'sets debug_mode to false' do
+ @ftp.send(:initialize)
+ @ftp.debug_mode.should == false
+ end
+ end
+ end
+
+ describe 'when the open_timeout option' do
+ describe 'is set' do
+ it 'sets open_timeout to the specified value' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ open_timeout: 42 })
+
+ @ftp.send(:initialize, nil, options)
+ @ftp.open_timeout.should == 42
+ end
+ end
+
+ describe 'is not set' do
+ it 'sets open_timeout to nil' do
+ @ftp.send(:initialize)
+ @ftp.open_timeout.should == nil
+ end
+ end
+ end
+
+ describe 'when the read_timeout option' do
+ describe 'is set' do
+ it 'sets read_timeout to the specified value' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ read_timeout: 100 })
+
+ @ftp.send(:initialize, nil, options)
+ @ftp.read_timeout.should == 100
+ end
+ end
+
+ describe 'is not set' do
+ it 'sets read_timeout to the default value' do
+ @ftp.send(:initialize)
+ @ftp.read_timeout.should == 60
+ end
+ end
+ end
+
+ describe 'when the ssl_handshake_timeout option' do
+ describe 'is set' do
+ it 'sets ssl_handshake_timeout to the specified value' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ ssl_handshake_timeout: 23 })
+
+ @ftp.send(:initialize, nil, options)
+ @ftp.ssl_handshake_timeout.should == 23
+ end
+ end
+
+ describe 'is not set' do
+ it 'sets ssl_handshake_timeout to nil' do
+ @ftp.send(:initialize)
+ @ftp.ssl_handshake_timeout.should == nil
+ end
+ end
+ end
+
+ describe 'when the ssl option' do
+ describe 'is set' do
+ describe "and the ssl option's value is true" do
+ it 'initializes ssl_context to a blank SSLContext object' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ ssl: true })
+
+ ssl_context = OpenSSL::SSL::SSLContext.allocate
+ ssl_context.stub!(:set_params)
+
+ OpenSSL::SSL::SSLContext.should_receive(:new).and_return(ssl_context)
+ ssl_context.should_receive(:set_params).with({})
+
+ @ftp.send(:initialize, nil, options)
+ @ftp.instance_variable_get(:@ssl_context).should == ssl_context
+ end
+ end
+
+ describe "and the ssl option's value is a hash" do
+ it 'initializes ssl_context to a configured SSLContext object' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ ssl: {key: 'value'} })
+
+ ssl_context = OpenSSL::SSL::SSLContext.allocate
+ ssl_context.stub!(:set_params)
+
+ OpenSSL::SSL::SSLContext.should_receive(:new).and_return(ssl_context)
+ ssl_context.should_receive(:set_params).with({key: 'value'})
+
+ @ftp.send(:initialize, nil, options)
+ @ftp.instance_variable_get(:@ssl_context).should == ssl_context
+ end
+ end
+
+ describe 'and private_data_connection' do
+ describe 'is set' do
+ it 'sets private_data_connection to that value' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ ssl: true, private_data_connection: 'true' })
+
+ @ftp.send(:initialize, nil, options)
+ @ftp.instance_variable_get(:@private_data_connection).should == 'true'
+ end
+ end
+
+ describe 'is not set' do
+ it 'sets private_data_connection to nil' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ ssl: true })
+
+ @ftp.send(:initialize, nil, options)
+ @ftp.instance_variable_get(:@private_data_connection).should == true
+ end
+ end
+ end
+ end
+
+ describe 'is not set' do
+ it 'sets ssl_context to nil' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({})
+
+ @ftp.send(:initialize, nil, options)
+ @ftp.instance_variable_get(:@ssl_context).should == nil
+ end
+
+ describe 'private_data_connection' do
+ describe 'is set' do
+ it 'raises an ArgumentError' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({ private_data_connection: true })
+
+ -> {
+ @ftp.send(:initialize, nil, options)
+ }.should raise_error(ArgumentError, /private_data_connection can be set to true only when ssl is enabled/)
+ end
+ end
+
+ describe 'is not set' do
+ it 'sets private_data_connection to false' do
+ options = mock('ftp initialize options')
+ options.should_receive(:to_hash).and_return({})
+
+ @ftp.send(:initialize, nil, options)
+ @ftp.instance_variable_get(:@private_data_connection).should == false
+ end
+ end
+ end
+ end
+ end
+end
diff --git a/spec/ruby/library/net-ftp/last_response_code_spec.rb b/spec/ruby/library/net-ftp/last_response_code_spec.rb
new file mode 100644
index 0000000000..c17c28f0f8
--- /dev/null
+++ b/spec/ruby/library/net-ftp/last_response_code_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+require_relative 'shared/last_response_code'
+require_relative 'fixtures/server'
+
+describe "Net::FTP#last_response_code" do
+ it_behaves_like :net_ftp_last_response_code, :last_response_code
+end
diff --git a/spec/ruby/library/net-ftp/last_response_spec.rb b/spec/ruby/library/net-ftp/last_response_spec.rb
new file mode 100644
index 0000000000..c9d9d70f35
--- /dev/null
+++ b/spec/ruby/library/net-ftp/last_response_spec.rb
@@ -0,0 +1,25 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+require_relative 'fixtures/server'
+
+describe "Net::FTP#last_response" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "returns the last response" do
+ @ftp.last_response.should == "220 Dummy FTP Server ready!\n"
+ @ftp.help
+ @ftp.last_response.should == "211 System status, or system help reply. (HELP)\n"
+ end
+end
diff --git a/spec/ruby/library/net-ftp/lastresp_spec.rb b/spec/ruby/library/net-ftp/lastresp_spec.rb
new file mode 100644
index 0000000000..e0c1b862a0
--- /dev/null
+++ b/spec/ruby/library/net-ftp/lastresp_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+require_relative 'shared/last_response_code'
+require_relative 'fixtures/server'
+
+describe "Net::FTP#lastresp" do
+ it_behaves_like :net_ftp_last_response_code, :lastresp
+end
diff --git a/spec/ruby/library/net-ftp/list_spec.rb b/spec/ruby/library/net-ftp/list_spec.rb
new file mode 100644
index 0000000000..6cb1bbc4b8
--- /dev/null
+++ b/spec/ruby/library/net-ftp/list_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+require_relative 'fixtures/server'
+require_relative 'shared/list'
+
+describe "Net::FTP#list" do
+ it_behaves_like :net_ftp_list, :list
+end
diff --git a/spec/ruby/library/net-ftp/login_spec.rb b/spec/ruby/library/net-ftp/login_spec.rb
new file mode 100644
index 0000000000..0de2f5cc63
--- /dev/null
+++ b/spec/ruby/library/net-ftp/login_spec.rb
@@ -0,0 +1,195 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+require_relative 'fixtures/server'
+
+describe "Net::FTP#login" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ describe "when passed no arguments" do
+ it "sends the USER command with 'anonymous' as name to the server" do
+ @ftp.login
+ @server.login_user.should == "anonymous"
+ end
+
+ it "sends 'anonymous@' as a password when required" do
+ @server.should_receive(:user).and_respond("331 User name okay, need password.")
+ @ftp.login
+ @server.login_pass.should == "anonymous@"
+ end
+
+ it "raises a Net::FTPReplyError when the server requests an account" do
+ @server.should_receive(:user).and_respond("331 User name okay, need password.")
+ @server.should_receive(:pass).and_respond("332 Need account for login.")
+ -> { @ftp.login }.should raise_error(Net::FTPReplyError)
+ end
+ end
+
+ describe "when passed name" do
+ it "sends the USER command with the passed name to the server" do
+ @ftp.login("rubyspec")
+ @server.login_user.should == "rubyspec"
+ end
+
+ it "raises a Net::FTPReplyError when the server requests a password, but none was given" do
+ @server.should_receive(:user).and_respond("331 User name okay, need password.")
+ -> { @ftp.login("rubyspec") }.should raise_error(Net::FTPReplyError)
+ end
+
+ it "raises a Net::FTPReplyError when the server requests an account, but none was given" do
+ @server.should_receive(:user).and_respond("331 User name okay, need password.")
+ @server.should_receive(:pass).and_respond("332 Need account for login.")
+ -> { @ftp.login("rubyspec") }.should raise_error(Net::FTPReplyError)
+ end
+ end
+
+ describe "when passed name, password" do
+ it "sends the USER command with the passed name to the server" do
+ @ftp.login("rubyspec", "rocks")
+ @server.login_user.should == "rubyspec"
+ end
+
+ it "sends the passed password when required" do
+ @server.should_receive(:user).and_respond("331 User name okay, need password.")
+ @ftp.login("rubyspec", "rocks")
+ @server.login_pass.should == "rocks"
+ end
+
+ it "raises a Net::FTPReplyError when the server requests an account" do
+ @server.should_receive(:user).and_respond("331 User name okay, need password.")
+ @server.should_receive(:pass).and_respond("332 Need account for login.")
+ -> { @ftp.login("rubyspec", "rocks") }.should raise_error(Net::FTPReplyError)
+ end
+ end
+
+ describe "when passed name, password, account" do
+ it "sends the USER command with the passed name to the server" do
+ @ftp.login("rubyspec", "rocks", "account")
+ @server.login_user.should == "rubyspec"
+ end
+
+ it "sends the passed password when required" do
+ @server.should_receive(:user).and_respond("331 User name okay, need password.")
+ @ftp.login("rubyspec", "rocks", "account")
+ @server.login_pass.should == "rocks"
+ end
+
+ it "sends the passed account when required" do
+ @server.should_receive(:user).and_respond("331 User name okay, need password.")
+ @server.should_receive(:pass).and_respond("332 Need account for login.")
+ @ftp.login("rubyspec", "rocks", "account")
+ @server.login_acct.should == "account"
+ end
+ end
+
+ describe "when the USER command fails" do
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:user).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:user).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:user).and_respond("502 Command not implemented.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:user).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:user).and_respond("530 Not logged in.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
+ end
+ end
+
+ describe "when the PASS command fails" do
+ before :each do
+ @server.should_receive(:user).and_respond("331 User name okay, need password.")
+ end
+
+ it "does not raise an Error when the response code is 202" do
+ @server.should_receive(:pass).and_respond("202 Command not implemented, superfluous at this site.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should_not raise_error
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:pass).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:pass).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:pass).and_respond("502 Command not implemented.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:pass).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:pass).and_respond("530 Not logged in.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
+ end
+ end
+
+ describe "when the ACCT command fails" do
+ before :each do
+ @server.should_receive(:user).and_respond("331 User name okay, need password.")
+ @server.should_receive(:pass).and_respond("332 Need account for login.")
+ end
+
+ it "does not raise an Error when the response code is 202" do
+ @server.should_receive(:acct).and_respond("202 Command not implemented, superfluous at this site.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should_not raise_error
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:acct).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:acct).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:acct).and_respond("502 Command not implemented.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:acct).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:acct).and_respond("530 Not logged in.")
+ -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
+ end
+ end
+end
diff --git a/spec/ruby/library/net-ftp/ls_spec.rb b/spec/ruby/library/net-ftp/ls_spec.rb
new file mode 100644
index 0000000000..acd7e9e523
--- /dev/null
+++ b/spec/ruby/library/net-ftp/ls_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+require_relative 'fixtures/server'
+require_relative 'shared/list'
+
+describe "Net::FTP#ls" do
+ it_behaves_like :net_ftp_list, :ls
+end
diff --git a/spec/ruby/library/net-ftp/mdtm_spec.rb b/spec/ruby/library/net-ftp/mdtm_spec.rb
new file mode 100644
index 0000000000..a504507c84
--- /dev/null
+++ b/spec/ruby/library/net-ftp/mdtm_spec.rb
@@ -0,0 +1,38 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+require_relative 'fixtures/server'
+
+describe "Net::FTP#mdtm" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "sends the MDTM with the passed filename command to the server" do
+ @ftp.mdtm("test.file")
+ @ftp.last_response.should == "213 19980705132316\n"
+ end
+
+ it "returns the last modification time of the passed file" do
+ @ftp.mdtm("test.file").should == "19980705132316"
+ end
+
+ it "raises a Net::FTPPermError when the response code is 550" do
+ @server.should_receive(:mdtm).and_respond("550 Requested action not taken.")
+ -> { @ftp.mdtm("test.file") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:mdtm).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.mdtm("test.file") }.should raise_error(Net::FTPTempError)
+ end
+end
diff --git a/spec/ruby/library/net-ftp/mkdir_spec.rb b/spec/ruby/library/net-ftp/mkdir_spec.rb
new file mode 100644
index 0000000000..8cc6ae785e
--- /dev/null
+++ b/spec/ruby/library/net-ftp/mkdir_spec.rb
@@ -0,0 +1,61 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+require_relative 'fixtures/server'
+
+describe "Net::FTP#mkdir" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "sends the MKD command with the passed pathname to the server" do
+ @ftp.mkdir("test.folder")
+ @ftp.last_response.should == %{257 "test.folder" created.\n}
+ end
+
+ it "returns the path to the newly created directory" do
+ @ftp.mkdir("test.folder").should == "test.folder"
+ @ftp.mkdir("/absolute/path/to/test.folder").should == "/absolute/path/to/test.folder"
+ @ftp.mkdir("relative/path/to/test.folder").should == "relative/path/to/test.folder"
+ @ftp.mkdir('/usr/dm/foo"bar').should == '/usr/dm/foo"bar'
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:mkd).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.mkdir("test.folder") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:mkd).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.mkdir("test.folder") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:mkd).and_respond("502 Command not implemented.")
+ -> { @ftp.mkdir("test.folder") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:mkd).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.mkdir("test.folder") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:mkd).and_respond("530 Not logged in.")
+ -> { @ftp.mkdir("test.folder") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 550" do
+ @server.should_receive(:mkd).and_respond("550 Requested action not taken.")
+ -> { @ftp.mkdir("test.folder") }.should raise_error(Net::FTPPermError)
+ end
+end
diff --git a/spec/ruby/library/net-ftp/mtime_spec.rb b/spec/ruby/library/net-ftp/mtime_spec.rb
new file mode 100644
index 0000000000..9dde1278a8
--- /dev/null
+++ b/spec/ruby/library/net-ftp/mtime_spec.rb
@@ -0,0 +1,50 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+require_relative 'fixtures/server'
+
+describe "Net::FTP#mtime" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "sends the MDTM with the passed filename command to the server" do
+ @ftp.mtime("test.file")
+ @ftp.last_response.should == "213 19980705132316\n"
+ end
+
+ describe "when passed filename" do
+ it "returns the last modification time of the passed file as a Time object in the local time" do
+ @ftp.mtime("test.file").should == Time.gm("1998", "07", "05", "13", "23", "16")
+ end
+ end
+
+ describe "when passed filename, local_time" do
+ it "returns the last modification time as a Time object in UTC when local_time is true" do
+ @ftp.mtime("test.file", true).should == Time.local("1998", "07", "05", "13", "23", "16")
+ end
+
+ it "returns the last modification time as a Time object in the local time when local_time is false" do
+ @ftp.mtime("test.file", false).should == Time.gm("1998", "07", "05", "13", "23", "16")
+ end
+ end
+
+ it "raises a Net::FTPPermError when the response code is 550" do
+ @server.should_receive(:mdtm).and_respond("550 Requested action not taken.")
+ -> { @ftp.mtime("test.file") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:mdtm).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.mtime("test.file") }.should raise_error(Net::FTPTempError)
+ end
+end
diff --git a/spec/ruby/library/net-ftp/nlst_spec.rb b/spec/ruby/library/net-ftp/nlst_spec.rb
new file mode 100644
index 0000000000..2f22543af6
--- /dev/null
+++ b/spec/ruby/library/net-ftp/nlst_spec.rb
@@ -0,0 +1,92 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+require_relative 'fixtures/server'
+
+describe "Net::FTP#nlst" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.passive = false
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ describe "when passed no arguments" do
+ it "returns an Array containing a list of files in the current dir" do
+ @ftp.nlst.should == ["last_response_code.rb", "list.rb", "pwd.rb"]
+ @ftp.last_response.should == "226 transfer complete (NLST)\n"
+ end
+ end
+
+ describe "when passed dir" do
+ it "returns an Array containing a list of files in the passed dir" do
+ @ftp.nlst("test.folder").should == ["last_response_code.rb", "list.rb", "pwd.rb"]
+ @ftp.last_response.should == "226 transfer complete (NLST test.folder)\n"
+ end
+ end
+
+ describe "when the NLST command fails" do
+ it "raises a Net::FTPTempError when the response code is 450" do
+ @server.should_receive(:nlst).and_respond("450 Requested file action not taken..")
+ -> { @ftp.nlst }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:nlst).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.nlst }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:nlst).and_respond("501 Syntax error, command unrecognized.")
+ -> { @ftp.nlst }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:nlst).and_respond("502 Command not implemented.")
+ -> { @ftp.nlst }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:nlst).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.nlst }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:nlst).and_respond("530 Not logged in.")
+ -> { @ftp.nlst }.should raise_error(Net::FTPPermError)
+ end
+ end
+
+ describe "when opening the data port fails" do
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:eprt).and_respond("500 Syntax error, command unrecognized.")
+ @server.should_receive(:port).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.nlst }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:eprt).and_respond("501 Syntax error in parameters or arguments.")
+ @server.should_receive(:port).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.nlst }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:eprt).and_respond("421 Service not available, closing control connection.")
+ @server.should_receive(:port).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.nlst }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:eprt).and_respond("530 Not logged in.")
+ @server.should_receive(:port).and_respond("530 Not logged in.")
+ -> { @ftp.nlst }.should raise_error(Net::FTPPermError)
+ end
+ end
+end
diff --git a/spec/ruby/library/net-ftp/noop_spec.rb b/spec/ruby/library/net-ftp/noop_spec.rb
new file mode 100644
index 0000000000..4743a39ef6
--- /dev/null
+++ b/spec/ruby/library/net-ftp/noop_spec.rb
@@ -0,0 +1,38 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+require_relative 'fixtures/server'
+
+describe "Net::FTP#noop" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "sends the NOOP command to the server" do
+ @ftp.noop
+ @ftp.last_response.should == "200 Command okay. (NOOP)\n"
+ end
+
+ it "returns nil" do
+ @ftp.noop.should be_nil
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:noop).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.noop }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:noop).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.noop }.should raise_error(Net::FTPTempError)
+ end
+end
diff --git a/spec/ruby/library/net-ftp/open_spec.rb b/spec/ruby/library/net-ftp/open_spec.rb
new file mode 100644
index 0000000000..e59496dc3c
--- /dev/null
+++ b/spec/ruby/library/net-ftp/open_spec.rb
@@ -0,0 +1,55 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+
+describe "Net::FTP.open" do
+ before :each do
+ @ftp = mock("Net::FTP instance")
+ Net::FTP.stub!(:new).and_return(@ftp)
+ end
+
+ describe "when passed no block" do
+ it "returns a new Net::FTP instance" do
+ Net::FTP.open("localhost").should equal(@ftp)
+ end
+
+ it "passes the passed arguments down to Net::FTP.new" do
+ Net::FTP.should_receive(:new).with("localhost", "user", "password", "account")
+ Net::FTP.open("localhost", "user", "password", "account")
+ end
+ end
+
+ describe "when passed a block" do
+ before :each do
+ @ftp.stub!(:close)
+ end
+
+ it "yields a new Net::FTP instance to the passed block" do
+ yielded = false
+ Net::FTP.open("localhost") do |ftp|
+ yielded = true
+ ftp.should equal(@ftp)
+ end
+ yielded.should be_true
+ end
+
+ it "closes the Net::FTP instance after yielding" do
+ Net::FTP.open("localhost") do |ftp|
+ ftp.should_receive(:close)
+ end
+ end
+
+ it "closes the Net::FTP instance even if an exception is raised while yielding" do
+ begin
+ Net::FTP.open("localhost") do |ftp|
+ ftp.should_receive(:close)
+ raise ArgumentError, "some exception"
+ end
+ rescue ArgumentError
+ end
+ end
+
+ it "returns the block's return value" do
+ Net::FTP.open("localhost") { :test }.should == :test
+ end
+ end
+end
diff --git a/spec/ruby/library/net-ftp/passive_spec.rb b/spec/ruby/library/net-ftp/passive_spec.rb
new file mode 100644
index 0000000000..97659f1b68
--- /dev/null
+++ b/spec/ruby/library/net-ftp/passive_spec.rb
@@ -0,0 +1,28 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+
+describe "Net::FTP#passive" do
+ it "returns true when self is in passive mode" do
+ ftp = Net::FTP.new
+ ftp.passive.should be_false
+
+ ftp.passive = true
+ ftp.passive.should be_true
+ end
+
+ it "is the value of Net::FTP.default_value by default" do
+ ruby_exe(fixture(__FILE__, "passive.rb")).should == "true"
+ end
+end
+
+describe "Net::FTP#passive=" do
+ it "sets self to passive mode when passed true" do
+ ftp = Net::FTP.new
+
+ ftp.passive = true
+ ftp.passive.should be_true
+
+ ftp.passive = false
+ ftp.passive.should be_false
+ end
+end
diff --git a/spec/ruby/library/net-ftp/put_spec.rb b/spec/ruby/library/net-ftp/put_spec.rb
new file mode 100644
index 0000000000..6d40d3d5b9
--- /dev/null
+++ b/spec/ruby/library/net-ftp/put_spec.rb
@@ -0,0 +1,21 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+require_relative 'fixtures/server'
+require_relative 'shared/puttextfile'
+require_relative 'shared/putbinaryfile'
+
+describe "Net::FTP#put (binary mode)" do
+ before :each do
+ @binary_mode = true
+ end
+
+ it_behaves_like :net_ftp_putbinaryfile, :put
+end
+
+describe "Net::FTP#put (text mode)" do
+ before :each do
+ @binary_mode = false
+ end
+
+ it_behaves_like :net_ftp_puttextfile, :put
+end
diff --git a/spec/ruby/library/net-ftp/putbinaryfile_spec.rb b/spec/ruby/library/net-ftp/putbinaryfile_spec.rb
new file mode 100644
index 0000000000..d0398229e5
--- /dev/null
+++ b/spec/ruby/library/net-ftp/putbinaryfile_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+require_relative 'fixtures/server'
+require_relative 'shared/putbinaryfile'
+
+describe "Net::FTP#putbinaryfile" do
+ it_behaves_like :net_ftp_putbinaryfile, :putbinaryfile
+end
diff --git a/spec/ruby/library/net-ftp/puttextfile_spec.rb b/spec/ruby/library/net-ftp/puttextfile_spec.rb
new file mode 100644
index 0000000000..b8bcac33df
--- /dev/null
+++ b/spec/ruby/library/net-ftp/puttextfile_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+require_relative 'fixtures/server'
+require_relative 'shared/puttextfile'
+
+describe "Net::FTP#puttextfile" do
+ it_behaves_like :net_ftp_puttextfile, :puttextfile
+end
diff --git a/spec/ruby/library/net-ftp/pwd_spec.rb b/spec/ruby/library/net-ftp/pwd_spec.rb
new file mode 100644
index 0000000000..992e2c4ed2
--- /dev/null
+++ b/spec/ruby/library/net-ftp/pwd_spec.rb
@@ -0,0 +1,53 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+require_relative 'fixtures/server'
+
+describe "Net::FTP#pwd" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "sends the PWD command to the server" do
+ @ftp.pwd
+ @ftp.last_response.should == "257 \"/some/dir/\" - current directory\n"
+ end
+
+ it "returns the current directory" do
+ @ftp.pwd.should == "/some/dir/"
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:pwd).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.pwd }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:pwd).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.pwd }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:pwd).and_respond("502 Command not implemented.")
+ -> { @ftp.pwd }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:pwd).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.pwd }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 550" do
+ @server.should_receive(:pwd).and_respond("550 Requested action not taken.")
+ -> { @ftp.pwd }.should raise_error(Net::FTPPermError)
+ end
+end
diff --git a/spec/ruby/library/net-ftp/quit_spec.rb b/spec/ruby/library/net-ftp/quit_spec.rb
new file mode 100644
index 0000000000..c5352ceada
--- /dev/null
+++ b/spec/ruby/library/net-ftp/quit_spec.rb
@@ -0,0 +1,33 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+require_relative 'fixtures/server'
+
+describe "Net::FTP#quit" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "sends the QUIT command to the server" do
+ @ftp.quit
+ @ftp.last_response.should == "221 OK, bye\n"
+ end
+
+ it "does not close the socket automatically" do
+ @ftp.quit
+ @ftp.closed?.should be_false
+ end
+
+ it "returns nil" do
+ @ftp.quit.should be_nil
+ end
+end
diff --git a/spec/ruby/library/net-ftp/rename_spec.rb b/spec/ruby/library/net-ftp/rename_spec.rb
new file mode 100644
index 0000000000..48f81b7deb
--- /dev/null
+++ b/spec/ruby/library/net-ftp/rename_spec.rb
@@ -0,0 +1,94 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+require_relative 'fixtures/server'
+
+describe "Net::FTP#rename" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ describe "when passed from_name, to_name" do
+ it "sends the RNFR command with the passed from_name and the RNTO command with the passed to_name to the server" do
+ @ftp.rename("from.file", "to.file")
+ @ftp.last_response.should == "250 Requested file action okay, completed. (Renamed from.file to to.file)\n"
+ end
+
+ it "returns something" do
+ @ftp.rename("from.file", "to.file").should be_nil
+ end
+ end
+
+ describe "when the RNFR command fails" do
+ it "raises a Net::FTPTempError when the response code is 450" do
+ @server.should_receive(:rnfr).and_respond("450 Requested file action not taken.")
+ -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 550" do
+ @server.should_receive(:rnfr).and_respond("550 Requested action not taken.")
+ -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:rnfr).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:rnfr).and_respond("502 Command not implemented.")
+ -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:rnfr).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:rnfr).and_respond("530 Not logged in.")
+ -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPPermError)
+ end
+ end
+
+ describe "when the RNTO command fails" do
+ it "raises a Net::FTPPermError when the response code is 532" do
+ @server.should_receive(:rnfr).and_respond("532 Need account for storing files.")
+ -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 553" do
+ @server.should_receive(:rnto).and_respond("553 Requested action not taken.")
+ -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:rnto).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:rnto).and_respond("502 Command not implemented.")
+ -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:rnto).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:rnto).and_respond("530 Not logged in.")
+ -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPPermError)
+ end
+ end
+end
diff --git a/spec/ruby/library/net-ftp/resume_spec.rb b/spec/ruby/library/net-ftp/resume_spec.rb
new file mode 100644
index 0000000000..6592fc5bb0
--- /dev/null
+++ b/spec/ruby/library/net-ftp/resume_spec.rb
@@ -0,0 +1,23 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+
+describe "Net::FTP#resume" do
+ it "returns true when self is set to resume uploads/downloads" do
+ ftp = Net::FTP.new
+ ftp.resume.should be_false
+
+ ftp.resume = true
+ ftp.resume.should be_true
+ end
+end
+
+describe "Net::FTP#resume=" do
+ it "sets self to resume uploads/downloads when set to true" do
+ ftp = Net::FTP.new
+ ftp.resume = true
+ ftp.resume.should be_true
+
+ ftp.resume = false
+ ftp.resume.should be_false
+ end
+end
diff --git a/spec/ruby/library/net-ftp/retrbinary_spec.rb b/spec/ruby/library/net-ftp/retrbinary_spec.rb
new file mode 100644
index 0000000000..de024208aa
--- /dev/null
+++ b/spec/ruby/library/net-ftp/retrbinary_spec.rb
@@ -0,0 +1,30 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+require_relative 'fixtures/server'
+
+describe "Net::FTP#retrbinary" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "sends the passed command to the server" do
+ @ftp.retrbinary("RETR test", 4096) {}
+ @ftp.last_response.should == "226 Closing data connection. (RETR test)\n"
+ end
+
+ it "yields the received content as binary blocks of the passed size" do
+ res = []
+ @ftp.retrbinary("RETR test", 10) { |bin| res << bin }
+ res.should == [ "This is th", "e content\n", "of the fil", "e named 't", "est'.\n" ]
+ end
+end
diff --git a/spec/ruby/library/net-ftp/retrlines_spec.rb b/spec/ruby/library/net-ftp/retrlines_spec.rb
new file mode 100644
index 0000000000..866ecb5f40
--- /dev/null
+++ b/spec/ruby/library/net-ftp/retrlines_spec.rb
@@ -0,0 +1,34 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+require_relative 'fixtures/server'
+
+describe "Net::FTP#retrlines" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "sends the passed command over the socket" do
+ @ftp.retrlines("LIST test.dir") {}
+ @ftp.last_response.should == "226 transfer complete (LIST test.dir)\n"
+ end
+
+ it "yields each received line to the passed block" do
+ res = []
+ @ftp.retrlines("LIST test.dir") { |x| res << x }
+ res.should == [
+ "-rw-r--r-- 1 spec staff 507 17 Jul 18:41 last_response_code.rb",
+ "-rw-r--r-- 1 spec staff 50 17 Jul 18:41 list.rb",
+ "-rw-r--r-- 1 spec staff 48 17 Jul 18:41 pwd.rb"
+ ]
+ end
+end
diff --git a/spec/ruby/library/net-ftp/return_code_spec.rb b/spec/ruby/library/net-ftp/return_code_spec.rb
new file mode 100644
index 0000000000..35a6232f7e
--- /dev/null
+++ b/spec/ruby/library/net-ftp/return_code_spec.rb
@@ -0,0 +1,24 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+
+describe "Net::FTP#return_code" do
+ before :each do
+ @ftp = Net::FTP.new
+ end
+
+ it "outputs a warning and returns a newline" do
+ -> do
+ @ftp.return_code.should == "\n"
+ end.should complain(/warning: Net::FTP#return_code is obsolete and do nothing/)
+ end
+end
+
+describe "Net::FTP#return_code=" do
+ before :each do
+ @ftp = Net::FTP.new
+ end
+
+ it "outputs a warning" do
+ -> { @ftp.return_code = 123 }.should complain(/warning: Net::FTP#return_code= is obsolete and do nothing/)
+ end
+end
diff --git a/spec/ruby/library/net-ftp/rmdir_spec.rb b/spec/ruby/library/net-ftp/rmdir_spec.rb
new file mode 100644
index 0000000000..400874d60d
--- /dev/null
+++ b/spec/ruby/library/net-ftp/rmdir_spec.rb
@@ -0,0 +1,58 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+require_relative 'fixtures/server'
+
+describe "Net::FTP#rmdir" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "sends the RMD command with the passed pathname to the server" do
+ @ftp.rmdir("test.folder")
+ @ftp.last_response.should == "250 Requested file action okay, completed. (RMD test.folder)\n"
+ end
+
+ it "returns nil" do
+ @ftp.rmdir("test.folder").should be_nil
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:rmd).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.rmdir("test.folder") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:rmd).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.rmdir("test.folder") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:rmd).and_respond("502 Command not implemented.")
+ -> { @ftp.rmdir("test.folder") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:rmd).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.rmdir("test.folder") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:rmd).and_respond("530 Not logged in.")
+ -> { @ftp.rmdir("test.folder") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 550" do
+ @server.should_receive(:rmd).and_respond("550 Requested action not taken.")
+ -> { @ftp.rmdir("test.folder") }.should raise_error(Net::FTPPermError)
+ end
+end
diff --git a/spec/ruby/library/net-ftp/sendcmd_spec.rb b/spec/ruby/library/net-ftp/sendcmd_spec.rb
new file mode 100644
index 0000000000..c50b373869
--- /dev/null
+++ b/spec/ruby/library/net-ftp/sendcmd_spec.rb
@@ -0,0 +1,54 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+require_relative 'fixtures/server'
+
+describe "Net::FTP#sendcmd" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "sends the passed command to the server" do
+ @ftp.sendcmd("HELP")
+ @ftp.last_response.should == "211 System status, or system help reply. (HELP)\n"
+ end
+
+ it "returns the server's response" do
+ @ftp.sendcmd("HELP").should == "211 System status, or system help reply. (HELP)\n"
+ end
+
+ it "raises no error when the response code is 1xx, 2xx or 3xx" do
+ @server.should_receive(:help).and_respond("120 Service ready in nnn minutes.")
+ -> { @ftp.sendcmd("HELP") }.should_not raise_error
+
+ @server.should_receive(:help).and_respond("200 Command okay.")
+ -> { @ftp.sendcmd("HELP") }.should_not raise_error
+
+ @server.should_receive(:help).and_respond("350 Requested file action pending further information.")
+ -> { @ftp.sendcmd("HELP") }.should_not raise_error
+ end
+
+ it "raises a Net::FTPTempError when the response code is 4xx" do
+ @server.should_receive(:help).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.sendcmd("HELP") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 5xx" do
+ @server.should_receive(:help).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.sendcmd("HELP") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPProtoError when the response code is not between 1xx-5xx" do
+ @server.should_receive(:help).and_respond("999 Invalid response.")
+ -> { @ftp.sendcmd("HELP") }.should raise_error(Net::FTPProtoError)
+ end
+end
diff --git a/spec/ruby/library/net-ftp/set_socket_spec.rb b/spec/ruby/library/net-ftp/set_socket_spec.rb
new file mode 100644
index 0000000000..8182dd8b33
--- /dev/null
+++ b/spec/ruby/library/net-ftp/set_socket_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+
+describe "Net::FTP#set_socket" do
+ # TODO: I won't spec this method, as it is not used
+ # anywhere and it should be private anyway.
+ it "needs to be reviewed for spec completeness"
+end
diff --git a/spec/ruby/library/net-ftp/shared/getbinaryfile.rb b/spec/ruby/library/net-ftp/shared/getbinaryfile.rb
new file mode 100644
index 0000000000..ceec8e7cd5
--- /dev/null
+++ b/spec/ruby/library/net-ftp/shared/getbinaryfile.rb
@@ -0,0 +1,150 @@
+describe :net_ftp_getbinaryfile, shared: true do
+ before :each do
+ @fixture_file = __dir__ + "/../fixtures/getbinaryfile"
+ @tmp_file = tmp("getbinaryfile")
+
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ @ftp.binary = @binary_mode
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+
+ rm_r @tmp_file
+ end
+
+ it "sends the RETR command to the server" do
+ @ftp.send(@method, "test", @tmp_file)
+ @ftp.last_response.should == "226 Closing data connection. (RETR test)\n"
+ end
+
+ it "returns nil" do
+ @ftp.send(@method, "test", @tmp_file).should be_nil
+ end
+
+ it "saves the contents of the passed remote file to the passed local file" do
+ @ftp.send(@method, "test", @tmp_file)
+ File.read(@tmp_file).should == "This is the content\nof the file named 'test'.\n"
+ end
+
+ describe "when passed a block" do
+ it "yields the received content as binary blocks of the passed size" do
+ res = []
+ @ftp.send(@method, "test", @tmp_file, 10) { |bin| res << bin }
+ res.should == [ "This is th", "e content\n", "of the fil", "e named 't", "est'.\n" ]
+ end
+ end
+
+ describe "when resuming an existing file" do
+ before :each do
+ @tmp_file = tmp("getbinaryfile_resume")
+
+ File.open(@tmp_file, "wb") do |f|
+ f << "This is the content\n"
+ end
+
+ @ftp.resume = true
+ end
+
+ it "saves the remaining content of the passed remote file to the passed local file" do
+ @ftp.send(@method, "test", @tmp_file)
+ File.read(@tmp_file).should == "This is the content\nof the file named 'test'.\n"
+ end
+
+ describe "and the REST command fails" do
+ it "raises a Net::FTPProtoError when the response code is 550" do
+ @server.should_receive(:rest).and_respond("Requested action not taken.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPProtoError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:rest).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:rest).and_respond("501 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:rest).and_respond("502 Command not implemented.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:rest).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:rest).and_respond("530 Not logged in.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
+ end
+ end
+ end
+
+ describe "when the RETR command fails" do
+ it "raises a Net::FTPTempError when the response code is 450" do
+ @server.should_receive(:retr).and_respond("450 Requested file action not taken.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPProtoError when the response code is 550" do
+ @server.should_receive(:retr).and_respond("Requested action not taken.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPProtoError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:retr).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:retr).and_respond("501 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:retr).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:retr).and_respond("530 Not logged in.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
+ end
+ end
+
+ describe "when opening the data port fails" do
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:eprt).and_respond("500 Syntax error, command unrecognized.")
+ @server.should_receive(:port).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:eprt).and_respond("501 Syntax error in parameters or arguments.")
+ @server.should_receive(:port).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:eprt).and_respond("421 Service not available, closing control connection.")
+ @server.should_receive(:port).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:eprt).and_respond("530 Not logged in.")
+ @server.should_receive(:port).and_respond("530 Not logged in.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
+ end
+ end
+end
diff --git a/spec/ruby/library/net-ftp/shared/gettextfile.rb b/spec/ruby/library/net-ftp/shared/gettextfile.rb
new file mode 100644
index 0000000000..7fe14f7dfb
--- /dev/null
+++ b/spec/ruby/library/net-ftp/shared/gettextfile.rb
@@ -0,0 +1,100 @@
+describe :net_ftp_gettextfile, shared: true do
+ before :each do
+ @tmp_file = tmp("gettextfile")
+
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ @ftp.binary = @binary_mode
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+
+ rm_r @tmp_file
+ end
+
+ it "sends the RETR command to the server" do
+ @ftp.send(@method, "test", @tmp_file)
+ @ftp.last_response.should == "226 Closing data connection. (RETR test)\n"
+ end
+
+ it "returns nil" do
+ @ftp.send(@method, "test", @tmp_file).should be_nil
+ end
+
+ it "saves the contents of the passed remote file to the passed local file" do
+ @ftp.send(@method, "test", @tmp_file)
+ File.read(@tmp_file).should == "This is the content\nof the file named 'test'.\n"
+ end
+
+ describe "when passed a block" do
+ it "yields each line of the retrieved file to the passed block" do
+ res = []
+ @ftp.send(@method, "test", @tmp_file) { |line| res << line }
+ res.should == [ "This is the content", "of the file named 'test'."]
+ end
+ end
+
+ describe "when the RETR command fails" do
+ it "raises a Net::FTPTempError when the response code is 450" do
+ @server.should_receive(:retr).and_respond("450 Requested file action not taken.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPProtoError when the response code is 550" do
+ @server.should_receive(:retr).and_respond("Requested action not taken.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPProtoError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:retr).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:retr).and_respond("501 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:retr).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:retr).and_respond("530 Not logged in.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
+ end
+ end
+
+ describe "when opening the data port fails" do
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:eprt).and_respond("500 Syntax error, command unrecognized.")
+ @server.should_receive(:port).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:eprt).and_respond("501 Syntax error in parameters or arguments.")
+ @server.should_receive(:port).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:eprt).and_respond("421 Service not available, closing control connection.")
+ @server.should_receive(:port).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:eprt).and_respond("530 Not logged in.")
+ @server.should_receive(:port).and_respond("530 Not logged in.")
+ -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
+ end
+ end
+end
diff --git a/spec/ruby/library/net/ftp/shared/last_response_code.rb b/spec/ruby/library/net-ftp/shared/last_response_code.rb
index 4fe53677db..4fe53677db 100644
--- a/spec/ruby/library/net/ftp/shared/last_response_code.rb
+++ b/spec/ruby/library/net-ftp/shared/last_response_code.rb
diff --git a/spec/ruby/library/net/ftp/shared/list.rb b/spec/ruby/library/net-ftp/shared/list.rb
index adc3fa59c1..adc3fa59c1 100644
--- a/spec/ruby/library/net/ftp/shared/list.rb
+++ b/spec/ruby/library/net-ftp/shared/list.rb
diff --git a/spec/ruby/library/net-ftp/shared/putbinaryfile.rb b/spec/ruby/library/net-ftp/shared/putbinaryfile.rb
new file mode 100644
index 0000000000..45f53adc2a
--- /dev/null
+++ b/spec/ruby/library/net-ftp/shared/putbinaryfile.rb
@@ -0,0 +1,167 @@
+describe :net_ftp_putbinaryfile, shared: true do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @local_fixture_file = __dir__ + "/../fixtures/putbinaryfile"
+ @remote_tmp_file = tmp("binaryfile", false)
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ @ftp.binary = @binary_mode
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+
+ rm_r @remote_tmp_file
+ end
+
+ it "sends the STOR command to the server" do
+ @ftp.send(@method, @local_fixture_file, "binary")
+ @ftp.last_response.should == "200 OK, Data received. (STOR binary)\n"
+ end
+
+ it "sends the contents of the passed local_file, without modifications" do
+ @ftp.send(@method, @local_fixture_file, "binary")
+
+ remote_lines = File.readlines(@remote_tmp_file)
+ local_lines = File.readlines(@local_fixture_file)
+
+ remote_lines.should == local_lines
+ end
+
+ it "returns nil" do
+ @ftp.send(@method, @local_fixture_file, "binary").should be_nil
+ end
+
+ describe "when passed a block" do
+ it "yields the transmitted content as binary blocks of the passed size" do
+ res = []
+ @ftp.send(@method, @local_fixture_file, "binary", 10) { |x| res << x }
+ res.should == [
+ "This is an", " example f",
+ "ile\nwhich ", "is going t",
+ "o be trans", "mitted\nusi",
+ "ng #putbin", "aryfile.\n"
+ ]
+ end
+ end
+
+ describe "when resuming an existing file" do
+ before :each do
+ File.open(@remote_tmp_file, "w") do |f|
+ f << "This is an example file\n"
+ end
+
+ @ftp.resume = true
+ end
+
+ it "sends the remaining content of the passed local_file to the passed remote_file" do
+ @ftp.send(@method, @local_fixture_file, "binary")
+ File.read(@remote_tmp_file).should == File.read(@local_fixture_file)
+ end
+
+ describe "and the APPE command fails" do
+ it "raises a Net::FTPProtoError when the response code is 550" do
+ @server.should_receive(:appe).and_respond("Requested action not taken.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPProtoError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:appe).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:appe).and_respond("501 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:appe).and_respond("502 Command not implemented.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:appe).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:appe).and_respond("530 Not logged in.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
+ end
+ end
+ end
+
+ describe "when the STOR command fails" do
+ it "raises a Net::FTPPermError when the response code is 532" do
+ @server.should_receive(:stor).and_respond("532 Need account for storing files.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 450" do
+ @server.should_receive(:stor).and_respond("450 Requested file action not taken.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 452" do
+ @server.should_receive(:stor).and_respond("452 Requested action not taken.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 553" do
+ @server.should_receive(:stor).and_respond("553 Requested action not taken.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:stor).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:stor).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:stor).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:stor).and_respond("530 Not logged in.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
+ end
+ end
+
+ describe "when opening the data port fails" do
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:eprt).and_respond("500 Syntax error, command unrecognized.")
+ @server.should_receive(:port).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:eprt).and_respond("501 Syntax error in parameters or arguments.")
+ @server.should_receive(:port).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:eprt).and_respond("421 Service not available, closing control connection.")
+ @server.should_receive(:port).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:eprt).and_respond("530 Not logged in.")
+ @server.should_receive(:port).and_respond("530 Not logged in.")
+ -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
+ end
+ end
+end
diff --git a/spec/ruby/library/net-ftp/shared/puttextfile.rb b/spec/ruby/library/net-ftp/shared/puttextfile.rb
new file mode 100644
index 0000000000..4722439674
--- /dev/null
+++ b/spec/ruby/library/net-ftp/shared/puttextfile.rb
@@ -0,0 +1,120 @@
+describe :net_ftp_puttextfile, shared: true do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @local_fixture_file = __dir__ + "/../fixtures/puttextfile"
+ @remote_tmp_file = tmp("textfile", false)
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ @ftp.binary = @binary_mode
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+
+ rm_r @remote_tmp_file
+ end
+
+ it "sends the STOR command to the server" do
+ @ftp.send(@method, @local_fixture_file, "text")
+ @ftp.last_response.should == "200 OK, Data received. (STOR text)\n"
+ end
+
+ it "sends the contents of the passed local_file, using \\r\\n as the newline separator" do
+ @ftp.send(@method, @local_fixture_file, "text")
+
+ remote_lines = File.binread(@remote_tmp_file)
+ local_lines = File.binread(@local_fixture_file)
+
+ remote_lines.should_not == local_lines
+ remote_lines.should == local_lines.gsub("\n", "\r\n")
+ end
+
+ it "returns nil" do
+ @ftp.send(@method, @local_fixture_file, "text").should be_nil
+ end
+
+ describe "when passed a block" do
+ it "yields each transmitted line" do
+ res = []
+ @ftp.send(@method, @local_fixture_file, "text") { |x| res << x }
+ res.should == [
+ "This is an example file\r\n",
+ "which is going to be transmitted\r\n",
+ "using #puttextfile.\r\n"
+ ]
+ end
+ end
+
+ describe "when the STOR command fails" do
+ it "raises a Net::FTPPermError when the response code is 532" do
+ @server.should_receive(:stor).and_respond("532 Need account for storing files.")
+ -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 450" do
+ @server.should_receive(:stor).and_respond("450 Requested file action not taken.")
+ -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 452" do
+ @server.should_receive(:stor).and_respond("452 Requested action not taken.")
+ -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 553" do
+ @server.should_receive(:stor).and_respond("553 Requested action not taken.")
+ -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:stor).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:stor).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:stor).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:stor).and_respond("530 Not logged in.")
+ -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPPermError)
+ end
+ end
+
+ describe "when opening the data port fails" do
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:eprt).and_respond("500 Syntax error, command unrecognized.")
+ @server.should_receive(:port).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:eprt).and_respond("501 Syntax error in parameters or arguments.")
+ @server.should_receive(:port).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:eprt).and_respond("421 Service not available, closing control connection.")
+ @server.should_receive(:port).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:eprt).and_respond("530 Not logged in.")
+ @server.should_receive(:port).and_respond("530 Not logged in.")
+ -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPPermError)
+ end
+ end
+end
diff --git a/spec/ruby/library/net/ftp/shared/pwd.rb b/spec/ruby/library/net-ftp/shared/pwd.rb
index 951d020f2d..951d020f2d 100644
--- a/spec/ruby/library/net/ftp/shared/pwd.rb
+++ b/spec/ruby/library/net-ftp/shared/pwd.rb
diff --git a/spec/ruby/library/net-ftp/site_spec.rb b/spec/ruby/library/net-ftp/site_spec.rb
new file mode 100644
index 0000000000..c3e589a920
--- /dev/null
+++ b/spec/ruby/library/net-ftp/site_spec.rb
@@ -0,0 +1,53 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+require_relative 'fixtures/server'
+
+describe "Net::FTP#site" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "sends the SITE command with the passed argument to the server" do
+ @ftp.site("param")
+ @ftp.last_response.should == "200 Command okay. (SITE param)\n"
+ end
+
+ it "returns nil" do
+ @ftp.site("param").should be_nil
+ end
+
+ it "does not raise an error when the response code is 202" do
+ @server.should_receive(:site).and_respond("202 Command not implemented, superfluous at this site.")
+ -> { @ftp.site("param") }.should_not raise_error
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:site).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.site("param") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:site).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.site("param") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:site).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.site("param") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:site).and_respond("530 Requested action not taken.")
+ -> { @ftp.site("param") }.should raise_error(Net::FTPPermError)
+ end
+end
diff --git a/spec/ruby/library/net-ftp/size_spec.rb b/spec/ruby/library/net-ftp/size_spec.rb
new file mode 100644
index 0000000000..0cf2e24477
--- /dev/null
+++ b/spec/ruby/library/net-ftp/size_spec.rb
@@ -0,0 +1,48 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+require_relative 'fixtures/server'
+
+describe "Net::FTP#size" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "sends the SIZE command to the server" do
+ @ftp.size("test.file")
+ @ftp.last_response.should == "213 1024\n"
+ end
+
+ it "returns the size of the passed file as Integer" do
+ @ftp.size("test.file").should eql(1024)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:size).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.size("test.file") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:size).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.size("test.file") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:size).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.size("test.file") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 550" do
+ @server.should_receive(:size).and_respond("550 Requested action not taken.")
+ -> { @ftp.size("test.file") }.should raise_error(Net::FTPPermError)
+ end
+end
diff --git a/spec/ruby/library/net/ftp/spec_helper.rb b/spec/ruby/library/net-ftp/spec_helper.rb
index c87d16218b..c87d16218b 100644
--- a/spec/ruby/library/net/ftp/spec_helper.rb
+++ b/spec/ruby/library/net-ftp/spec_helper.rb
diff --git a/spec/ruby/library/net-ftp/status_spec.rb b/spec/ruby/library/net-ftp/status_spec.rb
new file mode 100644
index 0000000000..9d9f86c381
--- /dev/null
+++ b/spec/ruby/library/net-ftp/status_spec.rb
@@ -0,0 +1,67 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+require_relative 'fixtures/server'
+
+describe "Net::FTP#status" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "sends the STAT command to the server" do
+ @ftp.status
+ @ftp.last_response.should == "211 System status, or system help reply. (STAT)\n"
+ end
+
+ it "sends the STAT command with an optional parameter to the server" do
+ @ftp.status("/pub").should == "211 System status, or system help reply. (STAT /pub)\n"
+ end
+
+ it "returns the received information" do
+ @ftp.status.should == "211 System status, or system help reply. (STAT)\n"
+ end
+
+ it "does not raise an error when the response code is 212" do
+ @server.should_receive(:stat).and_respond("212 Directory status.")
+ -> { @ftp.status }.should_not raise_error
+ end
+
+ it "does not raise an error when the response code is 213" do
+ @server.should_receive(:stat).and_respond("213 File status.")
+ -> { @ftp.status }.should_not raise_error
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:stat).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.status }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:stat).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.status }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:stat).and_respond("502 Command not implemented.")
+ -> { @ftp.status }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:stat).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.status }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 530" do
+ @server.should_receive(:stat).and_respond("530 Requested action not taken.")
+ -> { @ftp.status }.should raise_error(Net::FTPPermError)
+ end
+end
diff --git a/spec/ruby/library/net-ftp/storbinary_spec.rb b/spec/ruby/library/net-ftp/storbinary_spec.rb
new file mode 100644
index 0000000000..aa4c51f2e8
--- /dev/null
+++ b/spec/ruby/library/net-ftp/storbinary_spec.rb
@@ -0,0 +1,49 @@
+require_relative '../../spec_helper'
+
+require_relative 'spec_helper'
+require_relative 'fixtures/server'
+
+describe "Net::FTP#storbinary" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @local_fixture_file = __dir__ + "/fixtures/putbinaryfile"
+ @tmp_file = tmp("binaryfile", false)
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+
+ rm_r @tmp_file
+ end
+
+ it "sends the passed command and the passed File object's content to the server" do
+ File.open(@local_fixture_file) do |f|
+ f.binmode
+
+ @ftp.storbinary("STOR binary", f, 4096) {}
+ @ftp.last_response.should == "200 OK, Data received. (STOR binary)\n"
+ end
+ end
+
+ it "yields the transmitted content as binary blocks of the passed size" do
+ File.open(@local_fixture_file) do |f|
+ f.binmode
+
+ res = []
+ @ftp.storbinary("STOR binary", f, 10) { |x| res << x }
+ res.should == [
+ "This is an", " example f",
+ "ile\nwhich ", "is going t",
+ "o be trans", "mitted\nusi",
+ "ng #putbin", "aryfile.\n"
+ ]
+ end
+ end
+end
diff --git a/spec/ruby/library/net-ftp/storlines_spec.rb b/spec/ruby/library/net-ftp/storlines_spec.rb
new file mode 100644
index 0000000000..dc6830da7b
--- /dev/null
+++ b/spec/ruby/library/net-ftp/storlines_spec.rb
@@ -0,0 +1,44 @@
+require_relative '../../spec_helper'
+
+require_relative 'spec_helper'
+require_relative 'fixtures/server'
+
+describe "Net::FTP#storlines" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @local_fixture_file = __dir__ + "/fixtures/puttextfile"
+ @tmp_file = tmp("textfile", false)
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+
+ rm_r @tmp_file
+ end
+
+ it "sends the passed command and the passed File object's content to the server" do
+ File.open(@local_fixture_file) do |f|
+ @ftp.storlines("STOR text", f) {}
+ @ftp.last_response.should == "200 OK, Data received. (STOR text)\n"
+ end
+ end
+
+ it "yields each line of the transmitted content" do
+ File.open(@local_fixture_file) do |f|
+ res = []
+ @ftp.storlines("STOR text", f) { |x| res << x }
+ res.should == [
+ "This is an example file\r\n",
+ "which is going to be transmitted\r\n",
+ "using #puttextfile.\r\n"
+ ]
+ end
+ end
+end
diff --git a/spec/ruby/library/net-ftp/system_spec.rb b/spec/ruby/library/net-ftp/system_spec.rb
new file mode 100644
index 0000000000..2b7f0d2560
--- /dev/null
+++ b/spec/ruby/library/net-ftp/system_spec.rb
@@ -0,0 +1,48 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+require_relative 'fixtures/server'
+
+describe "Net::FTP#system" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "sends the SYST command to the server" do
+ @ftp.system
+ @ftp.last_response.should =~ /\A215 FTP Dummy Server \(SYST\)\Z/
+ end
+
+ it "returns the received information" do
+ @ftp.system.should =~ /\AFTP Dummy Server \(SYST\)\Z/
+ end
+
+ it "raises a Net::FTPPermError when the response code is 500" do
+ @server.should_receive(:syst).and_respond("500 Syntax error, command unrecognized.")
+ -> { @ftp.system }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 501" do
+ @server.should_receive(:syst).and_respond("501 Syntax error in parameters or arguments.")
+ -> { @ftp.system }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 502" do
+ @server.should_receive(:syst).and_respond("502 Command not implemented.")
+ -> { @ftp.system }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 421" do
+ @server.should_receive(:syst).and_respond("421 Service not available, closing control connection.")
+ -> { @ftp.system }.should raise_error(Net::FTPTempError)
+ end
+end
diff --git a/spec/ruby/library/net-ftp/voidcmd_spec.rb b/spec/ruby/library/net-ftp/voidcmd_spec.rb
new file mode 100644
index 0000000000..f2536fe697
--- /dev/null
+++ b/spec/ruby/library/net-ftp/voidcmd_spec.rb
@@ -0,0 +1,54 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+require_relative 'fixtures/server'
+
+describe "Net::FTP#voidcmd" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "sends the passed command to the server" do
+ @server.should_receive(:help).and_respond("2xx Does not raise.")
+ -> { @ftp.voidcmd("HELP") }.should_not raise_error
+ end
+
+ it "returns nil" do
+ @server.should_receive(:help).and_respond("2xx Does not raise.")
+ @ftp.voidcmd("HELP").should be_nil
+ end
+
+ it "raises a Net::FTPReplyError when the response code is 1xx" do
+ @server.should_receive(:help).and_respond("1xx Does raise a Net::FTPReplyError.")
+ -> { @ftp.voidcmd("HELP") }.should raise_error(Net::FTPReplyError)
+ end
+
+ it "raises a Net::FTPReplyError when the response code is 3xx" do
+ @server.should_receive(:help).and_respond("3xx Does raise a Net::FTPReplyError.")
+ -> { @ftp.voidcmd("HELP") }.should raise_error(Net::FTPReplyError)
+ end
+
+ it "raises a Net::FTPTempError when the response code is 4xx" do
+ @server.should_receive(:help).and_respond("4xx Does raise a Net::FTPTempError.")
+ -> { @ftp.voidcmd("HELP") }.should raise_error(Net::FTPTempError)
+ end
+
+ it "raises a Net::FTPPermError when the response code is 5xx" do
+ @server.should_receive(:help).and_respond("5xx Does raise a Net::FTPPermError.")
+ -> { @ftp.voidcmd("HELP") }.should raise_error(Net::FTPPermError)
+ end
+
+ it "raises a Net::FTPProtoError when the response code is not valid" do
+ @server.should_receive(:help).and_respond("999 Does raise a Net::FTPProtoError.")
+ -> { @ftp.voidcmd("HELP") }.should raise_error(Net::FTPProtoError)
+ end
+end
diff --git a/spec/ruby/library/net-ftp/welcome_spec.rb b/spec/ruby/library/net-ftp/welcome_spec.rb
new file mode 100644
index 0000000000..4279127ce3
--- /dev/null
+++ b/spec/ruby/library/net-ftp/welcome_spec.rb
@@ -0,0 +1,25 @@
+require_relative '../../spec_helper'
+require_relative 'spec_helper'
+require_relative 'fixtures/server'
+
+describe "Net::FTP#welcome" do
+ before :each do
+ @server = NetFTPSpecs::DummyFTP.new
+ @server.serve_once
+
+ @ftp = Net::FTP.new
+ @ftp.connect(@server.hostname, @server.server_port)
+ end
+
+ after :each do
+ @ftp.quit rescue nil
+ @ftp.close
+ @server.stop
+ end
+
+ it "returns the server's welcome message" do
+ @ftp.welcome.should be_nil
+ @ftp.login
+ @ftp.welcome.should == "230 User logged in, proceed. (USER anonymous)\n"
+ end
+end
diff --git a/spec/ruby/library/net-http/HTTPBadResponse_spec.rb b/spec/ruby/library/net-http/HTTPBadResponse_spec.rb
new file mode 100644
index 0000000000..8f2e8ccfaf
--- /dev/null
+++ b/spec/ruby/library/net-http/HTTPBadResponse_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPBadResponse" do
+ it "is a subclass of StandardError" do
+ Net::HTTPBadResponse.should < StandardError
+ end
+end
diff --git a/spec/ruby/library/net-http/HTTPClientExcepton_spec.rb b/spec/ruby/library/net-http/HTTPClientExcepton_spec.rb
new file mode 100644
index 0000000000..2992e6596f
--- /dev/null
+++ b/spec/ruby/library/net-http/HTTPClientExcepton_spec.rb
@@ -0,0 +1,12 @@
+require_relative '../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPClientException" do
+ it "is a subclass of Net::ProtoServerError" do
+ Net::HTTPClientException.should < Net::ProtoServerError
+ end
+
+ it "includes the Net::HTTPExceptions module" do
+ Net::HTTPClientException.should < Net::HTTPExceptions
+ end
+end
diff --git a/spec/ruby/library/net-http/HTTPError_spec.rb b/spec/ruby/library/net-http/HTTPError_spec.rb
new file mode 100644
index 0000000000..7f79eef8cf
--- /dev/null
+++ b/spec/ruby/library/net-http/HTTPError_spec.rb
@@ -0,0 +1,12 @@
+require_relative '../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPError" do
+ it "is a subclass of Net::ProtocolError" do
+ Net::HTTPError.should < Net::ProtocolError
+ end
+
+ it "includes the Net::HTTPExceptions module" do
+ Net::HTTPError.should < Net::HTTPExceptions
+ end
+end
diff --git a/spec/ruby/library/net-http/HTTPFatalError_spec.rb b/spec/ruby/library/net-http/HTTPFatalError_spec.rb
new file mode 100644
index 0000000000..0113b9da2d
--- /dev/null
+++ b/spec/ruby/library/net-http/HTTPFatalError_spec.rb
@@ -0,0 +1,12 @@
+require_relative '../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPFatalError" do
+ it "is a subclass of Net::ProtoFatalError" do
+ Net::HTTPFatalError.should < Net::ProtoFatalError
+ end
+
+ it "includes the Net::HTTPExceptions module" do
+ Net::HTTPFatalError.should < Net::HTTPExceptions
+ end
+end
diff --git a/spec/ruby/library/net-http/HTTPHeaderSyntaxError_spec.rb b/spec/ruby/library/net-http/HTTPHeaderSyntaxError_spec.rb
new file mode 100644
index 0000000000..b3b73ff46f
--- /dev/null
+++ b/spec/ruby/library/net-http/HTTPHeaderSyntaxError_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPHeaderSyntaxError" do
+ it "is a subclass of StandardError" do
+ Net::HTTPHeaderSyntaxError.should < StandardError
+ end
+end
diff --git a/spec/ruby/library/net-http/HTTPRetriableError_spec.rb b/spec/ruby/library/net-http/HTTPRetriableError_spec.rb
new file mode 100644
index 0000000000..677731fb68
--- /dev/null
+++ b/spec/ruby/library/net-http/HTTPRetriableError_spec.rb
@@ -0,0 +1,12 @@
+require_relative '../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPRetriableError" do
+ it "is a subclass of Net::ProtoRetriableError" do
+ Net::HTTPRetriableError.should < Net::ProtoRetriableError
+ end
+
+ it "includes the Net::HTTPExceptions module" do
+ Net::HTTPRetriableError.should < Net::HTTPExceptions
+ end
+end
diff --git a/spec/ruby/library/net-http/HTTPServerException_spec.rb b/spec/ruby/library/net-http/HTTPServerException_spec.rb
new file mode 100644
index 0000000000..5e0a833fee
--- /dev/null
+++ b/spec/ruby/library/net-http/HTTPServerException_spec.rb
@@ -0,0 +1,12 @@
+require_relative '../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPServerException" do
+ it "is a subclass of Net::ProtoServerError and is warned as deprecated" do
+ -> { Net::HTTPServerException.should < Net::ProtoServerError }.should complain(/warning: constant Net::HTTPServerException is deprecated/)
+ end
+
+ it "includes the Net::HTTPExceptions module and is warned as deprecated" do
+ -> { Net::HTTPServerException.should < Net::HTTPExceptions }.should complain(/warning: constant Net::HTTPServerException is deprecated/)
+ end
+end
diff --git a/spec/ruby/library/net-http/http/Proxy_spec.rb b/spec/ruby/library/net-http/http/Proxy_spec.rb
new file mode 100644
index 0000000000..a1a04fa00b
--- /dev/null
+++ b/spec/ruby/library/net-http/http/Proxy_spec.rb
@@ -0,0 +1,35 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTP.Proxy" do
+ it "returns a new subclass of Net::HTTP" do
+ Net::HTTP.Proxy("localhost").should < Net::HTTP
+ end
+
+ it "returns Net::HTTP when the passed address is nil" do
+ Net::HTTP.Proxy(nil).should == Net::HTTP
+ end
+
+ it "sets the returned subclasses' proxy options based on the passed arguments" do
+ http_with_proxy = Net::HTTP.Proxy("localhost", 1234, "rspec", "rocks")
+ http_with_proxy.proxy_address.should == "localhost"
+ http_with_proxy.proxy_port.should eql(1234)
+ http_with_proxy.proxy_user.should == "rspec"
+ http_with_proxy.proxy_pass.should == "rocks"
+ end
+end
+
+describe "Net::HTTP#proxy?" do
+ describe "when self is no proxy class instance" do
+ it "returns false" do
+ Net::HTTP.new("localhost", 3333).proxy?.should be_false
+ end
+ end
+
+ describe "when self is a proxy class instance" do
+ it "returns false" do
+ http_with_proxy = Net::HTTP.Proxy("localhost", 1234, "rspec", "rocks")
+ http_with_proxy.new("localhost", 3333).proxy?.should be_true
+ end
+ end
+end
diff --git a/spec/ruby/library/net-http/http/active_spec.rb b/spec/ruby/library/net-http/http/active_spec.rb
new file mode 100644
index 0000000000..c260274594
--- /dev/null
+++ b/spec/ruby/library/net-http/http/active_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+require_relative 'shared/started'
+
+describe "Net::HTTP#active?" do
+ it_behaves_like :net_http_started_p, :active?
+end
diff --git a/spec/ruby/library/net-http/http/address_spec.rb b/spec/ruby/library/net-http/http/address_spec.rb
new file mode 100644
index 0000000000..7c5b82a8f9
--- /dev/null
+++ b/spec/ruby/library/net-http/http/address_spec.rb
@@ -0,0 +1,9 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTP#address" do
+ it "returns the current host name" do
+ net = Net::HTTP.new("localhost")
+ net.address.should == "localhost"
+ end
+end
diff --git a/spec/ruby/library/net-http/http/close_on_empty_response_spec.rb b/spec/ruby/library/net-http/http/close_on_empty_response_spec.rb
new file mode 100644
index 0000000000..9cc756befb
--- /dev/null
+++ b/spec/ruby/library/net-http/http/close_on_empty_response_spec.rb
@@ -0,0 +1,10 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTP#close_on_empty_response" do
+ it "needs to be reviewed for spec completeness"
+end
+
+describe "Net::HTTP#close_on_empty_response=" do
+ it "needs to be reviewed for spec completeness"
+end
diff --git a/spec/ruby/library/net-http/http/copy_spec.rb b/spec/ruby/library/net-http/http/copy_spec.rb
new file mode 100644
index 0000000000..fba96c0f11
--- /dev/null
+++ b/spec/ruby/library/net-http/http/copy_spec.rb
@@ -0,0 +1,21 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+
+describe "Net::HTTP#copy" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
+ end
+
+ after :each do
+ @http.finish if @http.started?
+ NetHTTPSpecs.stop_server
+ end
+
+ it "sends a COPY request to the passed path and returns the response" do
+ response = @http.copy("/request")
+ response.should be_kind_of(Net::HTTPResponse)
+ response.body.should == "Request type: COPY"
+ end
+end
diff --git a/spec/ruby/library/net-http/http/default_port_spec.rb b/spec/ruby/library/net-http/http/default_port_spec.rb
new file mode 100644
index 0000000000..95b7316a0c
--- /dev/null
+++ b/spec/ruby/library/net-http/http/default_port_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTP.default_port" do
+ it "returns 80" do
+ Net::HTTP.http_default_port.should eql(80)
+ end
+end
diff --git a/spec/ruby/library/net-http/http/delete_spec.rb b/spec/ruby/library/net-http/http/delete_spec.rb
new file mode 100644
index 0000000000..d73aa5b375
--- /dev/null
+++ b/spec/ruby/library/net-http/http/delete_spec.rb
@@ -0,0 +1,21 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+
+describe "Net::HTTP#delete" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
+ end
+
+ after :each do
+ @http.finish if @http.started?
+ NetHTTPSpecs.stop_server
+ end
+
+ it "sends a DELETE request to the passed path and returns the response" do
+ response = @http.delete("/request")
+ response.should be_kind_of(Net::HTTPResponse)
+ response.body.should == "Request type: DELETE"
+ end
+end
diff --git a/spec/ruby/library/net-http/http/finish_spec.rb b/spec/ruby/library/net-http/http/finish_spec.rb
new file mode 100644
index 0000000000..d4aa00dffe
--- /dev/null
+++ b/spec/ruby/library/net-http/http/finish_spec.rb
@@ -0,0 +1,29 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+
+describe "Net::HTTP#finish" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @http = Net::HTTP.new("localhost", NetHTTPSpecs.port)
+ end
+
+ after :each do
+ @http.finish if @http.started?
+ NetHTTPSpecs.stop_server
+ end
+
+ describe "when self has been started" do
+ it "closes the tcp connection" do
+ @http.start
+ @http.finish
+ @http.started?.should be_false
+ end
+ end
+
+ describe "when self has not been started yet" do
+ it "raises an IOError" do
+ -> { @http.finish }.should raise_error(IOError)
+ end
+ end
+end
diff --git a/spec/ruby/library/net/http/http/fixtures/http_server.rb b/spec/ruby/library/net-http/http/fixtures/http_server.rb
index c1cedbfa76..c1cedbfa76 100644
--- a/spec/ruby/library/net/http/http/fixtures/http_server.rb
+++ b/spec/ruby/library/net-http/http/fixtures/http_server.rb
diff --git a/spec/ruby/library/net-http/http/get2_spec.rb b/spec/ruby/library/net-http/http/get2_spec.rb
new file mode 100644
index 0000000000..57c05ec64b
--- /dev/null
+++ b/spec/ruby/library/net-http/http/get2_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+require_relative 'shared/request_get'
+
+describe "Net::HTTP#get2" do
+ it_behaves_like :net_http_request_get, :get2
+end
diff --git a/spec/ruby/library/net-http/http/get_print_spec.rb b/spec/ruby/library/net-http/http/get_print_spec.rb
new file mode 100644
index 0000000000..3c24ce44ea
--- /dev/null
+++ b/spec/ruby/library/net-http/http/get_print_spec.rb
@@ -0,0 +1,30 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+
+describe "Net::HTTP.get_print" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @port = NetHTTPSpecs.port
+ end
+
+ after :each do
+ NetHTTPSpecs.stop_server
+ end
+
+ describe "when passed URI" do
+ it "it prints the body of the specified uri to $stdout" do
+ -> do
+ Net::HTTP.get_print URI.parse("http://localhost:#{@port}/")
+ end.should output(/This is the index page\./)
+ end
+ end
+
+ describe "when passed host, path, port" do
+ it "it prints the body of the specified uri to $stdout" do
+ -> do
+ Net::HTTP.get_print 'localhost', "/", @port
+ end.should output(/This is the index page\./)
+ end
+ end
+end
diff --git a/spec/ruby/library/net-http/http/get_response_spec.rb b/spec/ruby/library/net-http/http/get_response_spec.rb
new file mode 100644
index 0000000000..7133ef8101
--- /dev/null
+++ b/spec/ruby/library/net-http/http/get_response_spec.rb
@@ -0,0 +1,30 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+
+describe "Net::HTTP.get_response" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @port = NetHTTPSpecs.port
+ end
+
+ after :each do
+ NetHTTPSpecs.stop_server
+ end
+
+ describe "when passed URI" do
+ it "returns the response for the specified uri" do
+ res = Net::HTTP.get_response(URI.parse("http://localhost:#{@port}/"))
+ res.content_type.should == "text/plain"
+ res.body.should == "This is the index page."
+ end
+ end
+
+ describe "when passed host, path, port" do
+ it "returns the response for the specified host-path-combination" do
+ res = Net::HTTP.get_response('localhost', "/", @port)
+ res.content_type.should == "text/plain"
+ res.body.should == "This is the index page."
+ end
+ end
+end
diff --git a/spec/ruby/library/net-http/http/get_spec.rb b/spec/ruby/library/net-http/http/get_spec.rb
new file mode 100644
index 0000000000..e64a61c52c
--- /dev/null
+++ b/spec/ruby/library/net-http/http/get_spec.rb
@@ -0,0 +1,94 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+
+describe "Net::HTTP.get" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @port = NetHTTPSpecs.port
+ end
+
+ after :each do
+ NetHTTPSpecs.stop_server
+ end
+
+ describe "when passed URI" do
+ it "returns the body of the specified uri" do
+ Net::HTTP.get(URI.parse("http://localhost:#{@port}/")).should == "This is the index page."
+ end
+ end
+
+ describe "when passed host, path, port" do
+ it "returns the body of the specified host-path-combination" do
+ Net::HTTP.get('localhost', "/", @port).should == "This is the index page."
+ end
+ end
+end
+
+quarantine! do # These specs fail frequently with CHECK_LEAKS=true
+describe "Net::HTTP.get" do
+ describe "when reading gzipped contents" do
+ def start_threads
+ require 'zlib'
+ require 'stringio'
+
+ server = nil
+ server_thread = Thread.new do
+ server = TCPServer.new("127.0.0.1", 0)
+ begin
+ c = server.accept
+ ensure
+ server.close
+ end
+ c.print "HTTP/1.1 200\r\n"
+ c.print "Content-Type: text/plain\r\n"
+ c.print "Content-Encoding: gzip\r\n"
+ s = StringIO.new
+ z = Zlib::GzipWriter.new(s)
+ begin
+ z.write 'Hello World!'
+ ensure
+ z.close
+ end
+ c.print "Content-Length: #{s.length}\r\n\r\n"
+ # Write partial gzip content
+ c.write s.string.byteslice(0..-2)
+ c.flush
+ c
+ end
+ Thread.pass until server && server_thread.stop?
+
+ client_thread = Thread.new do
+ Thread.current.report_on_exception = false
+ Net::HTTP.get("127.0.0.1", '/', server.connect_address.ip_port)
+ end
+
+ socket = server_thread.value
+ Thread.pass until client_thread.stop?
+
+ [socket, client_thread]
+ end
+
+ it "propagates exceptions interrupting the thread and does not replace it with Zlib::BufError" do
+ my_exception = Class.new(RuntimeError)
+ socket, client_thread = start_threads
+ begin
+ client_thread.raise my_exception, "my exception"
+ -> { client_thread.value }.should raise_error(my_exception)
+ ensure
+ socket.close
+ end
+ end
+
+ it "lets the kill Thread exception goes through and does not replace it with Zlib::BufError" do
+ socket, client_thread = start_threads
+ begin
+ client_thread.kill
+ client_thread.value.should == nil
+ ensure
+ socket.close
+ end
+ end
+ end
+end
+end
diff --git a/spec/ruby/library/net-http/http/head2_spec.rb b/spec/ruby/library/net-http/http/head2_spec.rb
new file mode 100644
index 0000000000..84cfff33d7
--- /dev/null
+++ b/spec/ruby/library/net-http/http/head2_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+require_relative 'shared/request_head'
+
+describe "Net::HTTP#head2" do
+ it_behaves_like :net_http_request_head, :head2
+end
diff --git a/spec/ruby/library/net-http/http/head_spec.rb b/spec/ruby/library/net-http/http/head_spec.rb
new file mode 100644
index 0000000000..64621fa87b
--- /dev/null
+++ b/spec/ruby/library/net-http/http/head_spec.rb
@@ -0,0 +1,25 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+
+describe "Net::HTTP#head" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
+ end
+
+ after :each do
+ @http.finish if @http.started?
+ NetHTTPSpecs.stop_server
+ end
+
+ it "sends a HEAD request to the passed path and returns the response" do
+ response = @http.head("/request")
+ # HEAD requests have no responses
+ response.body.should be_nil
+ end
+
+ it "returns a Net::HTTPResponse" do
+ @http.head("/request").should be_kind_of(Net::HTTPResponse)
+ end
+end
diff --git a/spec/ruby/library/net-http/http/http_default_port_spec.rb b/spec/ruby/library/net-http/http/http_default_port_spec.rb
new file mode 100644
index 0000000000..3b17bcd0a5
--- /dev/null
+++ b/spec/ruby/library/net-http/http/http_default_port_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTP.http_default_port" do
+ it "returns 80" do
+ Net::HTTP.http_default_port.should eql(80)
+ end
+end
diff --git a/spec/ruby/library/net-http/http/https_default_port_spec.rb b/spec/ruby/library/net-http/http/https_default_port_spec.rb
new file mode 100644
index 0000000000..8c24e1d97c
--- /dev/null
+++ b/spec/ruby/library/net-http/http/https_default_port_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTP.https_default_port" do
+ it "returns 443" do
+ Net::HTTP.https_default_port.should eql(443)
+ end
+end
diff --git a/spec/ruby/library/net-http/http/initialize_spec.rb b/spec/ruby/library/net-http/http/initialize_spec.rb
new file mode 100644
index 0000000000..78aa01e1aa
--- /dev/null
+++ b/spec/ruby/library/net-http/http/initialize_spec.rb
@@ -0,0 +1,46 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTP#initialize" do
+ it "is private" do
+ Net::HTTP.should have_private_instance_method(:initialize)
+ end
+
+ describe "when passed address" do
+ before :each do
+ @net = Net::HTTP.allocate
+ @net.send(:initialize, "localhost")
+ end
+
+ it "sets the new Net::HTTP instance's address to the passed address" do
+ @net.address.should == "localhost"
+ end
+
+ it "sets the new Net::HTTP instance's port to the default HTTP port" do
+ @net.port.should eql(Net::HTTP.default_port)
+ end
+
+ it "does not start the new Net::HTTP instance" do
+ @net.started?.should be_false
+ end
+ end
+
+ describe "when passed address, port" do
+ before :each do
+ @net = Net::HTTP.allocate
+ @net.send(:initialize, "localhost", 3333)
+ end
+
+ it "sets the new Net::HTTP instance's address to the passed address" do
+ @net.address.should == "localhost"
+ end
+
+ it "sets the new Net::HTTP instance's port to the passed port" do
+ @net.port.should eql(3333)
+ end
+
+ it "does not start the new Net::HTTP instance" do
+ @net.started?.should be_false
+ end
+ end
+end
diff --git a/spec/ruby/library/net-http/http/inspect_spec.rb b/spec/ruby/library/net-http/http/inspect_spec.rb
new file mode 100644
index 0000000000..b8f650809e
--- /dev/null
+++ b/spec/ruby/library/net-http/http/inspect_spec.rb
@@ -0,0 +1,24 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+
+describe "Net::HTTP#inspect" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @port = NetHTTPSpecs.port
+ @http = Net::HTTP.new("localhost", @port)
+ end
+
+ after :each do
+ @http.finish if @http.started?
+ NetHTTPSpecs.stop_server
+ end
+
+ it "returns a String representation of self" do
+ @http.inspect.should be_kind_of(String)
+ @http.inspect.should == "#<Net::HTTP localhost:#{@port} open=false>"
+
+ @http.start
+ @http.inspect.should == "#<Net::HTTP localhost:#{@port} open=true>"
+ end
+end
diff --git a/spec/ruby/library/net-http/http/is_version_1_1_spec.rb b/spec/ruby/library/net-http/http/is_version_1_1_spec.rb
new file mode 100644
index 0000000000..bdb343f9e0
--- /dev/null
+++ b/spec/ruby/library/net-http/http/is_version_1_1_spec.rb
@@ -0,0 +1,7 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'shared/version_1_1'
+
+describe "Net::HTTP.is_version_1_1?" do
+ it_behaves_like :net_http_version_1_1_p, :is_version_1_1?
+end
diff --git a/spec/ruby/library/net-http/http/is_version_1_2_spec.rb b/spec/ruby/library/net-http/http/is_version_1_2_spec.rb
new file mode 100644
index 0000000000..555bb205dd
--- /dev/null
+++ b/spec/ruby/library/net-http/http/is_version_1_2_spec.rb
@@ -0,0 +1,7 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'shared/version_1_2'
+
+describe "Net::HTTP.is_version_1_2?" do
+ it_behaves_like :net_http_version_1_2_p, :is_version_1_2?
+end
diff --git a/spec/ruby/library/net-http/http/lock_spec.rb b/spec/ruby/library/net-http/http/lock_spec.rb
new file mode 100644
index 0000000000..aa1f944196
--- /dev/null
+++ b/spec/ruby/library/net-http/http/lock_spec.rb
@@ -0,0 +1,21 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+
+describe "Net::HTTP#lock" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
+ end
+
+ after :each do
+ @http.finish if @http.started?
+ NetHTTPSpecs.stop_server
+ end
+
+ it "sends a LOCK request to the passed path and returns the response" do
+ response = @http.lock("/request", "test=test")
+ response.should be_kind_of(Net::HTTPResponse)
+ response.body.should == "Request type: LOCK"
+ end
+end
diff --git a/spec/ruby/library/net-http/http/mkcol_spec.rb b/spec/ruby/library/net-http/http/mkcol_spec.rb
new file mode 100644
index 0000000000..f8009f9059
--- /dev/null
+++ b/spec/ruby/library/net-http/http/mkcol_spec.rb
@@ -0,0 +1,21 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+
+describe "Net::HTTP#mkcol" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
+ end
+
+ after :each do
+ @http.finish if @http.started?
+ NetHTTPSpecs.stop_server
+ end
+
+ it "sends a MKCOL request to the passed path and returns the response" do
+ response = @http.mkcol("/request")
+ response.should be_kind_of(Net::HTTPResponse)
+ response.body.should == "Request type: MKCOL"
+ end
+end
diff --git a/spec/ruby/library/net-http/http/move_spec.rb b/spec/ruby/library/net-http/http/move_spec.rb
new file mode 100644
index 0000000000..ae43016a2c
--- /dev/null
+++ b/spec/ruby/library/net-http/http/move_spec.rb
@@ -0,0 +1,25 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+
+describe "Net::HTTP#head" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
+ end
+
+ after :each do
+ @http.finish if @http.started?
+ NetHTTPSpecs.stop_server
+ end
+
+ it "sends a MOVE request to the passed path and returns the response" do
+ response = @http.move("/request")
+ # HEAD requests have no responses
+ response.body.should == "Request type: MOVE"
+ end
+
+ it "returns a Net::HTTPResponse" do
+ @http.move("/request").should be_kind_of(Net::HTTPResponse)
+ end
+end
diff --git a/spec/ruby/library/net-http/http/new_spec.rb b/spec/ruby/library/net-http/http/new_spec.rb
new file mode 100644
index 0000000000..1ec6bbd0c0
--- /dev/null
+++ b/spec/ruby/library/net-http/http/new_spec.rb
@@ -0,0 +1,86 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTP.new" do
+ describe "when passed address" do
+ before :each do
+ @http = Net::HTTP.new("localhost")
+ end
+
+ it "returns a Net::HTTP instance" do
+ @http.proxy?.should be_false
+ @http.instance_of?(Net::HTTP).should be_true
+ end
+
+ it "sets the new Net::HTTP instance's address to the passed address" do
+ @http.address.should == "localhost"
+ end
+
+ it "sets the new Net::HTTP instance's port to the default HTTP port" do
+ @http.port.should eql(Net::HTTP.default_port)
+ end
+
+ it "does not start the new Net::HTTP instance" do
+ @http.started?.should be_false
+ end
+ end
+
+ describe "when passed address, port" do
+ before :each do
+ @http = Net::HTTP.new("localhost", 3333)
+ end
+
+ it "returns a Net::HTTP instance" do
+ @http.proxy?.should be_false
+ @http.instance_of?(Net::HTTP).should be_true
+ end
+
+ it "sets the new Net::HTTP instance's address to the passed address" do
+ @http.address.should == "localhost"
+ end
+
+ it "sets the new Net::HTTP instance's port to the passed port" do
+ @http.port.should eql(3333)
+ end
+
+ it "does not start the new Net::HTTP instance" do
+ @http.started?.should be_false
+ end
+ end
+
+ describe "when passed address, port, *proxy_options" do
+ it "returns a Net::HTTP instance" do
+ http = Net::HTTP.new("localhost", 3333, "localhost")
+ http.proxy?.should be_true
+ http.instance_of?(Net::HTTP).should be_true
+ http.should be_kind_of(Net::HTTP)
+ end
+
+ it "correctly sets the passed Proxy options" do
+ http = Net::HTTP.new("localhost", 3333, "localhost")
+ http.proxy_address.should == "localhost"
+ http.proxy_port.should eql(80)
+ http.proxy_user.should be_nil
+ http.proxy_pass.should be_nil
+
+ http = Net::HTTP.new("localhost", 3333, "localhost", 1234)
+ http.proxy_address.should == "localhost"
+ http.proxy_port.should eql(1234)
+ http.proxy_user.should be_nil
+ http.proxy_pass.should be_nil
+
+ http = Net::HTTP.new("localhost", 3333, "localhost", 1234, "rubyspec")
+ http.proxy_address.should == "localhost"
+ http.proxy_port.should eql(1234)
+ http.proxy_user.should == "rubyspec"
+ http.proxy_pass.should be_nil
+
+ http = Net::HTTP.new("localhost", 3333, "localhost", 1234, "rubyspec", "rocks")
+ http.proxy_address.should == "localhost"
+ http.proxy_port.should eql(1234)
+ http.proxy_user.should == "rubyspec"
+ http.proxy_pass.should == "rocks"
+ end
+ end
+
+end
diff --git a/spec/ruby/library/net-http/http/newobj_spec.rb b/spec/ruby/library/net-http/http/newobj_spec.rb
new file mode 100644
index 0000000000..e19b30fca9
--- /dev/null
+++ b/spec/ruby/library/net-http/http/newobj_spec.rb
@@ -0,0 +1,48 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTP.newobj" do
+ before :each do
+ @net = Net::HTTP.newobj("localhost")
+ end
+
+ describe "when passed address" do
+ it "returns a new Net::HTTP instance" do
+ @net.should be_kind_of(Net::HTTP)
+ end
+
+ it "sets the new Net::HTTP instance's address to the passed address" do
+ @net.address.should == "localhost"
+ end
+
+ it "sets the new Net::HTTP instance's port to the default HTTP port" do
+ @net.port.should eql(Net::HTTP.default_port)
+ end
+
+ it "does not start the new Net::HTTP instance" do
+ @net.started?.should be_false
+ end
+ end
+
+ describe "when passed address, port" do
+ before :each do
+ @net = Net::HTTP.newobj("localhost", 3333)
+ end
+
+ it "returns a new Net::HTTP instance" do
+ @net.should be_kind_of(Net::HTTP)
+ end
+
+ it "sets the new Net::HTTP instance's address to the passed address" do
+ @net.address.should == "localhost"
+ end
+
+ it "sets the new Net::HTTP instance's port to the passed port" do
+ @net.port.should eql(3333)
+ end
+
+ it "does not start the new Net::HTTP instance" do
+ @net.started?.should be_false
+ end
+ end
+end
diff --git a/spec/ruby/library/net-http/http/open_timeout_spec.rb b/spec/ruby/library/net-http/http/open_timeout_spec.rb
new file mode 100644
index 0000000000..0d93752271
--- /dev/null
+++ b/spec/ruby/library/net-http/http/open_timeout_spec.rb
@@ -0,0 +1,24 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTP#open_timeout" do
+ it "returns the seconds to wait till the connection is open" do
+ net = Net::HTTP.new("localhost")
+ net.open_timeout.should eql(60)
+ net.open_timeout = 10
+ net.open_timeout.should eql(10)
+ end
+end
+
+describe "Net::HTTP#open_timeout=" do
+ it "sets the seconds to wait till the connection is open" do
+ net = Net::HTTP.new("localhost")
+ net.open_timeout = 10
+ net.open_timeout.should eql(10)
+ end
+
+ it "returns the newly set value" do
+ net = Net::HTTP.new("localhost")
+ (net.open_timeout = 10).should eql(10)
+ end
+end
diff --git a/spec/ruby/library/net-http/http/options_spec.rb b/spec/ruby/library/net-http/http/options_spec.rb
new file mode 100644
index 0000000000..3d9887a557
--- /dev/null
+++ b/spec/ruby/library/net-http/http/options_spec.rb
@@ -0,0 +1,25 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+
+describe "Net::HTTP#options" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
+ end
+
+ after :each do
+ @http.finish if @http.started?
+ NetHTTPSpecs.stop_server
+ end
+
+ it "sends an options request to the passed path and returns the response" do
+ response = @http.options("/request")
+
+ response.body.should == "Request type: OPTIONS"
+ end
+
+ it "returns a Net::HTTPResponse" do
+ @http.options("/request").should be_kind_of(Net::HTTPResponse)
+ end
+end
diff --git a/spec/ruby/library/net-http/http/port_spec.rb b/spec/ruby/library/net-http/http/port_spec.rb
new file mode 100644
index 0000000000..0984d5e6ce
--- /dev/null
+++ b/spec/ruby/library/net-http/http/port_spec.rb
@@ -0,0 +1,9 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTP#port" do
+ it "returns the current port number" do
+ net = Net::HTTP.new("localhost", 3333)
+ net.port.should eql(3333)
+ end
+end
diff --git a/spec/ruby/library/net-http/http/post2_spec.rb b/spec/ruby/library/net-http/http/post2_spec.rb
new file mode 100644
index 0000000000..abc998709f
--- /dev/null
+++ b/spec/ruby/library/net-http/http/post2_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+require_relative 'shared/request_post'
+
+describe "Net::HTTP#post2" do
+ it_behaves_like :net_http_request_post, :post2
+end
diff --git a/spec/ruby/library/net-http/http/post_form_spec.rb b/spec/ruby/library/net-http/http/post_form_spec.rb
new file mode 100644
index 0000000000..de64a25bae
--- /dev/null
+++ b/spec/ruby/library/net-http/http/post_form_spec.rb
@@ -0,0 +1,22 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+
+describe "Net::HTTP.post_form when passed URI" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @port = NetHTTPSpecs.port
+ end
+
+ after :each do
+ NetHTTPSpecs.stop_server
+ end
+
+ it "POSTs the passed form data to the given uri" do
+ uri = URI.parse("http://localhost:#{@port}/request/body")
+ data = { test: :data }
+
+ res = Net::HTTP.post_form(uri, data)
+ res.body.should == "test=data"
+ end
+end
diff --git a/spec/ruby/library/net-http/http/post_spec.rb b/spec/ruby/library/net-http/http/post_spec.rb
new file mode 100644
index 0000000000..d7d94fec4a
--- /dev/null
+++ b/spec/ruby/library/net-http/http/post_spec.rb
@@ -0,0 +1,74 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require 'uri'
+require_relative 'fixtures/http_server'
+
+describe "Net::HTTP.post" do
+ before :each do
+ NetHTTPSpecs.start_server
+ end
+
+ after :each do
+ NetHTTPSpecs.stop_server
+ end
+
+ it "sends post request to the specified URI and returns response" do
+ response = Net::HTTP.post(
+ URI("http://localhost:#{NetHTTPSpecs.port}/request"),
+ '{ "q": "ruby", "max": "50" }',
+ "Content-Type" => "application/json")
+ response.body.should == "Request type: POST"
+ end
+
+ it "returns a Net::HTTPResponse" do
+ response = Net::HTTP.post(URI("http://localhost:#{NetHTTPSpecs.port}/request"), "test=test")
+ response.should be_kind_of(Net::HTTPResponse)
+ end
+
+ it "sends Content-Type: application/x-www-form-urlencoded by default" do
+ response = Net::HTTP.post(URI("http://localhost:#{NetHTTPSpecs.port}/request/header"), "test=test")
+ response.body.should include('"Content-Type"=>"application/x-www-form-urlencoded"')
+ end
+
+ it "does not support HTTP Basic Auth" do
+ response = Net::HTTP.post(
+ URI("http://john:qwerty@localhost:#{NetHTTPSpecs.port}/request/basic_auth"),
+ "test=test")
+ response.body.should == "username: \npassword: "
+ end
+end
+
+describe "Net::HTTP#post" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
+ end
+
+ after :each do
+ @http.finish if @http.started?
+ NetHTTPSpecs.stop_server
+ end
+
+ it "sends an post request to the passed path and returns the response" do
+ response = @http.post("/request", "test=test")
+ response.body.should == "Request type: POST"
+ end
+
+ it "returns a Net::HTTPResponse" do
+ @http.post("/request", "test=test").should be_kind_of(Net::HTTPResponse)
+ end
+
+ describe "when passed a block" do
+ it "yields fragments of the response body to the passed block" do
+ str = +""
+ @http.post("/request", "test=test") do |res|
+ str << res
+ end
+ str.should == "Request type: POST"
+ end
+
+ it "returns a Net::HTTPResponse" do
+ @http.post("/request", "test=test") {}.should be_kind_of(Net::HTTPResponse)
+ end
+ end
+end
diff --git a/spec/ruby/library/net-http/http/propfind_spec.rb b/spec/ruby/library/net-http/http/propfind_spec.rb
new file mode 100644
index 0000000000..f3742d1b1a
--- /dev/null
+++ b/spec/ruby/library/net-http/http/propfind_spec.rb
@@ -0,0 +1,24 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+
+describe "Net::HTTP#propfind" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
+ end
+
+ after :each do
+ @http.finish if @http.started?
+ NetHTTPSpecs.stop_server
+ end
+
+ it "sends an propfind request to the passed path and returns the response" do
+ response = @http.propfind("/request", "test=test")
+ response.body.should == "Request type: PROPFIND"
+ end
+
+ it "returns a Net::HTTPResponse" do
+ @http.propfind("/request", "test=test").should be_kind_of(Net::HTTPResponse)
+ end
+end
diff --git a/spec/ruby/library/net-http/http/proppatch_spec.rb b/spec/ruby/library/net-http/http/proppatch_spec.rb
new file mode 100644
index 0000000000..0163d24d46
--- /dev/null
+++ b/spec/ruby/library/net-http/http/proppatch_spec.rb
@@ -0,0 +1,24 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+
+describe "Net::HTTP#proppatch" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
+ end
+
+ after :each do
+ @http.finish if @http.started?
+ NetHTTPSpecs.stop_server
+ end
+
+ it "sends an proppatch request to the passed path and returns the response" do
+ response = @http.proppatch("/request", "test=test")
+ response.body.should == "Request type: PROPPATCH"
+ end
+
+ it "returns a Net::HTTPResponse" do
+ @http.proppatch("/request", "test=test").should be_kind_of(Net::HTTPResponse)
+ end
+end
diff --git a/spec/ruby/library/net-http/http/proxy_address_spec.rb b/spec/ruby/library/net-http/http/proxy_address_spec.rb
new file mode 100644
index 0000000000..5b5efb7ac0
--- /dev/null
+++ b/spec/ruby/library/net-http/http/proxy_address_spec.rb
@@ -0,0 +1,31 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTP.proxy_address" do
+ describe "when self is no proxy class" do
+ it "returns nil" do
+ Net::HTTP.proxy_address.should be_nil
+ end
+ end
+
+ describe "when self is a proxy class" do
+ it "returns the address for self's proxy connection" do
+ Net::HTTP.Proxy("localhost", 1234, "rspec", "rocks").proxy_address.should == "localhost"
+ end
+ end
+end
+
+describe "Net::HTTP#proxy_address" do
+ describe "when self is no proxy class instance" do
+ it "returns nil" do
+ Net::HTTP.new("localhost", 3333).proxy_address.should be_nil
+ end
+ end
+
+ describe "when self is a proxy class instance" do
+ it "returns the password for self's proxy connection" do
+ http_with_proxy = Net::HTTP.Proxy("localhost", 1234, "rspec", "rocks")
+ http_with_proxy.new("localhost", 3333).proxy_address.should == "localhost"
+ end
+ end
+end
diff --git a/spec/ruby/library/net-http/http/proxy_class_spec.rb b/spec/ruby/library/net-http/http/proxy_class_spec.rb
new file mode 100644
index 0000000000..00975aef4e
--- /dev/null
+++ b/spec/ruby/library/net-http/http/proxy_class_spec.rb
@@ -0,0 +1,9 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTP.proxy_class?" do
+ it "returns true if self is a class created with Net::HTTP.Proxy" do
+ Net::HTTP.proxy_class?.should be_false
+ Net::HTTP.Proxy("localhost").proxy_class?.should be_true
+ end
+end
diff --git a/spec/ruby/library/net-http/http/proxy_pass_spec.rb b/spec/ruby/library/net-http/http/proxy_pass_spec.rb
new file mode 100644
index 0000000000..4e393a53ff
--- /dev/null
+++ b/spec/ruby/library/net-http/http/proxy_pass_spec.rb
@@ -0,0 +1,39 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTP.proxy_pass" do
+ describe "when self is no proxy class" do
+ it "returns nil" do
+ Net::HTTP.proxy_pass.should be_nil
+ end
+ end
+
+ describe "when self is a proxy class" do
+ it "returns nil if no password was set for self's proxy connection" do
+ Net::HTTP.Proxy("localhost").proxy_pass.should be_nil
+ end
+
+ it "returns the password for self's proxy connection" do
+ Net::HTTP.Proxy("localhost", 1234, "rspec", "rocks").proxy_pass.should == "rocks"
+ end
+ end
+end
+
+describe "Net::HTTP#proxy_pass" do
+ describe "when self is no proxy class instance" do
+ it "returns nil" do
+ Net::HTTP.new("localhost", 3333).proxy_pass.should be_nil
+ end
+ end
+
+ describe "when self is a proxy class instance" do
+ it "returns nil if no password was set for self's proxy connection" do
+ Net::HTTP.Proxy("localhost").new("localhost", 3333).proxy_pass.should be_nil
+ end
+
+ it "returns the password for self's proxy connection" do
+ http_with_proxy = Net::HTTP.Proxy("localhost", 1234, "rspec", "rocks")
+ http_with_proxy.new("localhost", 3333).proxy_pass.should == "rocks"
+ end
+ end
+end
diff --git a/spec/ruby/library/net-http/http/proxy_port_spec.rb b/spec/ruby/library/net-http/http/proxy_port_spec.rb
new file mode 100644
index 0000000000..d7d37f3927
--- /dev/null
+++ b/spec/ruby/library/net-http/http/proxy_port_spec.rb
@@ -0,0 +1,39 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTP.proxy_port" do
+ describe "when self is no proxy class" do
+ it "returns nil" do
+ Net::HTTP.proxy_port.should be_nil
+ end
+ end
+
+ describe "when self is a proxy class" do
+ it "returns 80 if no port was set for self's proxy connection" do
+ Net::HTTP.Proxy("localhost").proxy_port.should eql(80)
+ end
+
+ it "returns the port for self's proxy connection" do
+ Net::HTTP.Proxy("localhost", 1234, "rspec", "rocks").proxy_port.should eql(1234)
+ end
+ end
+end
+
+describe "Net::HTTP#proxy_port" do
+ describe "when self is no proxy class instance" do
+ it "returns nil" do
+ Net::HTTP.new("localhost", 3333).proxy_port.should be_nil
+ end
+ end
+
+ describe "when self is a proxy class instance" do
+ it "returns 80 if no port was set for self's proxy connection" do
+ Net::HTTP.Proxy("localhost").new("localhost", 3333).proxy_port.should eql(80)
+ end
+
+ it "returns the port for self's proxy connection" do
+ http_with_proxy = Net::HTTP.Proxy("localhost", 1234, "rspec", "rocks")
+ http_with_proxy.new("localhost", 3333).proxy_port.should eql(1234)
+ end
+ end
+end
diff --git a/spec/ruby/library/net-http/http/proxy_user_spec.rb b/spec/ruby/library/net-http/http/proxy_user_spec.rb
new file mode 100644
index 0000000000..ef7654425d
--- /dev/null
+++ b/spec/ruby/library/net-http/http/proxy_user_spec.rb
@@ -0,0 +1,39 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTP.proxy_user" do
+ describe "when self is no proxy class" do
+ it "returns nil" do
+ Net::HTTP.proxy_user.should be_nil
+ end
+ end
+
+ describe "when self is a proxy class" do
+ it "returns nil if no username was set for self's proxy connection" do
+ Net::HTTP.Proxy("localhost").proxy_user.should be_nil
+ end
+
+ it "returns the username for self's proxy connection" do
+ Net::HTTP.Proxy("localhost", 1234, "rspec", "rocks").proxy_user.should == "rspec"
+ end
+ end
+end
+
+describe "Net::HTTP#proxy_user" do
+ describe "when self is no proxy class instance" do
+ it "returns nil" do
+ Net::HTTP.new("localhost", 3333).proxy_user.should be_nil
+ end
+ end
+
+ describe "when self is a proxy class instance" do
+ it "returns nil if no username was set for self's proxy connection" do
+ Net::HTTP.Proxy("localhost").new("localhost", 3333).proxy_user.should be_nil
+ end
+
+ it "returns the username for self's proxy connection" do
+ http_with_proxy = Net::HTTP.Proxy("localhost", 1234, "rspec", "rocks")
+ http_with_proxy.new("localhost", 3333).proxy_user.should == "rspec"
+ end
+ end
+end
diff --git a/spec/ruby/library/net-http/http/put2_spec.rb b/spec/ruby/library/net-http/http/put2_spec.rb
new file mode 100644
index 0000000000..7b03a39d0b
--- /dev/null
+++ b/spec/ruby/library/net-http/http/put2_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+require_relative 'shared/request_put'
+
+describe "Net::HTTP#put2" do
+ it_behaves_like :net_http_request_put, :put2
+end
diff --git a/spec/ruby/library/net-http/http/put_spec.rb b/spec/ruby/library/net-http/http/put_spec.rb
new file mode 100644
index 0000000000..75f3c243d4
--- /dev/null
+++ b/spec/ruby/library/net-http/http/put_spec.rb
@@ -0,0 +1,24 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+
+describe "Net::HTTP#put" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
+ end
+
+ after :each do
+ @http.finish if @http.started?
+ NetHTTPSpecs.stop_server
+ end
+
+ it "sends an put request to the passed path and returns the response" do
+ response = @http.put("/request", "test=test")
+ response.body.should == "Request type: PUT"
+ end
+
+ it "returns a Net::HTTPResponse" do
+ @http.put("/request", "test=test").should be_kind_of(Net::HTTPResponse)
+ end
+end
diff --git a/spec/ruby/library/net-http/http/read_timeout_spec.rb b/spec/ruby/library/net-http/http/read_timeout_spec.rb
new file mode 100644
index 0000000000..7a0d2f1d72
--- /dev/null
+++ b/spec/ruby/library/net-http/http/read_timeout_spec.rb
@@ -0,0 +1,24 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTP#read_timeout" do
+ it "returns the seconds to wait until reading one block" do
+ net = Net::HTTP.new("localhost")
+ net.read_timeout.should eql(60)
+ net.read_timeout = 10
+ net.read_timeout.should eql(10)
+ end
+end
+
+describe "Net::HTTP#read_timeout=" do
+ it "sets the seconds to wait till the connection is open" do
+ net = Net::HTTP.new("localhost")
+ net.read_timeout = 10
+ net.read_timeout.should eql(10)
+ end
+
+ it "returns the newly set value" do
+ net = Net::HTTP.new("localhost")
+ (net.read_timeout = 10).should eql(10)
+ end
+end
diff --git a/spec/ruby/library/net-http/http/request_get_spec.rb b/spec/ruby/library/net-http/http/request_get_spec.rb
new file mode 100644
index 0000000000..98025a14a1
--- /dev/null
+++ b/spec/ruby/library/net-http/http/request_get_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+require_relative 'shared/request_get'
+
+describe "Net::HTTP#request_get" do
+ it_behaves_like :net_http_request_get, :get2
+end
diff --git a/spec/ruby/library/net-http/http/request_head_spec.rb b/spec/ruby/library/net-http/http/request_head_spec.rb
new file mode 100644
index 0000000000..8f514d4eee
--- /dev/null
+++ b/spec/ruby/library/net-http/http/request_head_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+require_relative 'shared/request_head'
+
+describe "Net::HTTP#request_head" do
+ it_behaves_like :net_http_request_head, :request_head
+end
diff --git a/spec/ruby/library/net-http/http/request_post_spec.rb b/spec/ruby/library/net-http/http/request_post_spec.rb
new file mode 100644
index 0000000000..719bd5a7ee
--- /dev/null
+++ b/spec/ruby/library/net-http/http/request_post_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+require_relative 'shared/request_post'
+
+describe "Net::HTTP#request_post" do
+ it_behaves_like :net_http_request_post, :request_post
+end
diff --git a/spec/ruby/library/net-http/http/request_put_spec.rb b/spec/ruby/library/net-http/http/request_put_spec.rb
new file mode 100644
index 0000000000..9fcf3a98d6
--- /dev/null
+++ b/spec/ruby/library/net-http/http/request_put_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+require_relative 'shared/request_put'
+
+describe "Net::HTTP#request_put" do
+ it_behaves_like :net_http_request_put, :request_put
+end
diff --git a/spec/ruby/library/net-http/http/request_spec.rb b/spec/ruby/library/net-http/http/request_spec.rb
new file mode 100644
index 0000000000..356e605b3b
--- /dev/null
+++ b/spec/ruby/library/net-http/http/request_spec.rb
@@ -0,0 +1,109 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+
+describe "Net::HTTP#request" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
+ end
+
+ after :each do
+ @http.finish if @http.started?
+ NetHTTPSpecs.stop_server
+ end
+
+ describe "when passed request_object" do
+ it "makes a HTTP Request based on the passed request_object" do
+ response = @http.request(Net::HTTP::Get.new("/request"), "test=test")
+ response.body.should == "Request type: GET"
+
+ response = @http.request(Net::HTTP::Head.new("/request"), "test=test")
+ response.body.should be_nil
+
+ response = @http.request(Net::HTTP::Post.new("/request"), "test=test")
+ response.body.should == "Request type: POST"
+
+ response = @http.request(Net::HTTP::Put.new("/request"), "test=test")
+ response.body.should == "Request type: PUT"
+
+ response = @http.request(Net::HTTP::Proppatch.new("/request"), "test=test")
+ response.body.should == "Request type: PROPPATCH"
+
+ response = @http.request(Net::HTTP::Lock.new("/request"), "test=test")
+ response.body.should == "Request type: LOCK"
+
+ response = @http.request(Net::HTTP::Unlock.new("/request"), "test=test")
+ response.body.should == "Request type: UNLOCK"
+
+ # TODO: Does not work?
+ #response = @http.request(Net::HTTP::Options.new("/request"), "test=test")
+ #response.body.should be_nil
+
+ response = @http.request(Net::HTTP::Propfind.new("/request"), "test=test")
+ response.body.should == "Request type: PROPFIND"
+
+ response = @http.request(Net::HTTP::Delete.new("/request"), "test=test")
+ response.body.should == "Request type: DELETE"
+
+ response = @http.request(Net::HTTP::Move.new("/request"), "test=test")
+ response.body.should == "Request type: MOVE"
+
+ response = @http.request(Net::HTTP::Copy.new("/request"), "test=test")
+ response.body.should == "Request type: COPY"
+
+ response = @http.request(Net::HTTP::Mkcol.new("/request"), "test=test")
+ response.body.should == "Request type: MKCOL"
+
+ response = @http.request(Net::HTTP::Trace.new("/request"), "test=test")
+ response.body.should == "Request type: TRACE"
+ end
+ end
+
+ describe "when passed request_object and request_body" do
+ it "sends the passed request_body when making the HTTP Request" do
+ response = @http.request(Net::HTTP::Get.new("/request/body"), "test=test")
+ response.body.should == "test=test"
+
+ response = @http.request(Net::HTTP::Head.new("/request/body"), "test=test")
+ response.body.should be_nil
+
+ response = @http.request(Net::HTTP::Post.new("/request/body"), "test=test")
+ response.body.should == "test=test"
+
+ response = @http.request(Net::HTTP::Put.new("/request/body"), "test=test")
+ response.body.should == "test=test"
+
+ response = @http.request(Net::HTTP::Proppatch.new("/request/body"), "test=test")
+ response.body.should == "test=test"
+
+ response = @http.request(Net::HTTP::Lock.new("/request/body"), "test=test")
+ response.body.should == "test=test"
+
+ response = @http.request(Net::HTTP::Unlock.new("/request/body"), "test=test")
+ response.body.should == "test=test"
+
+ # TODO: Does not work?
+ #response = @http.request(Net::HTTP::Options.new("/request/body"), "test=test")
+ #response.body.should be_nil
+
+ response = @http.request(Net::HTTP::Propfind.new("/request/body"), "test=test")
+ response.body.should == "test=test"
+
+ response = @http.request(Net::HTTP::Delete.new("/request/body"), "test=test")
+ response.body.should == "test=test"
+
+ response = @http.request(Net::HTTP::Move.new("/request/body"), "test=test")
+ response.body.should == "test=test"
+
+ response = @http.request(Net::HTTP::Copy.new("/request/body"), "test=test")
+ response.body.should == "test=test"
+
+ response = @http.request(Net::HTTP::Mkcol.new("/request/body"), "test=test")
+ response.body.should == "test=test"
+
+ response = @http.request(Net::HTTP::Trace.new("/request/body"), "test=test")
+ response.body.should == "test=test"
+ end
+ end
+end
diff --git a/spec/ruby/library/net-http/http/request_types_spec.rb b/spec/ruby/library/net-http/http/request_types_spec.rb
new file mode 100644
index 0000000000..53aef1ee58
--- /dev/null
+++ b/spec/ruby/library/net-http/http/request_types_spec.rb
@@ -0,0 +1,254 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTP::Get" do
+ it "is a subclass of Net::HTTPRequest" do
+ Net::HTTP::Get.should < Net::HTTPRequest
+ end
+
+ it "represents the 'GET'-Request-Method" do
+ Net::HTTP::Get::METHOD.should == "GET"
+ end
+
+ it "has no Request Body" do
+ Net::HTTP::Get::REQUEST_HAS_BODY.should be_false
+ end
+
+ it "has a Response Body" do
+ Net::HTTP::Get::RESPONSE_HAS_BODY.should be_true
+ end
+end
+
+describe "Net::HTTP::Head" do
+ it "is a subclass of Net::HTTPRequest" do
+ Net::HTTP::Head.should < Net::HTTPRequest
+ end
+
+ it "represents the 'HEAD'-Request-Method" do
+ Net::HTTP::Head::METHOD.should == "HEAD"
+ end
+
+ it "has no Request Body" do
+ Net::HTTP::Head::REQUEST_HAS_BODY.should be_false
+ end
+
+ it "has no Response Body" do
+ Net::HTTP::Head::RESPONSE_HAS_BODY.should be_false
+ end
+end
+
+describe "Net::HTTP::Post" do
+ it "is a subclass of Net::HTTPRequest" do
+ Net::HTTP::Post.should < Net::HTTPRequest
+ end
+
+ it "represents the 'POST'-Request-Method" do
+ Net::HTTP::Post::METHOD.should == "POST"
+ end
+
+ it "has a Request Body" do
+ Net::HTTP::Post::REQUEST_HAS_BODY.should be_true
+ end
+
+ it "has a Response Body" do
+ Net::HTTP::Post::RESPONSE_HAS_BODY.should be_true
+ end
+end
+
+describe "Net::HTTP::Put" do
+ it "is a subclass of Net::HTTPRequest" do
+ Net::HTTP::Put.should < Net::HTTPRequest
+ end
+
+ it "represents the 'PUT'-Request-Method" do
+ Net::HTTP::Put::METHOD.should == "PUT"
+ end
+
+ it "has a Request Body" do
+ Net::HTTP::Put::REQUEST_HAS_BODY.should be_true
+ end
+
+ it "has a Response Body" do
+ Net::HTTP::Put::RESPONSE_HAS_BODY.should be_true
+ end
+end
+
+describe "Net::HTTP::Delete" do
+ it "is a subclass of Net::HTTPRequest" do
+ Net::HTTP::Delete.should < Net::HTTPRequest
+ end
+
+ it "represents the 'DELETE'-Request-Method" do
+ Net::HTTP::Delete::METHOD.should == "DELETE"
+ end
+
+ it "has no Request Body" do
+ Net::HTTP::Delete::REQUEST_HAS_BODY.should be_false
+ end
+
+ it "has a Response Body" do
+ Net::HTTP::Delete::RESPONSE_HAS_BODY.should be_true
+ end
+end
+
+describe "Net::HTTP::Options" do
+ it "is a subclass of Net::HTTPRequest" do
+ Net::HTTP::Options.should < Net::HTTPRequest
+ end
+
+ it "represents the 'OPTIONS'-Request-Method" do
+ Net::HTTP::Options::METHOD.should == "OPTIONS"
+ end
+
+ it "has no Request Body" do
+ Net::HTTP::Options::REQUEST_HAS_BODY.should be_false
+ end
+
+ it "has no Response Body" do
+ Net::HTTP::Options::RESPONSE_HAS_BODY.should be_true
+ end
+end
+
+describe "Net::HTTP::Trace" do
+ it "is a subclass of Net::HTTPRequest" do
+ Net::HTTP::Trace.should < Net::HTTPRequest
+ end
+
+ it "represents the 'TRACE'-Request-Method" do
+ Net::HTTP::Trace::METHOD.should == "TRACE"
+ end
+
+ it "has no Request Body" do
+ Net::HTTP::Trace::REQUEST_HAS_BODY.should be_false
+ end
+
+ it "has a Response Body" do
+ Net::HTTP::Trace::RESPONSE_HAS_BODY.should be_true
+ end
+end
+
+describe "Net::HTTP::Propfind" do
+ it "is a subclass of Net::HTTPRequest" do
+ Net::HTTP::Propfind.should < Net::HTTPRequest
+ end
+
+ it "represents the 'PROPFIND'-Request-Method" do
+ Net::HTTP::Propfind::METHOD.should == "PROPFIND"
+ end
+
+ it "has a Request Body" do
+ Net::HTTP::Propfind::REQUEST_HAS_BODY.should be_true
+ end
+
+ it "has a Response Body" do
+ Net::HTTP::Propfind::RESPONSE_HAS_BODY.should be_true
+ end
+end
+
+describe "Net::HTTP::Proppatch" do
+ it "is a subclass of Net::HTTPRequest" do
+ Net::HTTP::Proppatch.should < Net::HTTPRequest
+ end
+
+ it "represents the 'PROPPATCH'-Request-Method" do
+ Net::HTTP::Proppatch::METHOD.should == "PROPPATCH"
+ end
+
+ it "has a Request Body" do
+ Net::HTTP::Proppatch::REQUEST_HAS_BODY.should be_true
+ end
+
+ it "has a Response Body" do
+ Net::HTTP::Proppatch::RESPONSE_HAS_BODY.should be_true
+ end
+end
+
+describe "Net::HTTP::Mkcol" do
+ it "is a subclass of Net::HTTPRequest" do
+ Net::HTTP::Mkcol.should < Net::HTTPRequest
+ end
+
+ it "represents the 'MKCOL'-Request-Method" do
+ Net::HTTP::Mkcol::METHOD.should == "MKCOL"
+ end
+
+ it "has a Request Body" do
+ Net::HTTP::Mkcol::REQUEST_HAS_BODY.should be_true
+ end
+
+ it "has a Response Body" do
+ Net::HTTP::Mkcol::RESPONSE_HAS_BODY.should be_true
+ end
+end
+
+describe "Net::HTTP::Copy" do
+ it "is a subclass of Net::HTTPRequest" do
+ Net::HTTP::Copy.should < Net::HTTPRequest
+ end
+
+ it "represents the 'COPY'-Request-Method" do
+ Net::HTTP::Copy::METHOD.should == "COPY"
+ end
+
+ it "has no Request Body" do
+ Net::HTTP::Copy::REQUEST_HAS_BODY.should be_false
+ end
+
+ it "has a Response Body" do
+ Net::HTTP::Copy::RESPONSE_HAS_BODY.should be_true
+ end
+end
+
+describe "Net::HTTP::Move" do
+ it "is a subclass of Net::HTTPRequest" do
+ Net::HTTP::Move.should < Net::HTTPRequest
+ end
+
+ it "represents the 'MOVE'-Request-Method" do
+ Net::HTTP::Move::METHOD.should == "MOVE"
+ end
+
+ it "has no Request Body" do
+ Net::HTTP::Move::REQUEST_HAS_BODY.should be_false
+ end
+
+ it "has a Response Body" do
+ Net::HTTP::Move::RESPONSE_HAS_BODY.should be_true
+ end
+end
+
+describe "Net::HTTP::Lock" do
+ it "is a subclass of Net::HTTPRequest" do
+ Net::HTTP::Lock.should < Net::HTTPRequest
+ end
+
+ it "represents the 'LOCK'-Request-Method" do
+ Net::HTTP::Lock::METHOD.should == "LOCK"
+ end
+
+ it "has a Request Body" do
+ Net::HTTP::Lock::REQUEST_HAS_BODY.should be_true
+ end
+
+ it "has a Response Body" do
+ Net::HTTP::Lock::RESPONSE_HAS_BODY.should be_true
+ end
+end
+
+describe "Net::HTTP::Unlock" do
+ it "is a subclass of Net::HTTPRequest" do
+ Net::HTTP::Unlock.should < Net::HTTPRequest
+ end
+
+ it "represents the 'UNLOCK'-Request-Method" do
+ Net::HTTP::Unlock::METHOD.should == "UNLOCK"
+ end
+
+ it "has a Request Body" do
+ Net::HTTP::Unlock::REQUEST_HAS_BODY.should be_true
+ end
+
+ it "has a Response Body" do
+ Net::HTTP::Unlock::RESPONSE_HAS_BODY.should be_true
+ end
+end
diff --git a/spec/ruby/library/net-http/http/send_request_spec.rb b/spec/ruby/library/net-http/http/send_request_spec.rb
new file mode 100644
index 0000000000..e82b2a96a1
--- /dev/null
+++ b/spec/ruby/library/net-http/http/send_request_spec.rb
@@ -0,0 +1,61 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+
+describe "Net::HTTP#send_request" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
+
+ # HEAD is special so handled separately
+ @methods = %w[
+ GET POST PUT DELETE
+ OPTIONS
+ PROPFIND PROPPATCH LOCK UNLOCK
+ ]
+ end
+
+ after :each do
+ @http.finish if @http.started?
+ NetHTTPSpecs.stop_server
+ end
+
+ # TODO: Does only work with GET and POST requests
+ describe "when passed type, path" do
+ it "sends a HTTP Request of the passed type to the passed path" do
+ response = @http.send_request("HEAD", "/request")
+ response.body.should be_nil
+
+ (@methods - %w[POST PUT]).each do |method|
+ response = @http.send_request(method, "/request")
+ response.body.should == "Request type: #{method}"
+ end
+ end
+ end
+
+ describe "when passed type, path, body" do
+ it "sends a HTTP Request with the passed body" do
+ response = @http.send_request("HEAD", "/request/body", "test=test")
+ response.body.should be_nil
+
+ @methods.each do |method|
+ response = @http.send_request(method, "/request/body", "test=test")
+ response.body.should == "test=test"
+ end
+ end
+ end
+
+ describe "when passed type, path, body, headers" do
+ it "sends a HTTP Request with the passed headers" do
+ referer = 'https://www.ruby-lang.org/'.freeze
+
+ response = @http.send_request("HEAD", "/request/header", "test=test", "referer" => referer)
+ response.body.should be_nil
+
+ @methods.each do |method|
+ response = @http.send_request(method, "/request/header", "test=test", "referer" => referer)
+ response.body.should include('"Referer"=>"' + referer + '"')
+ end
+ end
+ end
+end
diff --git a/spec/ruby/library/net-http/http/set_debug_output_spec.rb b/spec/ruby/library/net-http/http/set_debug_output_spec.rb
new file mode 100644
index 0000000000..5ceecb39fb
--- /dev/null
+++ b/spec/ruby/library/net-http/http/set_debug_output_spec.rb
@@ -0,0 +1,33 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require "stringio"
+require_relative 'fixtures/http_server'
+
+describe "Net::HTTP#set_debug_output when passed io" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @http = Net::HTTP.new("localhost", NetHTTPSpecs.port)
+ end
+
+ after :each do
+ @http.finish if @http.started?
+ NetHTTPSpecs.stop_server
+ end
+
+ it "sets the passed io as output stream for debugging" do
+ io = StringIO.new
+
+ @http.set_debug_output(io)
+ @http.start
+ io.string.should_not be_empty
+ size = io.string.size
+
+ @http.get("/")
+ io.string.size.should > size
+ end
+
+ it "outputs a warning when the connection has already been started" do
+ @http.start
+ -> { @http.set_debug_output(StringIO.new) }.should complain(/Net::HTTP#set_debug_output called after HTTP started/)
+ end
+end
diff --git a/spec/ruby/library/net/http/http/shared/request_get.rb b/spec/ruby/library/net-http/http/shared/request_get.rb
index d25f32049b..d25f32049b 100644
--- a/spec/ruby/library/net/http/http/shared/request_get.rb
+++ b/spec/ruby/library/net-http/http/shared/request_get.rb
diff --git a/spec/ruby/library/net/http/http/shared/request_head.rb b/spec/ruby/library/net-http/http/shared/request_head.rb
index 78b555884b..78b555884b 100644
--- a/spec/ruby/library/net/http/http/shared/request_head.rb
+++ b/spec/ruby/library/net-http/http/shared/request_head.rb
diff --git a/spec/ruby/library/net/http/http/shared/request_post.rb b/spec/ruby/library/net-http/http/shared/request_post.rb
index e832411c48..e832411c48 100644
--- a/spec/ruby/library/net/http/http/shared/request_post.rb
+++ b/spec/ruby/library/net-http/http/shared/request_post.rb
diff --git a/spec/ruby/library/net/http/http/shared/request_put.rb b/spec/ruby/library/net-http/http/shared/request_put.rb
index 3b902f4957..3b902f4957 100644
--- a/spec/ruby/library/net/http/http/shared/request_put.rb
+++ b/spec/ruby/library/net-http/http/shared/request_put.rb
diff --git a/spec/ruby/library/net/http/http/shared/started.rb b/spec/ruby/library/net-http/http/shared/started.rb
index 9ff6272c31..9ff6272c31 100644
--- a/spec/ruby/library/net/http/http/shared/started.rb
+++ b/spec/ruby/library/net-http/http/shared/started.rb
diff --git a/spec/ruby/library/net/http/http/shared/version_1_1.rb b/spec/ruby/library/net-http/http/shared/version_1_1.rb
index db3d6a986d..db3d6a986d 100644
--- a/spec/ruby/library/net/http/http/shared/version_1_1.rb
+++ b/spec/ruby/library/net-http/http/shared/version_1_1.rb
diff --git a/spec/ruby/library/net/http/http/shared/version_1_2.rb b/spec/ruby/library/net-http/http/shared/version_1_2.rb
index b044182c60..b044182c60 100644
--- a/spec/ruby/library/net/http/http/shared/version_1_2.rb
+++ b/spec/ruby/library/net-http/http/shared/version_1_2.rb
diff --git a/spec/ruby/library/net-http/http/socket_type_spec.rb b/spec/ruby/library/net-http/http/socket_type_spec.rb
new file mode 100644
index 0000000000..f6826777b0
--- /dev/null
+++ b/spec/ruby/library/net-http/http/socket_type_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTP.socket_type" do
+ it "returns BufferedIO" do
+ Net::HTTP.socket_type.should == Net::BufferedIO
+ end
+end
diff --git a/spec/ruby/library/net-http/http/start_spec.rb b/spec/ruby/library/net-http/http/start_spec.rb
new file mode 100644
index 0000000000..0ce3e79269
--- /dev/null
+++ b/spec/ruby/library/net-http/http/start_spec.rb
@@ -0,0 +1,111 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+
+describe "Net::HTTP.start" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @port = NetHTTPSpecs.port
+ end
+
+ after :each do
+ NetHTTPSpecs.stop_server
+ end
+
+ describe "when not passed a block" do
+ before :each do
+ @http = Net::HTTP.start("localhost", @port)
+ end
+
+ after :each do
+ @http.finish if @http.started?
+ end
+
+ it "returns a new Net::HTTP object for the passed address and port" do
+ @http.should be_kind_of(Net::HTTP)
+ @http.address.should == "localhost"
+ @http.port.should == @port
+ end
+
+ it "opens the tcp connection" do
+ @http.started?.should be_true
+ end
+ end
+
+ describe "when passed a block" do
+ it "returns the blocks return value" do
+ Net::HTTP.start("localhost", @port) { :test }.should == :test
+ end
+
+ it "yields the new Net::HTTP object to the block" do
+ yielded = false
+ Net::HTTP.start("localhost", @port) do |net|
+ yielded = true
+ net.should be_kind_of(Net::HTTP)
+ end
+ yielded.should be_true
+ end
+
+ it "opens the tcp connection before yielding" do
+ Net::HTTP.start("localhost", @port) { |http| http.started?.should be_true }
+ end
+
+ it "closes the tcp connection after yielding" do
+ net = nil
+ Net::HTTP.start("localhost", @port) { |x| net = x }
+ net.started?.should be_false
+ end
+ end
+end
+
+describe "Net::HTTP#start" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @http = Net::HTTP.new("localhost", NetHTTPSpecs.port)
+ end
+
+ after :each do
+ @http.finish if @http.started?
+ NetHTTPSpecs.stop_server
+ end
+
+ it "returns self" do
+ @http.start.should equal(@http)
+ end
+
+ it "opens the tcp connection" do
+ @http.start
+ @http.started?.should be_true
+ end
+
+ describe "when self has already been started" do
+ it "raises an IOError" do
+ @http.start
+ -> { @http.start }.should raise_error(IOError)
+ end
+ end
+
+ describe "when passed a block" do
+ it "returns the blocks return value" do
+ @http.start { :test }.should == :test
+ end
+
+ it "yields the new Net::HTTP object to the block" do
+ yielded = false
+ @http.start do |http|
+ yielded = true
+ http.should equal(@http)
+ end
+ yielded.should be_true
+ end
+
+ it "opens the tcp connection before yielding" do
+ @http.start { |http| http.started?.should be_true }
+ end
+
+ it "closes the tcp connection after yielding" do
+ @http.start { }
+ @http.started?.should be_false
+ end
+ end
+end
diff --git a/spec/ruby/library/net-http/http/started_spec.rb b/spec/ruby/library/net-http/http/started_spec.rb
new file mode 100644
index 0000000000..cbb82ceefa
--- /dev/null
+++ b/spec/ruby/library/net-http/http/started_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+require_relative 'shared/started'
+
+describe "Net::HTTP#started?" do
+ it_behaves_like :net_http_started_p, :started?
+end
diff --git a/spec/ruby/library/net-http/http/trace_spec.rb b/spec/ruby/library/net-http/http/trace_spec.rb
new file mode 100644
index 0000000000..9809d537c5
--- /dev/null
+++ b/spec/ruby/library/net-http/http/trace_spec.rb
@@ -0,0 +1,24 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+
+describe "Net::HTTP#trace" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
+ end
+
+ after :each do
+ @http.finish if @http.started?
+ NetHTTPSpecs.stop_server
+ end
+
+ it "sends a TRACE request to the passed path and returns the response" do
+ response = @http.trace("/request")
+ response.body.should == "Request type: TRACE"
+ end
+
+ it "returns a Net::HTTPResponse" do
+ @http.trace("/request").should be_kind_of(Net::HTTPResponse)
+ end
+end
diff --git a/spec/ruby/library/net-http/http/unlock_spec.rb b/spec/ruby/library/net-http/http/unlock_spec.rb
new file mode 100644
index 0000000000..adf0b49f65
--- /dev/null
+++ b/spec/ruby/library/net-http/http/unlock_spec.rb
@@ -0,0 +1,24 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/http_server'
+
+describe "Net::HTTP#unlock" do
+ before :each do
+ NetHTTPSpecs.start_server
+ @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
+ end
+
+ after :each do
+ @http.finish if @http.started?
+ NetHTTPSpecs.stop_server
+ end
+
+ it "sends an UNLOCK request to the passed path and returns the response" do
+ response = @http.unlock("/request", "test=test")
+ response.body.should == "Request type: UNLOCK"
+ end
+
+ it "returns a Net::HTTPResponse" do
+ @http.unlock("/request", "test=test").should be_kind_of(Net::HTTPResponse)
+ end
+end
diff --git a/spec/ruby/library/net-http/http/use_ssl_spec.rb b/spec/ruby/library/net-http/http/use_ssl_spec.rb
new file mode 100644
index 0000000000..912a62a8ba
--- /dev/null
+++ b/spec/ruby/library/net-http/http/use_ssl_spec.rb
@@ -0,0 +1,9 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTP#use_ssl?" do
+ it "returns false" do
+ http = Net::HTTP.new("localhost")
+ http.use_ssl?.should be_false
+ end
+end
diff --git a/spec/ruby/library/net-http/http/version_1_1_spec.rb b/spec/ruby/library/net-http/http/version_1_1_spec.rb
new file mode 100644
index 0000000000..34a4ac8a6b
--- /dev/null
+++ b/spec/ruby/library/net-http/http/version_1_1_spec.rb
@@ -0,0 +1,7 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'shared/version_1_1'
+
+describe "Net::HTTP.version_1_1?" do
+ it_behaves_like :net_http_version_1_1_p, :version_1_1?
+end
diff --git a/spec/ruby/library/net-http/http/version_1_2_spec.rb b/spec/ruby/library/net-http/http/version_1_2_spec.rb
new file mode 100644
index 0000000000..e994511aea
--- /dev/null
+++ b/spec/ruby/library/net-http/http/version_1_2_spec.rb
@@ -0,0 +1,20 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'shared/version_1_2'
+
+describe "Net::HTTP.version_1_2" do
+ it "turns on net/http 1.2 features" do
+ Net::HTTP.version_1_2
+
+ Net::HTTP.version_1_2?.should be_true
+ Net::HTTP.version_1_1?.should be_false
+ end
+
+ it "returns true" do
+ Net::HTTP.version_1_2.should be_true
+ end
+end
+
+describe "Net::HTTP.version_1_2?" do
+ it_behaves_like :net_http_version_1_2_p, :version_1_2?
+end
diff --git a/spec/ruby/library/net/http/httpexceptions/fixtures/classes.rb b/spec/ruby/library/net-http/httpexceptions/fixtures/classes.rb
index abe8855eff..abe8855eff 100644
--- a/spec/ruby/library/net/http/httpexceptions/fixtures/classes.rb
+++ b/spec/ruby/library/net-http/httpexceptions/fixtures/classes.rb
diff --git a/spec/ruby/library/net-http/httpexceptions/initialize_spec.rb b/spec/ruby/library/net-http/httpexceptions/initialize_spec.rb
new file mode 100644
index 0000000000..5316cca69d
--- /dev/null
+++ b/spec/ruby/library/net-http/httpexceptions/initialize_spec.rb
@@ -0,0 +1,17 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+
+describe "Net::HTTPExceptions#initialize when passed message, response" do
+ before :each do
+ @exception = NetHTTPExceptionsSpecs::Simple.new("error message", "a http response")
+ end
+
+ it "calls super with the passed message" do
+ @exception.message.should == "error message"
+ end
+
+ it "sets self's response to the passed response" do
+ @exception.response.should == "a http response"
+ end
+end
diff --git a/spec/ruby/library/net-http/httpexceptions/response_spec.rb b/spec/ruby/library/net-http/httpexceptions/response_spec.rb
new file mode 100644
index 0000000000..d718b1ae21
--- /dev/null
+++ b/spec/ruby/library/net-http/httpexceptions/response_spec.rb
@@ -0,0 +1,10 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+
+describe "Net::HTTPExceptions#response" do
+ it "returns self's response" do
+ exception = NetHTTPExceptionsSpecs::Simple.new("error message", "a http response")
+ exception.response.should == "a http response"
+ end
+end
diff --git a/spec/ruby/library/net-http/httpgenericrequest/body_exist_spec.rb b/spec/ruby/library/net-http/httpgenericrequest/body_exist_spec.rb
new file mode 100644
index 0000000000..6c886499ca
--- /dev/null
+++ b/spec/ruby/library/net-http/httpgenericrequest/body_exist_spec.rb
@@ -0,0 +1,21 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPGenericRequest#body_exist?" do
+ it "returns true when the response is expected to have a body" do
+ request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
+ request.body_exist?.should be_true
+
+ request = Net::HTTPGenericRequest.new("POST", true, false, "/some/path")
+ request.body_exist?.should be_false
+ end
+
+ describe "when $VERBOSE is true" do
+ it "emits a warning" do
+ request = Net::HTTPGenericRequest.new("POST", true, false, "/some/path")
+ -> {
+ request.body_exist?
+ }.should complain(/body_exist\? is obsolete/, verbose: true)
+ end
+ end
+end
diff --git a/spec/ruby/library/net-http/httpgenericrequest/body_spec.rb b/spec/ruby/library/net-http/httpgenericrequest/body_spec.rb
new file mode 100644
index 0000000000..5f7315f303
--- /dev/null
+++ b/spec/ruby/library/net-http/httpgenericrequest/body_spec.rb
@@ -0,0 +1,30 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require "stringio"
+
+describe "Net::HTTPGenericRequest#body" do
+ it "returns self's request body" do
+ request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
+ request.body.should be_nil
+
+ request.body = "Some Content"
+ request.body.should == "Some Content"
+ end
+end
+
+describe "Net::HTTPGenericRequest#body=" do
+ before :each do
+ @request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
+ end
+
+ it "sets self's body content to the passed String" do
+ @request.body = "Some Content"
+ @request.body.should == "Some Content"
+ end
+
+ it "sets self's body stream to nil" do
+ @request.body_stream = StringIO.new("")
+ @request.body = "Some Content"
+ @request.body_stream.should be_nil
+ end
+end
diff --git a/spec/ruby/library/net-http/httpgenericrequest/body_stream_spec.rb b/spec/ruby/library/net-http/httpgenericrequest/body_stream_spec.rb
new file mode 100644
index 0000000000..dea1c8c883
--- /dev/null
+++ b/spec/ruby/library/net-http/httpgenericrequest/body_stream_spec.rb
@@ -0,0 +1,32 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require "stringio"
+
+describe "Net::HTTPGenericRequest#body_stream" do
+ it "returns self's body stream Object" do
+ request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
+ request.body_stream.should be_nil
+
+ stream = StringIO.new("test")
+ request.body_stream = stream
+ request.body_stream.should equal(stream)
+ end
+end
+
+describe "Net::HTTPGenericRequest#body_stream=" do
+ before :each do
+ @request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
+ @stream = StringIO.new("test")
+ end
+
+ it "sets self's body stream to the passed Object" do
+ @request.body_stream = @stream
+ @request.body_stream.should equal(@stream)
+ end
+
+ it "sets self's body to nil" do
+ @request.body = "Some Content"
+ @request.body_stream = @stream
+ @request.body.should be_nil
+ end
+end
diff --git a/spec/ruby/library/net-http/httpgenericrequest/exec_spec.rb b/spec/ruby/library/net-http/httpgenericrequest/exec_spec.rb
new file mode 100644
index 0000000000..7de03d7da0
--- /dev/null
+++ b/spec/ruby/library/net-http/httpgenericrequest/exec_spec.rb
@@ -0,0 +1,131 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require "stringio"
+
+describe "Net::HTTPGenericRequest#exec when passed socket, version, path" do
+ before :each do
+ @socket = StringIO.new(+"")
+ @buffered_socket = Net::BufferedIO.new(@socket)
+ end
+
+ it "executes the request over the socket to the path using the HTTP version" do
+ request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
+
+ request.exec(@buffered_socket, "1.1", "/some/path")
+ str = @socket.string
+
+ str.should =~ %r[POST /some/path HTTP/1.1\r\n]
+ str.should =~ %r[Accept: \*/\*\r\n]
+ str[-4..-1].should == "\r\n\r\n"
+
+ request = Net::HTTPGenericRequest.new("GET", true, true, "/some/path",
+ "Content-Type" => "text/html")
+
+ request.exec(@buffered_socket, "1.0", "/some/other/path")
+ str = @socket.string
+
+ str.should =~ %r[GET /some/other/path HTTP/1.0\r\n]
+ str.should =~ %r[Accept: \*/\*\r\n]
+ str.should =~ %r[Content-Type: text/html\r\n]
+ str[-4..-1].should == "\r\n\r\n"
+ end
+
+ describe "when a request body is set" do
+ it "sets the 'Content-Type' header to 'application/x-www-form-urlencoded' unless the 'Content-Type' header is supplied" do
+ request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
+ request.body = "Some Content"
+
+ request.exec(@buffered_socket, "1.1", "/some/other/path")
+ str = @socket.string
+
+ str.should =~ %r[POST /some/other/path HTTP/1.1\r\n]
+ str.should =~ %r[Accept: \*/\*\r\n]
+ str.should =~ %r[Content-Type: application/x-www-form-urlencoded\r\n]
+ str.should =~ %r[Content-Length: 12\r\n]
+ str[-16..-1].should == "\r\n\r\nSome Content"
+ end
+
+ it "correctly sets the 'Content-Length' header and includes the body" do
+ request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path",
+ "Content-Type" => "text/html")
+ request.body = "Some Content"
+
+ request.exec(@buffered_socket, "1.1", "/some/other/path")
+ str = @socket.string
+
+ str.should =~ %r[POST /some/other/path HTTP/1.1\r\n]
+ str.should =~ %r[Accept: \*/\*\r\n]
+ str.should =~ %r[Content-Type: text/html\r\n]
+ str.should =~ %r[Content-Length: 12\r\n]
+ str[-16..-1].should == "\r\n\r\nSome Content"
+ end
+ end
+
+ describe "when a body stream is set" do
+ it "sets the 'Content-Type' header to 'application/x-www-form-urlencoded' unless the 'Content-Type' header is supplied" do
+ request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path",
+ "Content-Length" => "10")
+ request.body_stream = StringIO.new("a" * 20)
+
+ request.exec(@buffered_socket, "1.1", "/some/other/path")
+ str = @socket.string
+
+ str.should =~ %r[POST /some/other/path HTTP/1.1\r\n]
+ str.should =~ %r[Accept: \*/\*\r\n]
+ str.should =~ %r[Content-Type: application/x-www-form-urlencoded\r\n]
+ str.should =~ %r[Content-Length: 10\r\n]
+ str[-24..-1].should == "\r\n\r\naaaaaaaaaaaaaaaaaaaa"
+ end
+
+ it "sends the whole stream, regardless of the 'Content-Length' header" do
+ request = Net::HTTPGenericRequest.new("POST", true, true,"/some/path",
+ "Content-Type" => "text/html",
+ "Content-Length" => "10")
+ request.body_stream = StringIO.new("a" * 20)
+
+ request.exec(@buffered_socket, "1.1", "/some/other/path")
+ str = @socket.string
+
+ str.should =~ %r[POST /some/other/path HTTP/1.1\r\n]
+ str.should =~ %r[Accept: \*/\*\r\n]
+ str.should =~ %r[Content-Type: text/html\r\n]
+ str.should =~ %r[Content-Length: 10\r\n]
+ str[-24..-1].should == "\r\n\r\naaaaaaaaaaaaaaaaaaaa"
+ end
+
+ it "sends the request in chunks when 'Transfer-Encoding' is set to 'chunked'" do
+ request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path",
+ "Content-Type" => "text/html",
+ "Transfer-Encoding" => "chunked")
+ datasize = 1024 * 10
+ request.body_stream = StringIO.new("a" * datasize)
+
+ request.exec(@buffered_socket, "1.1", "/some/other/path")
+ str = @socket.string
+
+ str.should =~ %r[POST /some/other/path HTTP/1.1\r\n]
+ str.should =~ %r[Accept: \*/\*\r\n]
+ str.should =~ %r[Content-Type: text/html\r\n]
+ str.should =~ %r[Transfer-Encoding: chunked\r\n]
+ str =~ %r[\r\n\r\n]
+ str = $'
+ while datasize > 0
+ chunk_size_line, str = str.split(/\r\n/, 2)
+ chunk_size = chunk_size_line[/\A[0-9A-Fa-f]+/].to_i(16)
+ str.slice!(0, chunk_size).should == 'a' * chunk_size
+ datasize -= chunk_size
+ str.slice!(0, 2).should == "\r\n"
+ end
+ datasize.should == 0
+ str.should == %"0\r\n\r\n"
+ end
+
+ it "raises an ArgumentError when the 'Content-Length' is not set or 'Transfer-Encoding' is not set to 'chunked'" do
+ request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path",
+ "Content-Type" => "text/html")
+ request.body_stream = StringIO.new("Some Content")
+
+ -> { request.exec(@buffered_socket, "1.1", "/some/other/path") }.should raise_error(ArgumentError)
+ end
+ end
+end
diff --git a/spec/ruby/library/net-http/httpgenericrequest/inspect_spec.rb b/spec/ruby/library/net-http/httpgenericrequest/inspect_spec.rb
new file mode 100644
index 0000000000..d03b6e6953
--- /dev/null
+++ b/spec/ruby/library/net-http/httpgenericrequest/inspect_spec.rb
@@ -0,0 +1,25 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPGenericRequest#inspect" do
+ it "returns a String representation of self" do
+ request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
+ request.inspect.should == "#<Net::HTTPGenericRequest POST>"
+
+ request = Net::HTTPGenericRequest.new("GET", false, true, "/some/path")
+ request.inspect.should == "#<Net::HTTPGenericRequest GET>"
+
+ request = Net::HTTPGenericRequest.new("BLA", true, true, "/some/path")
+ request.inspect.should == "#<Net::HTTPGenericRequest BLA>"
+
+ # Subclasses
+ request = Net::HTTP::Get.new("/some/path")
+ request.inspect.should == "#<Net::HTTP::Get GET>"
+
+ request = Net::HTTP::Post.new("/some/path")
+ request.inspect.should == "#<Net::HTTP::Post POST>"
+
+ request = Net::HTTP::Trace.new("/some/path")
+ request.inspect.should == "#<Net::HTTP::Trace TRACE>"
+ end
+end
diff --git a/spec/ruby/library/net-http/httpgenericrequest/method_spec.rb b/spec/ruby/library/net-http/httpgenericrequest/method_spec.rb
new file mode 100644
index 0000000000..794bd328cd
--- /dev/null
+++ b/spec/ruby/library/net-http/httpgenericrequest/method_spec.rb
@@ -0,0 +1,15 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPGenericRequest#method" do
+ it "returns self's request method" do
+ request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
+ request.method.should == "POST"
+
+ request = Net::HTTPGenericRequest.new("GET", false, true, "/some/path")
+ request.method.should == "GET"
+
+ request = Net::HTTPGenericRequest.new("BLA", true, true, "/some/path")
+ request.method.should == "BLA"
+ end
+end
diff --git a/spec/ruby/library/net-http/httpgenericrequest/path_spec.rb b/spec/ruby/library/net-http/httpgenericrequest/path_spec.rb
new file mode 100644
index 0000000000..a9fac3f67e
--- /dev/null
+++ b/spec/ruby/library/net-http/httpgenericrequest/path_spec.rb
@@ -0,0 +1,12 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPGenericRequest#path" do
+ it "returns self's request path" do
+ request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
+ request.path.should == "/some/path"
+
+ request = Net::HTTPGenericRequest.new("POST", true, true, "/some/other/path")
+ request.path.should == "/some/other/path"
+ end
+end
diff --git a/spec/ruby/library/net-http/httpgenericrequest/request_body_permitted_spec.rb b/spec/ruby/library/net-http/httpgenericrequest/request_body_permitted_spec.rb
new file mode 100644
index 0000000000..1713b59baf
--- /dev/null
+++ b/spec/ruby/library/net-http/httpgenericrequest/request_body_permitted_spec.rb
@@ -0,0 +1,12 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPGenericRequest#request_body_permitted?" do
+ it "returns true when the request is expected to have a body" do
+ request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
+ request.request_body_permitted?.should be_true
+
+ request = Net::HTTPGenericRequest.new("POST", false, true, "/some/path")
+ request.request_body_permitted?.should be_false
+ end
+end
diff --git a/spec/ruby/library/net-http/httpgenericrequest/response_body_permitted_spec.rb b/spec/ruby/library/net-http/httpgenericrequest/response_body_permitted_spec.rb
new file mode 100644
index 0000000000..2f0751c344
--- /dev/null
+++ b/spec/ruby/library/net-http/httpgenericrequest/response_body_permitted_spec.rb
@@ -0,0 +1,12 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPGenericRequest#response_body_permitted?" do
+ it "returns true when the response is expected to have a body" do
+ request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
+ request.response_body_permitted?.should be_true
+
+ request = Net::HTTPGenericRequest.new("POST", true, false, "/some/path")
+ request.response_body_permitted?.should be_false
+ end
+end
diff --git a/spec/ruby/library/net-http/httpgenericrequest/set_body_internal_spec.rb b/spec/ruby/library/net-http/httpgenericrequest/set_body_internal_spec.rb
new file mode 100644
index 0000000000..358aa6cde3
--- /dev/null
+++ b/spec/ruby/library/net-http/httpgenericrequest/set_body_internal_spec.rb
@@ -0,0 +1,21 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPGenericRequest#set_body_internal when passed string" do
+ before :each do
+ @request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
+ end
+
+ it "sets self's body to the passed string" do
+ @request.set_body_internal("Some Content")
+ @request.body.should == "Some Content"
+ end
+
+ it "raises an ArgumentError when the body or body_stream of self have already been set" do
+ @request.body = "Some Content"
+ -> { @request.set_body_internal("Some other Content") }.should raise_error(ArgumentError)
+
+ @request.body_stream = "Some Content"
+ -> { @request.set_body_internal("Some other Content") }.should raise_error(ArgumentError)
+ end
+end
diff --git a/spec/ruby/library/net-http/httpheader/add_field_spec.rb b/spec/ruby/library/net-http/httpheader/add_field_spec.rb
new file mode 100644
index 0000000000..8cd3d33517
--- /dev/null
+++ b/spec/ruby/library/net-http/httpheader/add_field_spec.rb
@@ -0,0 +1,31 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+
+describe "Net::HTTPHeader#add_field when passed key, value" do
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ end
+
+ it "adds the passed value to the header entry with the passed key" do
+ @headers.add_field("My-Header", "a")
+ @headers.get_fields("My-Header").should == ["a"]
+
+ @headers.add_field("My-Header", "b")
+ @headers.get_fields("My-Header").should == ["a", "b"]
+
+ @headers.add_field("My-Header", "c")
+ @headers.get_fields("My-Header").should == ["a", "b", "c"]
+ end
+
+ it "is case-insensitive" do
+ @headers.add_field("My-Header", "a")
+ @headers.get_fields("My-Header").should == ["a"]
+
+ @headers.add_field("my-header", "b")
+ @headers.get_fields("My-Header").should == ["a", "b"]
+
+ @headers.add_field("MY-HEADER", "c")
+ @headers.get_fields("My-Header").should == ["a", "b", "c"]
+ end
+end
diff --git a/spec/ruby/library/net-http/httpheader/basic_auth_spec.rb b/spec/ruby/library/net-http/httpheader/basic_auth_spec.rb
new file mode 100644
index 0000000000..db7ca84d13
--- /dev/null
+++ b/spec/ruby/library/net-http/httpheader/basic_auth_spec.rb
@@ -0,0 +1,14 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+
+describe "Net::HTTPHeader#basic_auth when passed account, password" do
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ end
+
+ it "sets the 'Authorization' Header entry for basic authorization" do
+ @headers.basic_auth("rubyspec", "rocks")
+ @headers["Authorization"].should == "Basic cnVieXNwZWM6cm9ja3M="
+ end
+end
diff --git a/spec/ruby/library/net-http/httpheader/canonical_each_spec.rb b/spec/ruby/library/net-http/httpheader/canonical_each_spec.rb
new file mode 100644
index 0000000000..64a5cae89e
--- /dev/null
+++ b/spec/ruby/library/net-http/httpheader/canonical_each_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+require_relative 'shared/each_capitalized'
+
+describe "Net::HTTPHeader#canonical_each" do
+ it_behaves_like :net_httpheader_each_capitalized, :canonical_each
+end
diff --git a/spec/ruby/library/net-http/httpheader/chunked_spec.rb b/spec/ruby/library/net-http/httpheader/chunked_spec.rb
new file mode 100644
index 0000000000..b32a0aab38
--- /dev/null
+++ b/spec/ruby/library/net-http/httpheader/chunked_spec.rb
@@ -0,0 +1,22 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+
+describe "Net::HTTPHeader#chunked?" do
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ end
+
+ it "returns true if the 'Transfer-Encoding' header entry is set to chunked" do
+ @headers.chunked?.should be_false
+
+ @headers["Transfer-Encoding"] = "bla"
+ @headers.chunked?.should be_false
+
+ @headers["Transfer-Encoding"] = "blachunkedbla"
+ @headers.chunked?.should be_false
+
+ @headers["Transfer-Encoding"] = "chunked"
+ @headers.chunked?.should be_true
+ end
+end
diff --git a/spec/ruby/library/net-http/httpheader/content_length_spec.rb b/spec/ruby/library/net-http/httpheader/content_length_spec.rb
new file mode 100644
index 0000000000..f05c5f8d8b
--- /dev/null
+++ b/spec/ruby/library/net-http/httpheader/content_length_spec.rb
@@ -0,0 +1,54 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+
+describe "Net::HTTPHeader#content_length" do
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ end
+
+ it "returns nil if no 'Content-Length' header entry is set" do
+ @headers.content_length.should be_nil
+ end
+
+ it "raises a Net::HTTPHeaderSyntaxError when the 'Content-Length' header entry has an invalid format" do
+ @headers["Content-Length"] = "invalid"
+ -> { @headers.content_length }.should raise_error(Net::HTTPHeaderSyntaxError)
+ end
+
+ it "returns the value of the 'Content-Length' header entry as an Integer" do
+ @headers["Content-Length"] = "123"
+ @headers.content_length.should eql(123)
+
+ @headers["Content-Length"] = "123valid"
+ @headers.content_length.should eql(123)
+
+ @headers["Content-Length"] = "valid123"
+ @headers.content_length.should eql(123)
+ end
+end
+
+describe "Net::HTTPHeader#content_length=" do
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ end
+
+ it "removes the 'Content-Length' entry if passed false or nil" do
+ @headers["Content-Length"] = "123"
+ @headers.content_length = nil
+ @headers["Content-Length"].should be_nil
+ end
+
+ it "sets the 'Content-Length' entry to the passed value" do
+ @headers.content_length = "123"
+ @headers["Content-Length"].should == "123"
+
+ @headers.content_length = "123valid"
+ @headers["Content-Length"].should == "123"
+ end
+
+ it "sets the 'Content-Length' entry to 0 if the passed value is not valid" do
+ @headers.content_length = "invalid123"
+ @headers["Content-Length"].should == "0"
+ end
+end
diff --git a/spec/ruby/library/net-http/httpheader/content_range_spec.rb b/spec/ruby/library/net-http/httpheader/content_range_spec.rb
new file mode 100644
index 0000000000..09737141a5
--- /dev/null
+++ b/spec/ruby/library/net-http/httpheader/content_range_spec.rb
@@ -0,0 +1,32 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+
+describe "Net::HTTPHeader#content_range" do
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ end
+
+ it "returns a Range object that represents the 'Content-Range' header entry" do
+ @headers["Content-Range"] = "bytes 0-499/1234"
+ @headers.content_range.should == (0..499)
+
+ @headers["Content-Range"] = "bytes 500-1233/1234"
+ @headers.content_range.should == (500..1233)
+ end
+
+ it "returns nil when there is no 'Content-Range' header entry" do
+ @headers.content_range.should be_nil
+ end
+
+ it "raises a Net::HTTPHeaderSyntaxError when the 'Content-Range' has an invalid format" do
+ @headers["Content-Range"] = "invalid"
+ -> { @headers.content_range }.should raise_error(Net::HTTPHeaderSyntaxError)
+
+ @headers["Content-Range"] = "bytes 123-abc"
+ -> { @headers.content_range }.should raise_error(Net::HTTPHeaderSyntaxError)
+
+ @headers["Content-Range"] = "bytes abc-123"
+ -> { @headers.content_range }.should raise_error(Net::HTTPHeaderSyntaxError)
+ end
+end
diff --git a/spec/ruby/library/net-http/httpheader/content_type_spec.rb b/spec/ruby/library/net-http/httpheader/content_type_spec.rb
new file mode 100644
index 0000000000..a6e1ae1093
--- /dev/null
+++ b/spec/ruby/library/net-http/httpheader/content_type_spec.rb
@@ -0,0 +1,26 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+require_relative 'shared/set_content_type'
+
+describe "Net::HTTPHeader#content_type" do
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ end
+
+ it "returns the content type string, as per 'Content-Type' header entry" do
+ @headers["Content-Type"] = "text/html"
+ @headers.content_type.should == "text/html"
+
+ @headers["Content-Type"] = "text/html;charset=utf-8"
+ @headers.content_type.should == "text/html"
+ end
+
+ it "returns nil if the 'Content-Type' header entry does not exist" do
+ @headers.content_type.should be_nil
+ end
+end
+
+describe "Net::HTTPHeader#content_type=" do
+ it_behaves_like :net_httpheader_set_content_type, :content_type=
+end
diff --git a/spec/ruby/library/net-http/httpheader/delete_spec.rb b/spec/ruby/library/net-http/httpheader/delete_spec.rb
new file mode 100644
index 0000000000..8d929dbd86
--- /dev/null
+++ b/spec/ruby/library/net-http/httpheader/delete_spec.rb
@@ -0,0 +1,30 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+
+describe "Net::HTTPHeader#delete when passed key" do
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ end
+
+ it "removes the header entry with the passed key" do
+ @headers["My-Header"] = "test"
+ @headers.delete("My-Header")
+
+ @headers["My-Header"].should be_nil
+ @headers.size.should eql(0)
+ end
+
+ it "returns the removed values" do
+ @headers["My-Header"] = "test"
+ @headers.delete("My-Header").should == ["test"]
+ end
+
+ it "is case-insensitive" do
+ @headers["My-Header"] = "test"
+ @headers.delete("my-header")
+
+ @headers["My-Header"].should be_nil
+ @headers.size.should eql(0)
+ end
+end
diff --git a/spec/ruby/library/net-http/httpheader/each_capitalized_name_spec.rb b/spec/ruby/library/net-http/httpheader/each_capitalized_name_spec.rb
new file mode 100644
index 0000000000..27713577f9
--- /dev/null
+++ b/spec/ruby/library/net-http/httpheader/each_capitalized_name_spec.rb
@@ -0,0 +1,35 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+
+describe "Net::HTTPHeader#each_capitalized_name" do
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ @headers["My-Header"] = "test"
+ @headers.add_field("My-Other-Header", "a")
+ @headers.add_field("My-Other-Header", "b")
+ end
+
+ describe "when passed a block" do
+ it "yields each header key to the passed block (keys capitalized)" do
+ res = []
+ @headers.each_capitalized_name do |key|
+ res << key
+ end
+ res.sort.should == ["My-Header", "My-Other-Header"]
+ end
+ end
+
+ describe "when passed no block" do
+ it "returns an Enumerator" do
+ enumerator = @headers.each_capitalized_name
+ enumerator.should be_an_instance_of(Enumerator)
+
+ res = []
+ enumerator.each do |key|
+ res << key
+ end
+ res.sort.should == ["My-Header", "My-Other-Header"]
+ end
+ end
+end
diff --git a/spec/ruby/library/net-http/httpheader/each_capitalized_spec.rb b/spec/ruby/library/net-http/httpheader/each_capitalized_spec.rb
new file mode 100644
index 0000000000..1e853995ea
--- /dev/null
+++ b/spec/ruby/library/net-http/httpheader/each_capitalized_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+require_relative 'shared/each_capitalized'
+
+describe "Net::HTTPHeader#each_capitalized" do
+ it_behaves_like :net_httpheader_each_capitalized, :each_capitalized
+end
diff --git a/spec/ruby/library/net-http/httpheader/each_header_spec.rb b/spec/ruby/library/net-http/httpheader/each_header_spec.rb
new file mode 100644
index 0000000000..869feebacf
--- /dev/null
+++ b/spec/ruby/library/net-http/httpheader/each_header_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+require_relative 'shared/each_header'
+
+describe "Net::HTTPHeader#each_header" do
+ it_behaves_like :net_httpheader_each_header, :each_header
+end
diff --git a/spec/ruby/library/net-http/httpheader/each_key_spec.rb b/spec/ruby/library/net-http/httpheader/each_key_spec.rb
new file mode 100644
index 0000000000..1ad145629f
--- /dev/null
+++ b/spec/ruby/library/net-http/httpheader/each_key_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+require_relative 'shared/each_name'
+
+describe "Net::HTTPHeader#each_key" do
+ it_behaves_like :net_httpheader_each_name, :each_key
+end
diff --git a/spec/ruby/library/net-http/httpheader/each_name_spec.rb b/spec/ruby/library/net-http/httpheader/each_name_spec.rb
new file mode 100644
index 0000000000..f819bd989d
--- /dev/null
+++ b/spec/ruby/library/net-http/httpheader/each_name_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+require_relative 'shared/each_name'
+
+describe "Net::HTTPHeader#each_name" do
+ it_behaves_like :net_httpheader_each_name, :each_name
+end
diff --git a/spec/ruby/library/net-http/httpheader/each_spec.rb b/spec/ruby/library/net-http/httpheader/each_spec.rb
new file mode 100644
index 0000000000..ff37249d0a
--- /dev/null
+++ b/spec/ruby/library/net-http/httpheader/each_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+require_relative 'shared/each_header'
+
+describe "Net::HTTPHeader#each" do
+ it_behaves_like :net_httpheader_each_header, :each
+end
diff --git a/spec/ruby/library/net-http/httpheader/each_value_spec.rb b/spec/ruby/library/net-http/httpheader/each_value_spec.rb
new file mode 100644
index 0000000000..b71df58c65
--- /dev/null
+++ b/spec/ruby/library/net-http/httpheader/each_value_spec.rb
@@ -0,0 +1,35 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+
+describe "Net::HTTPHeader#each_value" do
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ @headers["My-Header"] = "test"
+ @headers.add_field("My-Other-Header", "a")
+ @headers.add_field("My-Other-Header", "b")
+ end
+
+ describe "when passed a block" do
+ it "yields each header entry's joined values" do
+ res = []
+ @headers.each_value do |value|
+ res << value
+ end
+ res.sort.should == ["a, b", "test"]
+ end
+ end
+
+ describe "when passed no block" do
+ it "returns an Enumerator" do
+ enumerator = @headers.each_value
+ enumerator.should be_an_instance_of(Enumerator)
+
+ res = []
+ enumerator.each do |key|
+ res << key
+ end
+ res.sort.should == ["a, b", "test"]
+ end
+ end
+end
diff --git a/spec/ruby/library/net-http/httpheader/element_reference_spec.rb b/spec/ruby/library/net-http/httpheader/element_reference_spec.rb
new file mode 100644
index 0000000000..1003c41af9
--- /dev/null
+++ b/spec/ruby/library/net-http/httpheader/element_reference_spec.rb
@@ -0,0 +1,39 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+
+describe "Net::HTTPHeader#[] when passed key" do
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ end
+
+ it "returns the value of the header entry with the passed key" do
+ @headers["My-Header"] = "test"
+ @headers["My-Header"].should == "test"
+ @headers["My-Other-Header"] = "another test"
+ @headers["My-Other-Header"].should == "another test"
+ end
+
+ it "is case-insensitive" do
+ @headers["My-Header"] = "test"
+
+ @headers['My-Header'].should == "test"
+ @headers['my-Header'].should == "test"
+ @headers['My-header'].should == "test"
+ @headers['my-header'].should == "test"
+ @headers['MY-HEADER'].should == "test"
+ end
+
+ it "returns multi-element values joined together" do
+ @headers["My-Header"] = "test"
+ @headers.add_field("My-Header", "another test")
+ @headers.add_field("My-Header", "and one more")
+
+ @headers["My-Header"].should == "test, another test, and one more"
+ end
+
+ it "returns nil for non-existing entries" do
+ @headers["My-Header"].should be_nil
+ @headers["My-Other-Header"].should be_nil
+ end
+end
diff --git a/spec/ruby/library/net-http/httpheader/element_set_spec.rb b/spec/ruby/library/net-http/httpheader/element_set_spec.rb
new file mode 100644
index 0000000000..376df2f977
--- /dev/null
+++ b/spec/ruby/library/net-http/httpheader/element_set_spec.rb
@@ -0,0 +1,41 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+
+describe "Net::HTTPHeader#[]= when passed key, value" do
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ end
+
+ it "sets the header entry with the passed key to the passed value" do
+ @headers["My-Header"] = "test"
+ @headers["My-Header"].should == "test"
+
+ @headers["My-Header"] = "overwritten"
+ @headers["My-Header"].should == "overwritten"
+
+ @headers["My-Other-Header"] = "another test"
+ @headers["My-Other-Header"].should == "another test"
+ end
+
+ it "is case-insensitive" do
+ @headers['My-Header'] = "test"
+ @headers['my-Header'] = "another test"
+ @headers['My-header'] = "and one more test"
+ @headers['my-header'] = "and another one"
+ @headers['MY-HEADER'] = "last one"
+
+ @headers["My-Header"].should == "last one"
+ @headers.size.should eql(1)
+ end
+
+ it "removes the header entry with the passed key when the value is false or nil" do
+ @headers['My-Header'] = "test"
+ @headers['My-Header'] = nil
+ @headers['My-Header'].should be_nil
+
+ @headers['My-Header'] = "test"
+ @headers['My-Header'] = false
+ @headers['My-Header'].should be_nil
+ end
+end
diff --git a/spec/ruby/library/net-http/httpheader/fetch_spec.rb b/spec/ruby/library/net-http/httpheader/fetch_spec.rb
new file mode 100644
index 0000000000..58c69c0377
--- /dev/null
+++ b/spec/ruby/library/net-http/httpheader/fetch_spec.rb
@@ -0,0 +1,68 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+
+describe "Net::HTTPHeader#fetch" do
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ end
+
+ describe "when passed key" do
+ it "returns the header entry for the passed key" do
+ @headers["My-Header"] = "test"
+ @headers.fetch("My-Header").should == "test"
+
+ @headers.add_field("My-Other-Header", "a")
+ @headers.add_field("My-Other-Header", "b")
+ @headers.add_field("My-Other-Header", "c")
+ @headers.fetch("My-Other-Header").should == "a, b, c"
+ end
+
+ it "is case-insensitive" do
+ @headers["My-Header"] = "test"
+ @headers.fetch("my-header").should == "test"
+ @headers.fetch("MY-HEADER").should == "test"
+ end
+
+ it "returns nil when there is no entry for the passed key" do
+ -> { @headers.fetch("my-header") }.should raise_error(IndexError)
+ end
+ end
+
+ describe "when passed key, default" do
+ it "returns the header entry for the passed key" do
+ @headers["My-Header"] = "test"
+ @headers.fetch("My-Header", "bla").should == "test"
+
+ @headers.add_field("My-Other-Header", "a")
+ @headers.add_field("My-Other-Header", "b")
+ @headers.add_field("My-Other-Header", "c")
+ @headers.fetch("My-Other-Header", "bla").should == "a, b, c"
+ end
+
+ # TODO: This raises a NoMethodError: undefined method `join' for "bla":String
+ it "returns the default value when there is no entry for the passed key" do
+ @headers.fetch("My-Header", "bla").should == "bla"
+ end
+ end
+
+ describe "when passed key and block" do
+ it "returns the header entry for the passed key" do
+ @headers["My-Header"] = "test"
+ @headers.fetch("My-Header") {}.should == "test"
+
+ @headers.add_field("My-Other-Header", "a")
+ @headers.add_field("My-Other-Header", "b")
+ @headers.add_field("My-Other-Header", "c")
+ -> {
+ @result = @headers.fetch("My-Other-Header", "bla") {}
+ }.should complain(/block supersedes default value argument/)
+ @result.should == "a, b, c"
+ end
+
+ # TODO: This raises a NoMethodError: undefined method `join' for "redaeh-ym":String
+ it "yieldsand returns the block's return value when there is no entry for the passed key" do
+ @headers.fetch("My-Header") { |key| key.reverse }.should == "redaeh-ym"
+ end
+ end
+end
diff --git a/spec/ruby/library/net/http/httpheader/fixtures/classes.rb b/spec/ruby/library/net-http/httpheader/fixtures/classes.rb
index b5ec6abd75..b5ec6abd75 100644
--- a/spec/ruby/library/net/http/httpheader/fixtures/classes.rb
+++ b/spec/ruby/library/net-http/httpheader/fixtures/classes.rb
diff --git a/spec/ruby/library/net-http/httpheader/form_data_spec.rb b/spec/ruby/library/net-http/httpheader/form_data_spec.rb
new file mode 100644
index 0000000000..acd913f53a
--- /dev/null
+++ b/spec/ruby/library/net-http/httpheader/form_data_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+require_relative 'shared/set_form_data'
+
+describe "Net::HTTPHeader#form_data=" do
+ it_behaves_like :net_httpheader_set_form_data, :form_data=
+end
diff --git a/spec/ruby/library/net-http/httpheader/get_fields_spec.rb b/spec/ruby/library/net-http/httpheader/get_fields_spec.rb
new file mode 100644
index 0000000000..0278bcede2
--- /dev/null
+++ b/spec/ruby/library/net-http/httpheader/get_fields_spec.rb
@@ -0,0 +1,39 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+
+describe "Net::HTTPHeader#get_fields when passed key" do
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ end
+
+ it "returns an Array containing the values of the header entry with the passed key" do
+ @headers["My-Header"] = "a"
+ @headers.get_fields("My-Header").should == ["a"]
+
+ @headers.add_field("My-Header", "b")
+ @headers.get_fields("My-Header").should == ["a", "b"]
+ end
+
+ it "returns a copy of the header entry values" do
+ @headers["My-Header"] = "a"
+
+ @headers.get_fields("My-Header").clear
+ @headers.get_fields("My-Header").should == ["a"]
+
+ @headers.get_fields("My-Header") << "b"
+ @headers.get_fields("My-Header").should == ["a"]
+ end
+
+ it "returns nil for non-existing header entries" do
+ @headers.get_fields("My-Header").should be_nil
+ @headers.get_fields("My-Other-header").should be_nil
+ end
+
+ it "is case-insensitive" do
+ @headers["My-Header"] = "test"
+ @headers.get_fields("My-Header").should == ["test"]
+ @headers.get_fields("my-header").should == ["test"]
+ @headers.get_fields("MY-HEADER").should == ["test"]
+ end
+end
diff --git a/spec/ruby/library/net-http/httpheader/initialize_http_header_spec.rb b/spec/ruby/library/net-http/httpheader/initialize_http_header_spec.rb
new file mode 100644
index 0000000000..f9e6d208e5
--- /dev/null
+++ b/spec/ruby/library/net-http/httpheader/initialize_http_header_spec.rb
@@ -0,0 +1,21 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+
+describe "Net::HTTPHeader#initialize_http_header when passed Hash" do
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.allocate
+ end
+
+ it "initializes the HTTP Header using the passed Hash" do
+ @headers.initialize_http_header("My-Header" => "test", "My-Other-Header" => "another test")
+ @headers["My-Header"].should == "test"
+ @headers["My-Other-Header"].should == "another test"
+ end
+
+ it "complains about duplicate keys when in verbose mode" do
+ -> do
+ @headers.initialize_http_header("My-Header" => "test", "my-header" => "another test")
+ end.should complain(/duplicated HTTP header/, verbose: true)
+ end
+end
diff --git a/spec/ruby/library/net-http/httpheader/key_spec.rb b/spec/ruby/library/net-http/httpheader/key_spec.rb
new file mode 100644
index 0000000000..2b7aeb9c2a
--- /dev/null
+++ b/spec/ruby/library/net-http/httpheader/key_spec.rb
@@ -0,0 +1,21 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+
+describe "Net::HTTPHeader#key? when passed key" do
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ end
+
+ it "returns true if the header entry with the passed key exists" do
+ @headers.key?("My-Header").should be_false
+ @headers["My-Header"] = "test"
+ @headers.key?("My-Header").should be_true
+ end
+
+ it "is case-insensitive" do
+ @headers["My-Header"] = "test"
+ @headers.key?("my-header").should be_true
+ @headers.key?("MY-HEADER").should be_true
+ end
+end
diff --git a/spec/ruby/library/net-http/httpheader/length_spec.rb b/spec/ruby/library/net-http/httpheader/length_spec.rb
new file mode 100644
index 0000000000..57e32742e4
--- /dev/null
+++ b/spec/ruby/library/net-http/httpheader/length_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+require_relative 'shared/size'
+
+describe "Net::HTTPHeader#length" do
+ it_behaves_like :net_httpheader_size, :length
+end
diff --git a/spec/ruby/library/net-http/httpheader/main_type_spec.rb b/spec/ruby/library/net-http/httpheader/main_type_spec.rb
new file mode 100644
index 0000000000..4dd551d8f4
--- /dev/null
+++ b/spec/ruby/library/net-http/httpheader/main_type_spec.rb
@@ -0,0 +1,24 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+
+describe "Net::HTTPHeader#main_type" do
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ end
+
+ it "returns the 'main-content-type', as per 'Content-Type' header entry" do
+ @headers["Content-Type"] = "text/html"
+ @headers.main_type.should == "text"
+
+ @headers["Content-Type"] = "application/pdf"
+ @headers.main_type.should == "application"
+
+ @headers["Content-Type"] = "text/html;charset=utf-8"
+ @headers.main_type.should == "text"
+ end
+
+ it "returns nil if the 'Content-Type' header entry does not exist" do
+ @headers.main_type.should be_nil
+ end
+end
diff --git a/spec/ruby/library/net-http/httpheader/proxy_basic_auth_spec.rb b/spec/ruby/library/net-http/httpheader/proxy_basic_auth_spec.rb
new file mode 100644
index 0000000000..d9f6afc5a7
--- /dev/null
+++ b/spec/ruby/library/net-http/httpheader/proxy_basic_auth_spec.rb
@@ -0,0 +1,14 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+
+describe "Net::HTTPHeader#proxy_basic_auth when passed account, password" do
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ end
+
+ it "sets the 'Proxy-Authorization' Header entry for basic authorization" do
+ @headers.proxy_basic_auth("rubyspec", "rocks")
+ @headers["Proxy-Authorization"].should == "Basic cnVieXNwZWM6cm9ja3M="
+ end
+end
diff --git a/spec/ruby/library/net-http/httpheader/range_length_spec.rb b/spec/ruby/library/net-http/httpheader/range_length_spec.rb
new file mode 100644
index 0000000000..77323ac872
--- /dev/null
+++ b/spec/ruby/library/net-http/httpheader/range_length_spec.rb
@@ -0,0 +1,32 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+
+describe "Net::HTTPHeader#range_length" do
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ end
+
+ it "returns the length of the Range represented by the 'Content-Range' header entry" do
+ @headers["Content-Range"] = "bytes 0-499/1234"
+ @headers.range_length.should eql(500)
+
+ @headers["Content-Range"] = "bytes 500-1233/1234"
+ @headers.range_length.should eql(734)
+ end
+
+ it "returns nil when there is no 'Content-Range' header entry" do
+ @headers.range_length.should be_nil
+ end
+
+ it "raises a Net::HTTPHeaderSyntaxError when the 'Content-Range' has an invalid format" do
+ @headers["Content-Range"] = "invalid"
+ -> { @headers.range_length }.should raise_error(Net::HTTPHeaderSyntaxError)
+
+ @headers["Content-Range"] = "bytes 123-abc"
+ -> { @headers.range_length }.should raise_error(Net::HTTPHeaderSyntaxError)
+
+ @headers["Content-Range"] = "bytes abc-123"
+ -> { @headers.range_length }.should raise_error(Net::HTTPHeaderSyntaxError)
+ end
+end
diff --git a/spec/ruby/library/net-http/httpheader/range_spec.rb b/spec/ruby/library/net-http/httpheader/range_spec.rb
new file mode 100644
index 0000000000..2de80a825e
--- /dev/null
+++ b/spec/ruby/library/net-http/httpheader/range_spec.rb
@@ -0,0 +1,48 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+require_relative 'shared/set_range'
+
+describe "Net::HTTPHeader#range" do
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ end
+
+ it "returns a Range object that represents the 'Range' header entry" do
+ @headers["Range"] = "bytes=0-499"
+ @headers.range.should == [0..499]
+
+ @headers["Range"] = "bytes=500-1233"
+ @headers.range.should == [500..1233]
+
+ @headers["Range"] = "bytes=10-"
+ @headers.range.should == [10..-1]
+
+ @headers["Range"] = "bytes=-10"
+ @headers.range.should == [-10..-1]
+ end
+
+ it "returns nil when there is no 'Range' header entry" do
+ @headers.range.should be_nil
+ end
+
+ it "raises a Net::HTTPHeaderSyntaxError when the 'Range' has an invalid format" do
+ @headers["Range"] = "invalid"
+ -> { @headers.range }.should raise_error(Net::HTTPHeaderSyntaxError)
+
+ @headers["Range"] = "bytes 123-abc"
+ -> { @headers.range }.should raise_error(Net::HTTPHeaderSyntaxError)
+
+ @headers["Range"] = "bytes abc-123"
+ -> { @headers.range }.should raise_error(Net::HTTPHeaderSyntaxError)
+ end
+
+ it "raises a Net::HTTPHeaderSyntaxError when the 'Range' was not specified" do
+ @headers["Range"] = "bytes=-"
+ -> { @headers.range }.should raise_error(Net::HTTPHeaderSyntaxError)
+ end
+end
+
+describe "Net::HTTPHeader#range=" do
+ it_behaves_like :net_httpheader_set_range, :range=
+end
diff --git a/spec/ruby/library/net-http/httpheader/set_content_type_spec.rb b/spec/ruby/library/net-http/httpheader/set_content_type_spec.rb
new file mode 100644
index 0000000000..7ec4f90b8e
--- /dev/null
+++ b/spec/ruby/library/net-http/httpheader/set_content_type_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+require_relative 'shared/set_content_type'
+
+describe "Net::HTTPHeader#set_content_type" do
+ it_behaves_like :net_httpheader_set_content_type, :set_content_type
+end
diff --git a/spec/ruby/library/net-http/httpheader/set_form_data_spec.rb b/spec/ruby/library/net-http/httpheader/set_form_data_spec.rb
new file mode 100644
index 0000000000..7aac19f045
--- /dev/null
+++ b/spec/ruby/library/net-http/httpheader/set_form_data_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+require_relative 'shared/set_form_data'
+
+describe "Net::HTTPHeader#set_form_data" do
+ it_behaves_like :net_httpheader_set_form_data, :set_form_data
+end
diff --git a/spec/ruby/library/net-http/httpheader/set_range_spec.rb b/spec/ruby/library/net-http/httpheader/set_range_spec.rb
new file mode 100644
index 0000000000..0f98de55e6
--- /dev/null
+++ b/spec/ruby/library/net-http/httpheader/set_range_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+require_relative 'shared/set_range'
+
+describe "Net::HTTPHeader#set_range" do
+ it_behaves_like :net_httpheader_set_range, :set_range
+end
diff --git a/spec/ruby/library/net/http/httpheader/shared/each_capitalized.rb b/spec/ruby/library/net-http/httpheader/shared/each_capitalized.rb
index 3bac409876..3bac409876 100644
--- a/spec/ruby/library/net/http/httpheader/shared/each_capitalized.rb
+++ b/spec/ruby/library/net-http/httpheader/shared/each_capitalized.rb
diff --git a/spec/ruby/library/net/http/httpheader/shared/each_header.rb b/spec/ruby/library/net-http/httpheader/shared/each_header.rb
index 6bf3a6ddfe..6bf3a6ddfe 100644
--- a/spec/ruby/library/net/http/httpheader/shared/each_header.rb
+++ b/spec/ruby/library/net-http/httpheader/shared/each_header.rb
diff --git a/spec/ruby/library/net/http/httpheader/shared/each_name.rb b/spec/ruby/library/net-http/httpheader/shared/each_name.rb
index efc6a09dfd..efc6a09dfd 100644
--- a/spec/ruby/library/net/http/httpheader/shared/each_name.rb
+++ b/spec/ruby/library/net-http/httpheader/shared/each_name.rb
diff --git a/spec/ruby/library/net/http/httpheader/shared/set_content_type.rb b/spec/ruby/library/net-http/httpheader/shared/set_content_type.rb
index b7359bdca6..b7359bdca6 100644
--- a/spec/ruby/library/net/http/httpheader/shared/set_content_type.rb
+++ b/spec/ruby/library/net-http/httpheader/shared/set_content_type.rb
diff --git a/spec/ruby/library/net/http/httpheader/shared/set_form_data.rb b/spec/ruby/library/net-http/httpheader/shared/set_form_data.rb
index db20b18803..db20b18803 100644
--- a/spec/ruby/library/net/http/httpheader/shared/set_form_data.rb
+++ b/spec/ruby/library/net-http/httpheader/shared/set_form_data.rb
diff --git a/spec/ruby/library/net/http/httpheader/shared/set_range.rb b/spec/ruby/library/net-http/httpheader/shared/set_range.rb
index 87f51d46f3..87f51d46f3 100644
--- a/spec/ruby/library/net/http/httpheader/shared/set_range.rb
+++ b/spec/ruby/library/net-http/httpheader/shared/set_range.rb
diff --git a/spec/ruby/library/net/http/httpheader/shared/size.rb b/spec/ruby/library/net-http/httpheader/shared/size.rb
index e2b1e4c22b..e2b1e4c22b 100644
--- a/spec/ruby/library/net/http/httpheader/shared/size.rb
+++ b/spec/ruby/library/net-http/httpheader/shared/size.rb
diff --git a/spec/ruby/library/net-http/httpheader/size_spec.rb b/spec/ruby/library/net-http/httpheader/size_spec.rb
new file mode 100644
index 0000000000..210060ce21
--- /dev/null
+++ b/spec/ruby/library/net-http/httpheader/size_spec.rb
@@ -0,0 +1,8 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+require_relative 'shared/size'
+
+describe "Net::HTTPHeader#size" do
+ it_behaves_like :net_httpheader_size, :size
+end
diff --git a/spec/ruby/library/net-http/httpheader/sub_type_spec.rb b/spec/ruby/library/net-http/httpheader/sub_type_spec.rb
new file mode 100644
index 0000000000..b39b57fe8d
--- /dev/null
+++ b/spec/ruby/library/net-http/httpheader/sub_type_spec.rb
@@ -0,0 +1,32 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+
+describe "Net::HTTPHeader#sub_type" do
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ end
+
+ it "returns the 'sub-content-type', as per 'Content-Type' header entry" do
+ @headers["Content-Type"] = "text/html"
+ @headers.sub_type.should == "html"
+
+ @headers["Content-Type"] = "application/pdf"
+ @headers.sub_type.should == "pdf"
+
+ @headers["Content-Type"] = "text/html;charset=utf-8"
+ @headers.sub_type.should == "html"
+ end
+
+ it "returns nil if no 'sub-content-type' is set" do
+ @headers["Content-Type"] = "text"
+ @headers.sub_type.should be_nil
+
+ @headers["Content-Type"] = "text;charset=utf-8"
+ @headers.sub_type.should be_nil
+ end
+
+ it "returns nil if the 'Content-Type' header entry does not exist" do
+ @headers.sub_type.should be_nil
+ end
+end
diff --git a/spec/ruby/library/net-http/httpheader/to_hash_spec.rb b/spec/ruby/library/net-http/httpheader/to_hash_spec.rb
new file mode 100644
index 0000000000..3cebc519a6
--- /dev/null
+++ b/spec/ruby/library/net-http/httpheader/to_hash_spec.rb
@@ -0,0 +1,25 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+
+describe "Net::HTTPHeader#to_hash" do
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ end
+
+ it "returns a Hash representing all Header entries (keys in lower case, values as arrays)" do
+ @headers.to_hash.should == {}
+
+ @headers["My-Header"] = "test"
+ @headers.to_hash.should == { "my-header" => ["test"] }
+
+ @headers.add_field("My-Header", "another test")
+ @headers.to_hash.should == { "my-header" => ["test", "another test"] }
+ end
+
+ it "does not allow modifying the headers from the returned hash" do
+ @headers.to_hash["my-header"] = ["test"]
+ @headers.to_hash.should == {}
+ @headers.key?("my-header").should be_false
+ end
+end
diff --git a/spec/ruby/library/net-http/httpheader/type_params_spec.rb b/spec/ruby/library/net-http/httpheader/type_params_spec.rb
new file mode 100644
index 0000000000..ac97e2b48c
--- /dev/null
+++ b/spec/ruby/library/net-http/httpheader/type_params_spec.rb
@@ -0,0 +1,24 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'fixtures/classes'
+
+describe "Net::HTTPHeader#type_params" do
+ before :each do
+ @headers = NetHTTPHeaderSpecs::Example.new
+ end
+
+ it "returns additional 'Content-Type' information as a Hash" do
+ @headers["Content-Type"] = "text/html;charset=utf-8"
+ @headers.type_params.should == {"charset" => "utf-8"}
+
+ @headers["Content-Type"] = "text/html; charset=utf-8; rubyspec=rocks"
+ @headers.type_params.should == {"charset" => "utf-8", "rubyspec" => "rocks"}
+ end
+
+ it "returns an empty Hash when no additional 'Content-Type' information is set" do
+ @headers.type_params.should == {}
+
+ @headers["Content-Type"] = "text/html"
+ @headers.type_params.should == {}
+ end
+end
diff --git a/spec/ruby/library/net-http/httprequest/initialize_spec.rb b/spec/ruby/library/net-http/httprequest/initialize_spec.rb
new file mode 100644
index 0000000000..d009a00ed2
--- /dev/null
+++ b/spec/ruby/library/net-http/httprequest/initialize_spec.rb
@@ -0,0 +1,45 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+module NetHTTPRequestSpecs
+ class TestRequest < Net::HTTPRequest
+ METHOD = "TEST"
+ REQUEST_HAS_BODY = false
+ RESPONSE_HAS_BODY = true
+ end
+end
+
+describe "Net::HTTPRequest#initialize" do
+ before :each do
+ @req = NetHTTPRequestSpecs::TestRequest.allocate
+ end
+
+ it "uses the METHOD constants to set the request method" do
+ @req.send(:initialize, "/some/path")
+ @req.method.should == "TEST"
+ end
+
+ it "uses the REQUEST_HAS_BODY to set whether the Request has a body or not" do
+ @req.send(:initialize, "/some/path")
+ @req.request_body_permitted?.should be_false
+ end
+
+ it "uses the RESPONSE_HAS_BODY to set whether the Response can have a body or not" do
+ @req.send(:initialize, "/some/path")
+ @req.response_body_permitted?.should be_true
+ end
+
+ describe "when passed path" do
+ it "sets self's path to the passed path" do
+ @req.send(:initialize, "/some/path")
+ @req.path.should == "/some/path"
+ end
+ end
+
+ describe "when passed path, headers" do
+ it "uses the passed headers Hash to initialize self's header entries" do
+ @req.send(:initialize, "/some/path", "Content-Type" => "text/html")
+ @req["Content-Type"].should == "text/html"
+ end
+ end
+end
diff --git a/spec/ruby/library/net-http/httpresponse/body_permitted_spec.rb b/spec/ruby/library/net-http/httpresponse/body_permitted_spec.rb
new file mode 100644
index 0000000000..68965de4a1
--- /dev/null
+++ b/spec/ruby/library/net-http/httpresponse/body_permitted_spec.rb
@@ -0,0 +1,13 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPResponse.body_permitted?" do
+ it "returns true if this response type can have a response body" do
+ Net::HTTPUnknownResponse.should.body_permitted?
+ Net::HTTPInformation.should_not.body_permitted?
+ Net::HTTPSuccess.should.body_permitted?
+ Net::HTTPRedirection.should.body_permitted?
+ Net::HTTPClientError.should.body_permitted?
+ Net::HTTPServerError.should.body_permitted?
+ end
+end
diff --git a/spec/ruby/library/net-http/httpresponse/body_spec.rb b/spec/ruby/library/net-http/httpresponse/body_spec.rb
new file mode 100644
index 0000000000..ddfcd834c4
--- /dev/null
+++ b/spec/ruby/library/net-http/httpresponse/body_spec.rb
@@ -0,0 +1,7 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'shared/body'
+
+describe "Net::HTTPResponse#body" do
+ it_behaves_like :net_httpresponse_body, :body
+end
diff --git a/spec/ruby/library/net-http/httpresponse/code_spec.rb b/spec/ruby/library/net-http/httpresponse/code_spec.rb
new file mode 100644
index 0000000000..699062ad97
--- /dev/null
+++ b/spec/ruby/library/net-http/httpresponse/code_spec.rb
@@ -0,0 +1,24 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPResponse#code" do
+ it "returns the result code string" do
+ res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
+ res.code.should == "???"
+
+ res = Net::HTTPInformation.new("1.0", "1xx", "test response")
+ res.code.should == "1xx"
+
+ res = Net::HTTPSuccess.new("1.0", "2xx", "test response")
+ res.code.should == "2xx"
+
+ res = Net::HTTPRedirection.new("1.0", "3xx", "test response")
+ res.code.should == "3xx"
+
+ res = Net::HTTPClientError.new("1.0", "4xx", "test response")
+ res.code.should == "4xx"
+
+ res = Net::HTTPServerError.new("1.0", "5xx", "test response")
+ res.code.should == "5xx"
+ end
+end
diff --git a/spec/ruby/library/net-http/httpresponse/code_type_spec.rb b/spec/ruby/library/net-http/httpresponse/code_type_spec.rb
new file mode 100644
index 0000000000..beb661cbbe
--- /dev/null
+++ b/spec/ruby/library/net-http/httpresponse/code_type_spec.rb
@@ -0,0 +1,24 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPResponse#code_type" do
+ it "returns self's class" do
+ res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
+ res.code_type.should == Net::HTTPUnknownResponse
+
+ res = Net::HTTPInformation.new("1.0", "1xx", "test response")
+ res.code_type.should == Net::HTTPInformation
+
+ res = Net::HTTPSuccess.new("1.0", "2xx", "test response")
+ res.code_type.should == Net::HTTPSuccess
+
+ res = Net::HTTPRedirection.new("1.0", "3xx", "test response")
+ res.code_type.should == Net::HTTPRedirection
+
+ res = Net::HTTPClientError.new("1.0", "4xx", "test response")
+ res.code_type.should == Net::HTTPClientError
+
+ res = Net::HTTPServerError.new("1.0", "5xx", "test response")
+ res.code_type.should == Net::HTTPServerError
+ end
+end
diff --git a/spec/ruby/library/net-http/httpresponse/entity_spec.rb b/spec/ruby/library/net-http/httpresponse/entity_spec.rb
new file mode 100644
index 0000000000..ca8c4b29c0
--- /dev/null
+++ b/spec/ruby/library/net-http/httpresponse/entity_spec.rb
@@ -0,0 +1,7 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require_relative 'shared/body'
+
+describe "Net::HTTPResponse#entity" do
+ it_behaves_like :net_httpresponse_body, :entity
+end
diff --git a/spec/ruby/library/net-http/httpresponse/error_spec.rb b/spec/ruby/library/net-http/httpresponse/error_spec.rb
new file mode 100644
index 0000000000..6ced90fa23
--- /dev/null
+++ b/spec/ruby/library/net-http/httpresponse/error_spec.rb
@@ -0,0 +1,24 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPResponse#error!" do
+ it "raises self's class 'EXCEPTION_TYPE' Exception" do
+ res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
+ -> { res.error! }.should raise_error(Net::HTTPError)
+
+ res = Net::HTTPInformation.new("1.0", "1xx", "test response")
+ -> { res.error! }.should raise_error(Net::HTTPError)
+
+ res = Net::HTTPSuccess.new("1.0", "2xx", "test response")
+ -> { res.error! }.should raise_error(Net::HTTPError)
+
+ res = Net::HTTPRedirection.new("1.0", "3xx", "test response")
+ -> { res.error! }.should raise_error(Net::HTTPRetriableError)
+
+ res = Net::HTTPClientError.new("1.0", "4xx", "test response")
+ -> { res.error! }.should raise_error(Net::HTTPClientException)
+
+ res = Net::HTTPServerError.new("1.0", "5xx", "test response")
+ -> { res.error! }.should raise_error(Net::HTTPFatalError)
+ end
+end
diff --git a/spec/ruby/library/net-http/httpresponse/error_type_spec.rb b/spec/ruby/library/net-http/httpresponse/error_type_spec.rb
new file mode 100644
index 0000000000..3969621a5e
--- /dev/null
+++ b/spec/ruby/library/net-http/httpresponse/error_type_spec.rb
@@ -0,0 +1,24 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPResponse#error_type" do
+ it "returns self's class 'EXCEPTION_TYPE' constant" do
+ res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
+ res.error_type.should == Net::HTTPError
+
+ res = Net::HTTPInformation.new("1.0", "1xx", "test response")
+ res.error_type.should == Net::HTTPError
+
+ res = Net::HTTPSuccess.new("1.0", "2xx", "test response")
+ res.error_type.should == Net::HTTPError
+
+ res = Net::HTTPRedirection.new("1.0", "3xx", "test response")
+ res.error_type.should == Net::HTTPRetriableError
+
+ res = Net::HTTPClientError.new("1.0", "4xx", "test response")
+ res.error_type.should == Net::HTTPClientException
+
+ res = Net::HTTPServerError.new("1.0", "5xx", "test response")
+ res.error_type.should == Net::HTTPFatalError
+ end
+end
diff --git a/spec/ruby/library/net-http/httpresponse/exception_type_spec.rb b/spec/ruby/library/net-http/httpresponse/exception_type_spec.rb
new file mode 100644
index 0000000000..dd2761a744
--- /dev/null
+++ b/spec/ruby/library/net-http/httpresponse/exception_type_spec.rb
@@ -0,0 +1,13 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPResponse.exception_type" do
+ it "returns self's 'EXCEPTION_TYPE' constant" do
+ Net::HTTPUnknownResponse.exception_type.should == Net::HTTPError
+ Net::HTTPInformation.exception_type.should == Net::HTTPError
+ Net::HTTPSuccess.exception_type.should == Net::HTTPError
+ Net::HTTPRedirection.exception_type.should == Net::HTTPRetriableError
+ Net::HTTPClientError.exception_type.should == Net::HTTPClientException
+ Net::HTTPServerError.exception_type.should == Net::HTTPFatalError
+ end
+end
diff --git a/spec/ruby/library/net-http/httpresponse/header_spec.rb b/spec/ruby/library/net-http/httpresponse/header_spec.rb
new file mode 100644
index 0000000000..a403dbd2c3
--- /dev/null
+++ b/spec/ruby/library/net-http/httpresponse/header_spec.rb
@@ -0,0 +1,9 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPResponse#header" do
+ it "returns self" do
+ res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
+ res.response.should equal(res)
+ end
+end
diff --git a/spec/ruby/library/net-http/httpresponse/http_version_spec.rb b/spec/ruby/library/net-http/httpresponse/http_version_spec.rb
new file mode 100644
index 0000000000..a3e413a360
--- /dev/null
+++ b/spec/ruby/library/net-http/httpresponse/http_version_spec.rb
@@ -0,0 +1,12 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPResponse#http_version" do
+ it "returns self's http version" do
+ res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
+ res.http_version.should == "1.0"
+
+ res = Net::HTTPUnknownResponse.new("1.1", "???", "test response")
+ res.http_version.should == "1.1"
+ end
+end
diff --git a/spec/ruby/library/net-http/httpresponse/initialize_spec.rb b/spec/ruby/library/net-http/httpresponse/initialize_spec.rb
new file mode 100644
index 0000000000..673c11a245
--- /dev/null
+++ b/spec/ruby/library/net-http/httpresponse/initialize_spec.rb
@@ -0,0 +1,11 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPResponse#initialize when passed http_version, response_code, response_message" do
+ it "sets self http_version, response_code and response_message to the passed values" do
+ res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
+ res.http_version.should == "1.0"
+ res.code.should == "???"
+ res.message.should == "test response"
+ end
+end
diff --git a/spec/ruby/library/net-http/httpresponse/inspect_spec.rb b/spec/ruby/library/net-http/httpresponse/inspect_spec.rb
new file mode 100644
index 0000000000..43071ec8cd
--- /dev/null
+++ b/spec/ruby/library/net-http/httpresponse/inspect_spec.rb
@@ -0,0 +1,15 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require "stringio"
+
+describe "Net::HTTPResponse#inspect" do
+ it "returns a String representation of self" do
+ res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
+ res.inspect.should == "#<Net::HTTPUnknownResponse ??? test response readbody=false>"
+
+ res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
+ socket = Net::BufferedIO.new(StringIO.new("test body"))
+ res.reading_body(socket, true) {}
+ res.inspect.should == "#<Net::HTTPUnknownResponse ??? test response readbody=true>"
+ end
+end
diff --git a/spec/ruby/library/net-http/httpresponse/message_spec.rb b/spec/ruby/library/net-http/httpresponse/message_spec.rb
new file mode 100644
index 0000000000..5ba73bb449
--- /dev/null
+++ b/spec/ruby/library/net-http/httpresponse/message_spec.rb
@@ -0,0 +1,9 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPResponse#message" do
+ it "returns self's response message" do
+ res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
+ res.message.should == "test response"
+ end
+end
diff --git a/spec/ruby/library/net-http/httpresponse/msg_spec.rb b/spec/ruby/library/net-http/httpresponse/msg_spec.rb
new file mode 100644
index 0000000000..04f5836d7a
--- /dev/null
+++ b/spec/ruby/library/net-http/httpresponse/msg_spec.rb
@@ -0,0 +1,9 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPResponse#msg" do
+ it "returns self's response message" do
+ res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
+ res.message.should == "test response"
+ end
+end
diff --git a/spec/ruby/library/net-http/httpresponse/read_body_spec.rb b/spec/ruby/library/net-http/httpresponse/read_body_spec.rb
new file mode 100644
index 0000000000..4530a26bfc
--- /dev/null
+++ b/spec/ruby/library/net-http/httpresponse/read_body_spec.rb
@@ -0,0 +1,86 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require 'stringio'
+
+describe "Net::HTTPResponse#read_body" do
+ before :each do
+ @res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
+ @socket = Net::BufferedIO.new(StringIO.new("test body"))
+ end
+
+ describe "when passed no arguments" do
+ it "returns the read body" do
+ @res.reading_body(@socket, true) do
+ @res.read_body.should == "test body"
+ end
+ end
+
+ it "returns the previously read body if called a second time" do
+ @res.reading_body(@socket, true) do
+ @res.read_body.should equal(@res.read_body)
+ end
+ end
+ end
+
+ describe "when passed a buffer" do
+ it "reads the body to the passed buffer" do
+ @res.reading_body(@socket, true) do
+ buffer = +""
+ @res.read_body(buffer)
+ buffer.should == "test body"
+ end
+ end
+
+ it "returns the passed buffer" do
+ @res.reading_body(@socket, true) do
+ buffer = +""
+ @res.read_body(buffer).should equal(buffer)
+ end
+ end
+
+ it "raises an IOError if called a second time" do
+ @res.reading_body(@socket, true) do
+ @res.read_body(+"")
+ -> { @res.read_body(+"") }.should raise_error(IOError)
+ end
+ end
+ end
+
+ describe "when passed a block" do
+ it "reads the body and yields it to the passed block (in chunks)" do
+ @res.reading_body(@socket, true) do
+ yielded = false
+
+ buffer = +""
+ @res.read_body do |body|
+ yielded = true
+ buffer << body
+ end
+
+ yielded.should be_true
+ buffer.should == "test body"
+ end
+ end
+
+ it "returns the ReadAdapter" do
+ @res.reading_body(@socket, true) do
+ @res.read_body { nil }.should be_kind_of(Net::ReadAdapter)
+ end
+ end
+
+ it "raises an IOError if called a second time" do
+ @res.reading_body(@socket, true) do
+ @res.read_body {}
+ -> { @res.read_body {} }.should raise_error(IOError)
+ end
+ end
+ end
+
+ describe "when passed buffer and block" do
+ it "raises an ArgumentError" do
+ @res.reading_body(@socket, true) do
+ -> { @res.read_body(+"") {} }.should raise_error(ArgumentError)
+ end
+ end
+ end
+end
diff --git a/spec/ruby/library/net-http/httpresponse/read_header_spec.rb b/spec/ruby/library/net-http/httpresponse/read_header_spec.rb
new file mode 100644
index 0000000000..3ea4ee834b
--- /dev/null
+++ b/spec/ruby/library/net-http/httpresponse/read_header_spec.rb
@@ -0,0 +1,9 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPResponse#read_header" do
+ it "returns self" do
+ res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
+ res.response.should equal(res)
+ end
+end
diff --git a/spec/ruby/library/net-http/httpresponse/read_new_spec.rb b/spec/ruby/library/net-http/httpresponse/read_new_spec.rb
new file mode 100644
index 0000000000..82f7a47ce8
--- /dev/null
+++ b/spec/ruby/library/net-http/httpresponse/read_new_spec.rb
@@ -0,0 +1,23 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require 'stringio'
+
+describe "Net::HTTPResponse.read_new" do
+ it "creates a HTTPResponse object based on the response read from the passed socket" do
+ socket = Net::BufferedIO.new(StringIO.new(<<EOS))
+HTTP/1.1 200 OK
+Content-Type: text/html; charset=utf-8
+
+test-body
+EOS
+ response = Net::HTTPResponse.read_new(socket)
+
+ response.should be_kind_of(Net::HTTPOK)
+ response.code.should == "200"
+ response["Content-Type"].should == "text/html; charset=utf-8"
+
+ response.reading_body(socket, true) do
+ response.body.should == "test-body\n"
+ end
+ end
+end
diff --git a/spec/ruby/library/net-http/httpresponse/reading_body_spec.rb b/spec/ruby/library/net-http/httpresponse/reading_body_spec.rb
new file mode 100644
index 0000000000..637a2806f8
--- /dev/null
+++ b/spec/ruby/library/net-http/httpresponse/reading_body_spec.rb
@@ -0,0 +1,58 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+require "stringio"
+
+describe "Net::HTTPResponse#reading_body" do
+ before :each do
+ @res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
+ @socket = Net::BufferedIO.new(StringIO.new("test body"))
+ end
+
+ describe "when body_allowed is true" do
+ it "reads and returns the response body for self from the passed socket" do
+ @res.reading_body(@socket, true) {}.should == "test body"
+ @res.body.should == "test body"
+ end
+
+ it "yields the passed block before reading the body" do
+ yielded = false
+
+ @res.reading_body(@socket, true) do
+ @res.inspect.should == "#<Net::HTTPUnknownResponse ??? test response readbody=false>"
+ yielded = true
+ end
+
+ yielded.should be_true
+ end
+
+ describe "but the response type is not allowed to have a body" do
+ before :each do
+ @res = Net::HTTPInformation.new("1.0", "???", "test response")
+ end
+
+ it "returns nil" do
+ @res.reading_body(@socket, false) {}.should be_nil
+ @res.body.should be_nil
+ end
+
+ it "yields the passed block" do
+ yielded = false
+ @res.reading_body(@socket, true) { yielded = true }
+ yielded.should be_true
+ end
+ end
+ end
+
+ describe "when body_allowed is false" do
+ it "returns nil" do
+ @res.reading_body(@socket, false) {}.should be_nil
+ @res.body.should be_nil
+ end
+
+ it "yields the passed block" do
+ yielded = false
+ @res.reading_body(@socket, true) { yielded = true }
+ yielded.should be_true
+ end
+ end
+end
diff --git a/spec/ruby/library/net-http/httpresponse/response_spec.rb b/spec/ruby/library/net-http/httpresponse/response_spec.rb
new file mode 100644
index 0000000000..caa0ca2d19
--- /dev/null
+++ b/spec/ruby/library/net-http/httpresponse/response_spec.rb
@@ -0,0 +1,9 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPResponse#response" do
+ it "returns self" do
+ res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
+ res.response.should equal(res)
+ end
+end
diff --git a/spec/ruby/library/net/http/httpresponse/shared/body.rb b/spec/ruby/library/net-http/httpresponse/shared/body.rb
index 618e3936fb..618e3936fb 100644
--- a/spec/ruby/library/net/http/httpresponse/shared/body.rb
+++ b/spec/ruby/library/net-http/httpresponse/shared/body.rb
diff --git a/spec/ruby/library/net-http/httpresponse/value_spec.rb b/spec/ruby/library/net-http/httpresponse/value_spec.rb
new file mode 100644
index 0000000000..2df8beaa10
--- /dev/null
+++ b/spec/ruby/library/net-http/httpresponse/value_spec.rb
@@ -0,0 +1,24 @@
+require_relative '../../../spec_helper'
+require 'net/http'
+
+describe "Net::HTTPResponse#value" do
+ it "raises an HTTP error for non 2xx HTTP Responses" do
+ res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
+ -> { res.value }.should raise_error(Net::HTTPError)
+
+ res = Net::HTTPInformation.new("1.0", "1xx", "test response")
+ -> { res.value }.should raise_error(Net::HTTPError)
+
+ res = Net::HTTPSuccess.new("1.0", "2xx", "test response")
+ -> { res.value }.should_not raise_error(Net::HTTPError)
+
+ res = Net::HTTPRedirection.new("1.0", "3xx", "test response")
+ -> { res.value }.should raise_error(Net::HTTPRetriableError)
+
+ res = Net::HTTPClientError.new("1.0", "4xx", "test response")
+ -> { res.value }.should raise_error(Net::HTTPClientException)
+
+ res = Net::HTTPServerError.new("1.0", "5xx", "test response")
+ -> { res.value }.should raise_error(Net::HTTPFatalError)
+ end
+end
diff --git a/spec/ruby/library/net/FTPError_spec.rb b/spec/ruby/library/net/FTPError_spec.rb
deleted file mode 100644
index 84128511db..0000000000
--- a/spec/ruby/library/net/FTPError_spec.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-require_relative '../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require 'net/ftp'
-
- describe "Net::FTPError" do
- it "is an Exception" do
- Net::FTPError.should < Exception
- end
- end
-end
diff --git a/spec/ruby/library/net/FTPPermError_spec.rb b/spec/ruby/library/net/FTPPermError_spec.rb
deleted file mode 100644
index 0da35e7d82..0000000000
--- a/spec/ruby/library/net/FTPPermError_spec.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-require_relative '../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require 'net/ftp'
-
- describe "Net::FTPPermError" do
- it "is an Exception" do
- Net::FTPPermError.should < Exception
- end
-
- it "is a subclass of Net::FTPError" do
- Net::FTPPermError.should < Net::FTPError
- end
- end
-end
diff --git a/spec/ruby/library/net/FTPProtoError_spec.rb b/spec/ruby/library/net/FTPProtoError_spec.rb
deleted file mode 100644
index 20e30dd2dd..0000000000
--- a/spec/ruby/library/net/FTPProtoError_spec.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-require_relative '../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require 'net/ftp'
-
- describe "Net::FTPProtoError" do
- it "is an Exception" do
- Net::FTPProtoError.should < Exception
- end
-
- it "is a subclass of Net::FTPError" do
- Net::FTPPermError.should < Net::FTPError
- end
- end
-end
diff --git a/spec/ruby/library/net/FTPReplyError_spec.rb b/spec/ruby/library/net/FTPReplyError_spec.rb
deleted file mode 100644
index cc774aabe5..0000000000
--- a/spec/ruby/library/net/FTPReplyError_spec.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-require_relative '../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require 'net/ftp'
-
- describe "Net::FTPReplyError" do
- it "is an Exception" do
- Net::FTPReplyError.should < Exception
- end
-
- it "is a subclass of Net::FTPError" do
- Net::FTPPermError.should < Net::FTPError
- end
- end
-end
diff --git a/spec/ruby/library/net/FTPTempError_spec.rb b/spec/ruby/library/net/FTPTempError_spec.rb
deleted file mode 100644
index e2fbdfd842..0000000000
--- a/spec/ruby/library/net/FTPTempError_spec.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-require_relative '../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require 'net/ftp'
-
- describe "Net::FTPTempError" do
- it "is an Exception" do
- Net::FTPTempError.should < Exception
- end
-
- it "is a subclass of Net::FTPError" do
- Net::FTPPermError.should < Net::FTPError
- end
- end
-end
diff --git a/spec/ruby/library/net/ftp/abort_spec.rb b/spec/ruby/library/net/ftp/abort_spec.rb
deleted file mode 100644
index ebdfed4b16..0000000000
--- a/spec/ruby/library/net/ftp/abort_spec.rb
+++ /dev/null
@@ -1,65 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
- require_relative 'fixtures/server'
-
- describe "Net::FTP#abort" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "sends the ABOR command to the server" do
- -> { @ftp.abort }.should_not raise_error
- end
-
- it "ignores the response" do
- @ftp.abort
- @ftp.last_response.should == "220 Dummy FTP Server ready!\n"
- end
-
- it "returns the full response" do
- @ftp.abort.should == "226 Closing data connection. (ABOR)\n"
- end
-
- it "does not raise any error when the response code is 225" do
- @server.should_receive(:abor).and_respond("225 Data connection open; no transfer in progress.")
- -> { @ftp.abort }.should_not raise_error
- end
-
- it "does not raise any error when the response code is 226" do
- @server.should_receive(:abor).and_respond("226 Closing data connection.")
- -> { @ftp.abort }.should_not raise_error
- end
-
- it "raises a Net::FTPProtoError when the response code is 500" do
- @server.should_receive(:abor).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.abort }.should raise_error(Net::FTPProtoError)
- end
-
- it "raises a Net::FTPProtoError when the response code is 501" do
- @server.should_receive(:abor).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.abort }.should raise_error(Net::FTPProtoError)
- end
-
- it "raises a Net::FTPProtoError when the response code is 502" do
- @server.should_receive(:abor).and_respond("502 Command not implemented.")
- -> { @ftp.abort }.should raise_error(Net::FTPProtoError)
- end
-
- it "raises a Net::FTPProtoError when the response code is 421" do
- @server.should_receive(:abor).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.abort }.should raise_error(Net::FTPProtoError)
- end
- end
-end
diff --git a/spec/ruby/library/net/ftp/acct_spec.rb b/spec/ruby/library/net/ftp/acct_spec.rb
deleted file mode 100644
index a960ae20a4..0000000000
--- a/spec/ruby/library/net/ftp/acct_spec.rb
+++ /dev/null
@@ -1,61 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
- require_relative 'fixtures/server'
-
- describe "Net::FTP#acct" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "writes the ACCT command to the server" do
- @ftp.acct("my_account")
- @ftp.last_response.should == "230 User 'my_account' logged in, proceed. (ACCT)\n"
- end
-
- it "returns nil" do
- @ftp.acct("my_account").should == nil
- end
-
- it "does not raise any error when the response code is 230" do
- @server.should_receive(:acct).and_respond("230 User logged in, proceed.")
- -> { @ftp.acct("my_account") }.should_not raise_error
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:acct).and_respond("530 Not logged in.")
- -> { @ftp.acct("my_account") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:acct).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.acct("my_account") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:acct).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.acct("my_account") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 503" do
- @server.should_receive(:acct).and_respond("503 Bad sequence of commands.")
- -> { @ftp.acct("my_account") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:acct).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.acct("my_account") }.should raise_error(Net::FTPTempError)
- end
- end
-end
diff --git a/spec/ruby/library/net/ftp/binary_spec.rb b/spec/ruby/library/net/ftp/binary_spec.rb
deleted file mode 100644
index da7e2d6c14..0000000000
--- a/spec/ruby/library/net/ftp/binary_spec.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
-
- describe "Net::FTP#binary" do
- it "returns true when self is in binary mode" do
- ftp = Net::FTP.new
- ftp.binary.should be_true
-
- ftp.binary = false
- ftp.binary.should be_false
- end
- end
-
- describe "Net::FTP#binary=" do
- it "sets self to binary mode when passed true" do
- ftp = Net::FTP.new
-
- ftp.binary = true
- ftp.binary.should be_true
-
- ftp.binary = false
- ftp.binary.should be_false
- end
- end
-end
diff --git a/spec/ruby/library/net/ftp/chdir_spec.rb b/spec/ruby/library/net/ftp/chdir_spec.rb
deleted file mode 100644
index 741c3c845e..0000000000
--- a/spec/ruby/library/net/ftp/chdir_spec.rb
+++ /dev/null
@@ -1,102 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
- require_relative 'fixtures/server'
-
- describe "Net::FTP#chdir" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- describe "when switching to the parent directory" do
- it "sends the 'CDUP' command to the server" do
- @ftp.chdir("..")
- @ftp.last_response.should == "200 Command okay. (CDUP)\n"
- end
-
- it "returns nil" do
- @ftp.chdir("..").should be_nil
- end
-
- it "does not raise a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:cdup).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.chdir("..") }.should_not raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:cdup).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.chdir("..") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:cdup).and_respond("502 Command not implemented.")
- -> { @ftp.chdir("..") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:cdup).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.chdir("..") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:cdup).and_respond("530 Not logged in.")
- -> { @ftp.chdir("..") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 550" do
- @server.should_receive(:cdup).and_respond("550 Requested action not taken.")
- -> { @ftp.chdir("..") }.should raise_error(Net::FTPPermError)
- end
- end
-
- it "writes the 'CWD' command with the passed directory to the socket" do
- @ftp.chdir("test")
- @ftp.last_response.should == "200 Command okay. (CWD test)\n"
- end
-
- it "returns nil" do
- @ftp.chdir("test").should be_nil
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:cwd).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.chdir("test") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:cwd).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.chdir("test") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:cwd).and_respond("502 Command not implemented.")
- -> { @ftp.chdir("test") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:cwd).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.chdir("test") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:cwd).and_respond("530 Not logged in.")
- -> { @ftp.chdir("test") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 550" do
- @server.should_receive(:cwd).and_respond("550 Requested action not taken.")
- -> { @ftp.chdir("test") }.should raise_error(Net::FTPPermError)
- end
- end
-end
diff --git a/spec/ruby/library/net/ftp/close_spec.rb b/spec/ruby/library/net/ftp/close_spec.rb
deleted file mode 100644
index 49cdf4dea7..0000000000
--- a/spec/ruby/library/net/ftp/close_spec.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
-
- describe "Net::FTP#close" do
- before :each do
- @socket = mock("Socket")
- @socket.stub!(:closed?).and_return(false)
- @socket.stub!(:read_timeout).and_return(60)
- @socket.stub!(:read_timeout=).and_return(3)
-
- @ftp = Net::FTP.new
- @ftp.instance_variable_set(:@sock, @socket)
- end
-
- it "closes the socket" do
- @socket.should_receive(:close)
- @ftp.close.should be_nil
- end
-
- it "does not try to close the socket if it has already been closed" do
- @socket.should_receive(:closed?).and_return(true)
- @socket.should_not_receive(:close)
- @ftp.close.should be_nil
- end
-
- it "does not try to close the socket if it is nil" do
- @ftp.instance_variable_set(:@sock, nil)
- @ftp.close.should be_nil
- end
- end
-end
diff --git a/spec/ruby/library/net/ftp/closed_spec.rb b/spec/ruby/library/net/ftp/closed_spec.rb
deleted file mode 100644
index a81917090a..0000000000
--- a/spec/ruby/library/net/ftp/closed_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
-
- describe "Net::FTP#closed?" do
- before :each do
- @socket = mock("Socket")
-
- @ftp = Net::FTP.new
- @ftp.instance_variable_set(:@sock, @socket)
- end
-
- it "returns true when the socket is closed" do
- @socket.should_receive(:closed?).and_return(true)
- @ftp.closed?.should be_true
- end
-
- it "returns true when the socket is nil" do
- @ftp.instance_variable_set(:@sock, nil)
- @ftp.closed?.should be_true
- end
- end
-end
diff --git a/spec/ruby/library/net/ftp/connect_spec.rb b/spec/ruby/library/net/ftp/connect_spec.rb
deleted file mode 100644
index b45e46c530..0000000000
--- a/spec/ruby/library/net/ftp/connect_spec.rb
+++ /dev/null
@@ -1,52 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
- require_relative 'fixtures/server'
-
- # TODO: Add specs for using the SOCKSSocket
- describe "Net::FTP#connect" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- end
-
- after :each do
- @server.connect_message = nil
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "tries to connect to the FTP Server on the given host and port" do
- -> { @ftp.connect(@server.hostname, @server.server_port) }.should_not raise_error
- end
-
- it "returns nil" do
- @ftp.connect(@server.hostname, @server.server_port).should be_nil
- end
-
- it "prints a small debug line when in debug mode" do
- @ftp.debug_mode = true
- -> { @ftp.connect(@server.hostname, @server.server_port) }.should output(/#{"connect: "}#{@server.hostname}#{", "}#{@server.server_port}#{"\\nget: 220 Dummy FTP Server ready!"}/)
- @ftp.debug_mode = false
- end
-
- it "does not raise any error when the response code is 220" do
- @server.connect_message = "220 Dummy FTP Server ready!"
- -> { @ftp.connect(@server.hostname, @server.server_port) }.should_not raise_error
- end
-
- it "raises a Net::FTPReplyError when the response code is 120" do
- @server.connect_message = "120 Service ready in nnn minutes."
- -> { @ftp.connect(@server.hostname, @server.server_port) }.should raise_error(Net::FTPReplyError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.connect_message = "421 Service not available, closing control connection."
- -> { @ftp.connect(@server.hostname, @server.server_port) }.should raise_error(Net::FTPTempError)
- end
- end
-end
diff --git a/spec/ruby/library/net/ftp/debug_mode_spec.rb b/spec/ruby/library/net/ftp/debug_mode_spec.rb
deleted file mode 100644
index 46d207bbea..0000000000
--- a/spec/ruby/library/net/ftp/debug_mode_spec.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
-
- describe "Net::FTP#debug_mode" do
- it "returns true when self is in debug mode" do
- ftp = Net::FTP.new
- ftp.debug_mode.should be_false
-
- ftp.debug_mode = true
- ftp.debug_mode.should be_true
- end
- end
-
- describe "Net::FTP#debug_mode=" do
- it "sets self into debug mode when passed true" do
- ftp = Net::FTP.new
- ftp.debug_mode = true
- ftp.debug_mode.should be_true
-
- ftp.debug_mode = false
- ftp.debug_mode.should be_false
- end
- end
-end
diff --git a/spec/ruby/library/net/ftp/default_passive_spec.rb b/spec/ruby/library/net/ftp/default_passive_spec.rb
deleted file mode 100644
index 9348d3294d..0000000000
--- a/spec/ruby/library/net/ftp/default_passive_spec.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
-
- describe "Net::FTP#default_passive" do
- it "is true by default" do
- ruby_exe(fixture(__FILE__, "default_passive.rb")).should == "true\ntrue\n"
- end
- end
-end
diff --git a/spec/ruby/library/net/ftp/delete_spec.rb b/spec/ruby/library/net/ftp/delete_spec.rb
deleted file mode 100644
index 43bfcc1541..0000000000
--- a/spec/ruby/library/net/ftp/delete_spec.rb
+++ /dev/null
@@ -1,62 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
- require_relative 'fixtures/server'
-
- describe "Net::FTP#delete" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "sends the DELE command with the passed filename to the server" do
- @ftp.delete("test.file")
- @ftp.last_response.should == "250 Requested file action okay, completed. (DELE test.file)\n"
- end
-
- it "raises a Net::FTPTempError when the response code is 450" do
- @server.should_receive(:dele).and_respond("450 Requested file action not taken.")
- -> { @ftp.delete("test.file") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 550" do
- @server.should_receive(:dele).and_respond("550 Requested action not taken.")
- -> { @ftp.delete("test.file") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:dele).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.delete("test.file") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:dele).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.delete("test.file") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:dele).and_respond("502 Command not implemented.")
- -> { @ftp.delete("test.file") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:dele).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.delete("test.file") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:dele).and_respond("530 Not logged in.")
- -> { @ftp.delete("test.file") }.should raise_error(Net::FTPPermError)
- end
- end
-end
diff --git a/spec/ruby/library/net/ftp/dir_spec.rb b/spec/ruby/library/net/ftp/dir_spec.rb
deleted file mode 100644
index dce50a5ac5..0000000000
--- a/spec/ruby/library/net/ftp/dir_spec.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
- require_relative 'fixtures/server'
- require_relative 'shared/list'
-
- describe "Net::FTP#dir" do
- it_behaves_like :net_ftp_list, :dir
- end
-end
diff --git a/spec/ruby/library/net/ftp/get_spec.rb b/spec/ruby/library/net/ftp/get_spec.rb
deleted file mode 100644
index 892b30061c..0000000000
--- a/spec/ruby/library/net/ftp/get_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
- require_relative 'fixtures/server'
- require_relative 'shared/gettextfile'
- require_relative 'shared/getbinaryfile'
-
- describe "Net::FTP#get (binary mode)" do
- before :each do
- @binary_mode = true
- end
-
- it_behaves_like :net_ftp_getbinaryfile, :get
- end
-
- describe "Net::FTP#get (text mode)" do
- before :each do
- @binary_mode = false
- end
-
- it_behaves_like :net_ftp_gettextfile, :get
- end
-end
diff --git a/spec/ruby/library/net/ftp/getbinaryfile_spec.rb b/spec/ruby/library/net/ftp/getbinaryfile_spec.rb
deleted file mode 100644
index c5abdd67e7..0000000000
--- a/spec/ruby/library/net/ftp/getbinaryfile_spec.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
- require_relative 'fixtures/server'
- require_relative 'shared/getbinaryfile'
-
- describe "Net::FTP#getbinaryfile" do
- it_behaves_like :net_ftp_getbinaryfile, :getbinaryfile
- end
-end
diff --git a/spec/ruby/library/net/ftp/getdir_spec.rb b/spec/ruby/library/net/ftp/getdir_spec.rb
deleted file mode 100644
index 8f6fca5bfb..0000000000
--- a/spec/ruby/library/net/ftp/getdir_spec.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
- require_relative 'shared/pwd'
-
- describe "Net::FTP#getdir" do
- it_behaves_like :net_ftp_pwd, :getdir
- end
-end
diff --git a/spec/ruby/library/net/ftp/gettextfile_spec.rb b/spec/ruby/library/net/ftp/gettextfile_spec.rb
deleted file mode 100644
index e272ae73b1..0000000000
--- a/spec/ruby/library/net/ftp/gettextfile_spec.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
- require_relative 'fixtures/server'
- require_relative 'shared/gettextfile'
-
- describe "Net::FTP#gettextfile" do
- it_behaves_like :net_ftp_gettextfile, :gettextfile
- end
-end
diff --git a/spec/ruby/library/net/ftp/help_spec.rb b/spec/ruby/library/net/ftp/help_spec.rb
deleted file mode 100644
index 9b15f42ede..0000000000
--- a/spec/ruby/library/net/ftp/help_spec.rb
+++ /dev/null
@@ -1,69 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
- require_relative 'fixtures/server'
-
- describe "Net::FTP#help" do
- def with_connection
- yield
- end
-
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "writes the HELP command to the server" do
- @ftp.help
- @ftp.last_response.should == "211 System status, or system help reply. (HELP)\n"
- end
-
- it "returns the server's response" do
- @ftp.help.should == "211 System status, or system help reply. (HELP)\n"
- end
-
- it "writes the HELP command with an optional parameter to the socket" do
- @ftp.help("some parameter").should == "211 System status, or system help reply. (HELP some parameter)\n"
- end
-
- it "does not raise any error when the response code is 211" do
- @server.should_receive(:help).and_respond("211 System status, or system help reply.")
- -> { @ftp.help }.should_not raise_error
- end
-
- it "does not raise any error when the response code is 214" do
- @server.should_receive(:help).and_respond("214 Help message.")
- -> { @ftp.help }.should_not raise_error
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:help).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.help }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:help).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.help }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:help).and_respond("502 Command not implemented.")
- -> { @ftp.help }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:help).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.help }.should raise_error(Net::FTPTempError)
- end
- end
-end
diff --git a/spec/ruby/library/net/ftp/initialize_spec.rb b/spec/ruby/library/net/ftp/initialize_spec.rb
deleted file mode 100644
index 80f71a9161..0000000000
--- a/spec/ruby/library/net/ftp/initialize_spec.rb
+++ /dev/null
@@ -1,408 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
-
- describe "Net::FTP#initialize" do
- before :each do
- @ftp = Net::FTP.allocate
- @ftp.stub!(:connect)
- @port_args = []
- @port_args << 21
- end
-
- it "is private" do
- Net::FTP.should have_private_instance_method(:initialize)
- end
-
- it "sets self into binary mode" do
- @ftp.binary.should be_nil
- @ftp.send(:initialize)
- @ftp.binary.should be_true
- end
-
- it "sets self into active mode" do
- @ftp.passive.should be_nil
- @ftp.send(:initialize)
- @ftp.passive.should be_false
- end
-
- it "sets self into non-debug mode" do
- @ftp.debug_mode.should be_nil
- @ftp.send(:initialize)
- @ftp.debug_mode.should be_false
- end
-
- it "sets self to not resume file uploads/downloads" do
- @ftp.resume.should be_nil
- @ftp.send(:initialize)
- @ftp.resume.should be_false
- end
-
- describe "when passed no arguments" do
- it "does not try to connect" do
- @ftp.should_not_receive(:connect)
- @ftp.send(:initialize)
- end
- end
-
- describe "when passed host" do
- it "tries to connect to the passed host" do
- @ftp.should_receive(:connect).with("localhost", *@port_args)
- @ftp.send(:initialize, "localhost")
- end
- end
-
- describe "when passed host, user" do
- it "tries to connect to the passed host" do
- @ftp.should_receive(:connect).with("localhost", *@port_args)
- @ftp.send(:initialize, "localhost")
- end
-
- it "tries to login with the passed username" do
- @ftp.should_receive(:login).with("rubyspec", nil, nil)
- @ftp.send(:initialize, "localhost", "rubyspec")
- end
- end
-
- describe "when passed host, user, password" do
- it "tries to connect to the passed host" do
- @ftp.should_receive(:connect).with("localhost", *@port_args)
- @ftp.send(:initialize, "localhost")
- end
-
- it "tries to login with the passed username and password" do
- @ftp.should_receive(:login).with("rubyspec", "rocks", nil)
- @ftp.send(:initialize, "localhost", "rubyspec", "rocks")
- end
- end
-
- describe "when passed host, user" do
- it "tries to connect to the passed host" do
- @ftp.should_receive(:connect).with("localhost", *@port_args)
- @ftp.send(:initialize, "localhost")
- end
-
- it "tries to login with the passed username, password and account" do
- @ftp.should_receive(:login).with("rubyspec", "rocks", "account")
- @ftp.send(:initialize, "localhost", "rubyspec", "rocks", "account")
- end
- end
-
- before :each do
- @ftp.stub!(:login)
- end
-
- describe 'when the host' do
- describe 'is set' do
- describe 'and port option' do
- describe 'is set' do
- it 'tries to connect to the host on the specified port' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ port: 8080 })
- @ftp.should_receive(:connect).with('localhost', 8080)
-
- @ftp.send(:initialize, 'localhost', options)
- end
- end
-
- describe 'is not set' do
- it 'tries to connect to the host without a port' do
- @ftp.should_receive(:connect).with("localhost", *@port_args)
-
- @ftp.send(:initialize, 'localhost')
- end
- end
- end
-
- describe 'when the username option' do
- describe 'is set' do
- describe 'and the password option' do
- describe 'is set' do
- describe 'and the account option' do
- describe 'is set' do
- it 'tries to log in with the supplied parameters' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ username: 'a', password: 'topsecret', account: 'b' })
- @ftp.should_receive(:login).with('a', 'topsecret', 'b')
-
- @ftp.send(:initialize, 'localhost', options)
- end
- end
-
- describe 'is unset' do
- it 'tries to log in with the supplied parameters' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ username: 'a', password: 'topsecret' })
- @ftp.should_receive(:login).with('a', 'topsecret', nil)
-
- @ftp.send(:initialize, 'localhost', options)
- end
- end
- end
- end
-
- describe 'is unset' do
- describe 'and the account option' do
- describe 'is set' do
- it 'tries to log in with the supplied parameters' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ username: 'a', account: 'b' })
- @ftp.should_receive(:login).with('a', nil, 'b')
-
- @ftp.send(:initialize, 'localhost', options)
- end
- end
-
- describe 'is unset' do
- it 'tries to log in with the supplied parameters' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ username: 'a'})
- @ftp.should_receive(:login).with('a', nil, nil)
-
- @ftp.send(:initialize, 'localhost', options)
- end
- end
- end
- end
- end
- end
-
- describe 'is not set' do
- it 'does not try to log in' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({})
- @ftp.should_not_receive(:login)
-
- @ftp.send(:initialize, 'localhost', options)
- end
- end
- end
- end
-
- describe 'is unset' do
- it 'does not try to connect' do
- @ftp.should_not_receive(:connect)
-
- @ftp.send(:initialize)
- end
-
- it 'does not try to log in' do
- @ftp.should_not_receive(:login)
-
- @ftp.send(:initialize)
- end
- end
- end
-
- describe 'when the passive option' do
- describe 'is set' do
- describe 'to true' do
- it 'sets passive to true' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ passive: true })
-
- @ftp.send(:initialize, nil, options)
- @ftp.passive.should == true
- end
- end
-
- describe 'to false' do
- it 'sets passive to false' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ passive: false })
-
- @ftp.send(:initialize, nil, options)
- @ftp.passive.should == false
- end
- end
- end
-
- describe 'is unset' do
- it 'sets passive to false' do
- @ftp.send(:initialize)
- @ftp.passive.should == false
- end
- end
- end
-
- describe 'when the debug_mode option' do
- describe 'is set' do
- describe 'to true' do
- it 'sets debug_mode to true' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ debug_mode: true })
-
- @ftp.send(:initialize, nil, options)
- @ftp.debug_mode.should == true
- end
- end
-
- describe 'to false' do
- it 'sets debug_mode to false' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ debug_mode: false })
-
- @ftp.send(:initialize, nil, options)
- @ftp.debug_mode.should == false
- end
- end
- end
-
- describe 'is unset' do
- it 'sets debug_mode to false' do
- @ftp.send(:initialize)
- @ftp.debug_mode.should == false
- end
- end
- end
-
- describe 'when the open_timeout option' do
- describe 'is set' do
- it 'sets open_timeout to the specified value' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ open_timeout: 42 })
-
- @ftp.send(:initialize, nil, options)
- @ftp.open_timeout.should == 42
- end
- end
-
- describe 'is not set' do
- it 'sets open_timeout to nil' do
- @ftp.send(:initialize)
- @ftp.open_timeout.should == nil
- end
- end
- end
-
- describe 'when the read_timeout option' do
- describe 'is set' do
- it 'sets read_timeout to the specified value' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ read_timeout: 100 })
-
- @ftp.send(:initialize, nil, options)
- @ftp.read_timeout.should == 100
- end
- end
-
- describe 'is not set' do
- it 'sets read_timeout to the default value' do
- @ftp.send(:initialize)
- @ftp.read_timeout.should == 60
- end
- end
- end
-
- describe 'when the ssl_handshake_timeout option' do
- describe 'is set' do
- it 'sets ssl_handshake_timeout to the specified value' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ ssl_handshake_timeout: 23 })
-
- @ftp.send(:initialize, nil, options)
- @ftp.ssl_handshake_timeout.should == 23
- end
- end
-
- describe 'is not set' do
- it 'sets ssl_handshake_timeout to nil' do
- @ftp.send(:initialize)
- @ftp.ssl_handshake_timeout.should == nil
- end
- end
- end
-
- describe 'when the ssl option' do
- describe 'is set' do
- describe "and the ssl option's value is true" do
- it 'initializes ssl_context to a blank SSLContext object' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ ssl: true })
-
- ssl_context = OpenSSL::SSL::SSLContext.allocate
- ssl_context.stub!(:set_params)
-
- OpenSSL::SSL::SSLContext.should_receive(:new).and_return(ssl_context)
- ssl_context.should_receive(:set_params).with({})
-
- @ftp.send(:initialize, nil, options)
- @ftp.instance_variable_get(:@ssl_context).should == ssl_context
- end
- end
-
- describe "and the ssl option's value is a hash" do
- it 'initializes ssl_context to a configured SSLContext object' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ ssl: {key: 'value'} })
-
- ssl_context = OpenSSL::SSL::SSLContext.allocate
- ssl_context.stub!(:set_params)
-
- OpenSSL::SSL::SSLContext.should_receive(:new).and_return(ssl_context)
- ssl_context.should_receive(:set_params).with({key: 'value'})
-
- @ftp.send(:initialize, nil, options)
- @ftp.instance_variable_get(:@ssl_context).should == ssl_context
- end
- end
-
- describe 'and private_data_connection' do
- describe 'is set' do
- it 'sets private_data_connection to that value' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ ssl: true, private_data_connection: 'true' })
-
- @ftp.send(:initialize, nil, options)
- @ftp.instance_variable_get(:@private_data_connection).should == 'true'
- end
- end
-
- describe 'is not set' do
- it 'sets private_data_connection to nil' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ ssl: true })
-
- @ftp.send(:initialize, nil, options)
- @ftp.instance_variable_get(:@private_data_connection).should == true
- end
- end
- end
- end
-
- describe 'is not set' do
- it 'sets ssl_context to nil' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({})
-
- @ftp.send(:initialize, nil, options)
- @ftp.instance_variable_get(:@ssl_context).should == nil
- end
-
- describe 'private_data_connection' do
- describe 'is set' do
- it 'raises an ArgumentError' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({ private_data_connection: true })
-
- -> {
- @ftp.send(:initialize, nil, options)
- }.should raise_error(ArgumentError, /private_data_connection can be set to true only when ssl is enabled/)
- end
- end
-
- describe 'is not set' do
- it 'sets private_data_connection to false' do
- options = mock('ftp initialize options')
- options.should_receive(:to_hash).and_return({})
-
- @ftp.send(:initialize, nil, options)
- @ftp.instance_variable_get(:@private_data_connection).should == false
- end
- end
- end
- end
- end
- end
-end
diff --git a/spec/ruby/library/net/ftp/last_response_code_spec.rb b/spec/ruby/library/net/ftp/last_response_code_spec.rb
deleted file mode 100644
index 86f2b9a695..0000000000
--- a/spec/ruby/library/net/ftp/last_response_code_spec.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
- require_relative 'shared/last_response_code'
- require_relative 'fixtures/server'
-
- describe "Net::FTP#last_response_code" do
- it_behaves_like :net_ftp_last_response_code, :last_response_code
- end
-end
diff --git a/spec/ruby/library/net/ftp/last_response_spec.rb b/spec/ruby/library/net/ftp/last_response_spec.rb
deleted file mode 100644
index 1d29b9b73f..0000000000
--- a/spec/ruby/library/net/ftp/last_response_spec.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
- require_relative 'fixtures/server'
-
- describe "Net::FTP#last_response" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "returns the last response" do
- @ftp.last_response.should == "220 Dummy FTP Server ready!\n"
- @ftp.help
- @ftp.last_response.should == "211 System status, or system help reply. (HELP)\n"
- end
- end
-end
diff --git a/spec/ruby/library/net/ftp/lastresp_spec.rb b/spec/ruby/library/net/ftp/lastresp_spec.rb
deleted file mode 100644
index 9d26efb8f8..0000000000
--- a/spec/ruby/library/net/ftp/lastresp_spec.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
- require_relative 'shared/last_response_code'
- require_relative 'fixtures/server'
-
- describe "Net::FTP#lastresp" do
- it_behaves_like :net_ftp_last_response_code, :lastresp
- end
-end
diff --git a/spec/ruby/library/net/ftp/list_spec.rb b/spec/ruby/library/net/ftp/list_spec.rb
deleted file mode 100644
index 6cffafeb4f..0000000000
--- a/spec/ruby/library/net/ftp/list_spec.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
- require_relative 'fixtures/server'
- require_relative 'shared/list'
-
- describe "Net::FTP#list" do
- it_behaves_like :net_ftp_list, :list
- end
-end
diff --git a/spec/ruby/library/net/ftp/login_spec.rb b/spec/ruby/library/net/ftp/login_spec.rb
deleted file mode 100644
index 981b439082..0000000000
--- a/spec/ruby/library/net/ftp/login_spec.rb
+++ /dev/null
@@ -1,198 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
- require_relative 'fixtures/server'
-
- describe "Net::FTP#login" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- describe "when passed no arguments" do
- it "sends the USER command with 'anonymous' as name to the server" do
- @ftp.login
- @server.login_user.should == "anonymous"
- end
-
- it "sends 'anonymous@' as a password when required" do
- @server.should_receive(:user).and_respond("331 User name okay, need password.")
- @ftp.login
- @server.login_pass.should == "anonymous@"
- end
-
- it "raises a Net::FTPReplyError when the server requests an account" do
- @server.should_receive(:user).and_respond("331 User name okay, need password.")
- @server.should_receive(:pass).and_respond("332 Need account for login.")
- -> { @ftp.login }.should raise_error(Net::FTPReplyError)
- end
- end
-
- describe "when passed name" do
- it "sends the USER command with the passed name to the server" do
- @ftp.login("rubyspec")
- @server.login_user.should == "rubyspec"
- end
-
- it "raises a Net::FTPReplyError when the server requests a password, but none was given" do
- @server.should_receive(:user).and_respond("331 User name okay, need password.")
- -> { @ftp.login("rubyspec") }.should raise_error(Net::FTPReplyError)
- end
-
- it "raises a Net::FTPReplyError when the server requests an account, but none was given" do
- @server.should_receive(:user).and_respond("331 User name okay, need password.")
- @server.should_receive(:pass).and_respond("332 Need account for login.")
- -> { @ftp.login("rubyspec") }.should raise_error(Net::FTPReplyError)
- end
- end
-
- describe "when passed name, password" do
- it "sends the USER command with the passed name to the server" do
- @ftp.login("rubyspec", "rocks")
- @server.login_user.should == "rubyspec"
- end
-
- it "sends the passed password when required" do
- @server.should_receive(:user).and_respond("331 User name okay, need password.")
- @ftp.login("rubyspec", "rocks")
- @server.login_pass.should == "rocks"
- end
-
- it "raises a Net::FTPReplyError when the server requests an account" do
- @server.should_receive(:user).and_respond("331 User name okay, need password.")
- @server.should_receive(:pass).and_respond("332 Need account for login.")
- -> { @ftp.login("rubyspec", "rocks") }.should raise_error(Net::FTPReplyError)
- end
- end
-
- describe "when passed name, password, account" do
- it "sends the USER command with the passed name to the server" do
- @ftp.login("rubyspec", "rocks", "account")
- @server.login_user.should == "rubyspec"
- end
-
- it "sends the passed password when required" do
- @server.should_receive(:user).and_respond("331 User name okay, need password.")
- @ftp.login("rubyspec", "rocks", "account")
- @server.login_pass.should == "rocks"
- end
-
- it "sends the passed account when required" do
- @server.should_receive(:user).and_respond("331 User name okay, need password.")
- @server.should_receive(:pass).and_respond("332 Need account for login.")
- @ftp.login("rubyspec", "rocks", "account")
- @server.login_acct.should == "account"
- end
- end
-
- describe "when the USER command fails" do
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:user).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:user).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:user).and_respond("502 Command not implemented.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:user).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:user).and_respond("530 Not logged in.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
- end
- end
-
- describe "when the PASS command fails" do
- before :each do
- @server.should_receive(:user).and_respond("331 User name okay, need password.")
- end
-
- it "does not raise an Error when the response code is 202" do
- @server.should_receive(:pass).and_respond("202 Command not implemented, superfluous at this site.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should_not raise_error
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:pass).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:pass).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:pass).and_respond("502 Command not implemented.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:pass).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:pass).and_respond("530 Not logged in.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
- end
- end
-
- describe "when the ACCT command fails" do
- before :each do
- @server.should_receive(:user).and_respond("331 User name okay, need password.")
- @server.should_receive(:pass).and_respond("332 Need account for login.")
- end
-
- it "does not raise an Error when the response code is 202" do
- @server.should_receive(:acct).and_respond("202 Command not implemented, superfluous at this site.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should_not raise_error
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:acct).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:acct).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:acct).and_respond("502 Command not implemented.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:acct).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:acct).and_respond("530 Not logged in.")
- -> { @ftp.login("rubyspec", "rocks", "account") }.should raise_error(Net::FTPPermError)
- end
- end
- end
-end
diff --git a/spec/ruby/library/net/ftp/ls_spec.rb b/spec/ruby/library/net/ftp/ls_spec.rb
deleted file mode 100644
index f262515865..0000000000
--- a/spec/ruby/library/net/ftp/ls_spec.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
- require_relative 'fixtures/server'
- require_relative 'shared/list'
-
- describe "Net::FTP#ls" do
- it_behaves_like :net_ftp_list, :ls
- end
-end
diff --git a/spec/ruby/library/net/ftp/mdtm_spec.rb b/spec/ruby/library/net/ftp/mdtm_spec.rb
deleted file mode 100644
index ea55533c43..0000000000
--- a/spec/ruby/library/net/ftp/mdtm_spec.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
- require_relative 'fixtures/server'
-
- describe "Net::FTP#mdtm" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "sends the MDTM with the passed filename command to the server" do
- @ftp.mdtm("test.file")
- @ftp.last_response.should == "213 19980705132316\n"
- end
-
- it "returns the last modification time of the passed file" do
- @ftp.mdtm("test.file").should == "19980705132316"
- end
-
- it "raises a Net::FTPPermError when the response code is 550" do
- @server.should_receive(:mdtm).and_respond("550 Requested action not taken.")
- -> { @ftp.mdtm("test.file") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:mdtm).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.mdtm("test.file") }.should raise_error(Net::FTPTempError)
- end
- end
-end
diff --git a/spec/ruby/library/net/ftp/mkdir_spec.rb b/spec/ruby/library/net/ftp/mkdir_spec.rb
deleted file mode 100644
index 2cb437a076..0000000000
--- a/spec/ruby/library/net/ftp/mkdir_spec.rb
+++ /dev/null
@@ -1,64 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
- require_relative 'fixtures/server'
-
- describe "Net::FTP#mkdir" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "sends the MKD command with the passed pathname to the server" do
- @ftp.mkdir("test.folder")
- @ftp.last_response.should == %{257 "test.folder" created.\n}
- end
-
- it "returns the path to the newly created directory" do
- @ftp.mkdir("test.folder").should == "test.folder"
- @ftp.mkdir("/absolute/path/to/test.folder").should == "/absolute/path/to/test.folder"
- @ftp.mkdir("relative/path/to/test.folder").should == "relative/path/to/test.folder"
- @ftp.mkdir('/usr/dm/foo"bar').should == '/usr/dm/foo"bar'
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:mkd).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.mkdir("test.folder") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:mkd).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.mkdir("test.folder") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:mkd).and_respond("502 Command not implemented.")
- -> { @ftp.mkdir("test.folder") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:mkd).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.mkdir("test.folder") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:mkd).and_respond("530 Not logged in.")
- -> { @ftp.mkdir("test.folder") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 550" do
- @server.should_receive(:mkd).and_respond("550 Requested action not taken.")
- -> { @ftp.mkdir("test.folder") }.should raise_error(Net::FTPPermError)
- end
- end
-end
diff --git a/spec/ruby/library/net/ftp/mtime_spec.rb b/spec/ruby/library/net/ftp/mtime_spec.rb
deleted file mode 100644
index 7265667a52..0000000000
--- a/spec/ruby/library/net/ftp/mtime_spec.rb
+++ /dev/null
@@ -1,53 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
- require_relative 'fixtures/server'
-
- describe "Net::FTP#mtime" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "sends the MDTM with the passed filename command to the server" do
- @ftp.mtime("test.file")
- @ftp.last_response.should == "213 19980705132316\n"
- end
-
- describe "when passed filename" do
- it "returns the last modification time of the passed file as a Time object in the local time" do
- @ftp.mtime("test.file").should == Time.gm("1998", "07", "05", "13", "23", "16")
- end
- end
-
- describe "when passed filename, local_time" do
- it "returns the last modification time as a Time object in UTC when local_time is true" do
- @ftp.mtime("test.file", true).should == Time.local("1998", "07", "05", "13", "23", "16")
- end
-
- it "returns the last modification time as a Time object in the local time when local_time is false" do
- @ftp.mtime("test.file", false).should == Time.gm("1998", "07", "05", "13", "23", "16")
- end
- end
-
- it "raises a Net::FTPPermError when the response code is 550" do
- @server.should_receive(:mdtm).and_respond("550 Requested action not taken.")
- -> { @ftp.mtime("test.file") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:mdtm).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.mtime("test.file") }.should raise_error(Net::FTPTempError)
- end
- end
-end
diff --git a/spec/ruby/library/net/ftp/nlst_spec.rb b/spec/ruby/library/net/ftp/nlst_spec.rb
deleted file mode 100644
index 0de84b3a76..0000000000
--- a/spec/ruby/library/net/ftp/nlst_spec.rb
+++ /dev/null
@@ -1,95 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
- require_relative 'fixtures/server'
-
- describe "Net::FTP#nlst" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.passive = false
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- describe "when passed no arguments" do
- it "returns an Array containing a list of files in the current dir" do
- @ftp.nlst.should == ["last_response_code.rb", "list.rb", "pwd.rb"]
- @ftp.last_response.should == "226 transfer complete (NLST)\n"
- end
- end
-
- describe "when passed dir" do
- it "returns an Array containing a list of files in the passed dir" do
- @ftp.nlst("test.folder").should == ["last_response_code.rb", "list.rb", "pwd.rb"]
- @ftp.last_response.should == "226 transfer complete (NLST test.folder)\n"
- end
- end
-
- describe "when the NLST command fails" do
- it "raises a Net::FTPTempError when the response code is 450" do
- @server.should_receive(:nlst).and_respond("450 Requested file action not taken..")
- -> { @ftp.nlst }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:nlst).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.nlst }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:nlst).and_respond("501 Syntax error, command unrecognized.")
- -> { @ftp.nlst }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:nlst).and_respond("502 Command not implemented.")
- -> { @ftp.nlst }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:nlst).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.nlst }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:nlst).and_respond("530 Not logged in.")
- -> { @ftp.nlst }.should raise_error(Net::FTPPermError)
- end
- end
-
- describe "when opening the data port fails" do
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:eprt).and_respond("500 Syntax error, command unrecognized.")
- @server.should_receive(:port).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.nlst }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:eprt).and_respond("501 Syntax error in parameters or arguments.")
- @server.should_receive(:port).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.nlst }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:eprt).and_respond("421 Service not available, closing control connection.")
- @server.should_receive(:port).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.nlst }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:eprt).and_respond("530 Not logged in.")
- @server.should_receive(:port).and_respond("530 Not logged in.")
- -> { @ftp.nlst }.should raise_error(Net::FTPPermError)
- end
- end
- end
-end
diff --git a/spec/ruby/library/net/ftp/noop_spec.rb b/spec/ruby/library/net/ftp/noop_spec.rb
deleted file mode 100644
index 71011d4af7..0000000000
--- a/spec/ruby/library/net/ftp/noop_spec.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
- require_relative 'fixtures/server'
-
- describe "Net::FTP#noop" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "sends the NOOP command to the server" do
- @ftp.noop
- @ftp.last_response.should == "200 Command okay. (NOOP)\n"
- end
-
- it "returns nil" do
- @ftp.noop.should be_nil
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:noop).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.noop }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:noop).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.noop }.should raise_error(Net::FTPTempError)
- end
- end
-end
diff --git a/spec/ruby/library/net/ftp/open_spec.rb b/spec/ruby/library/net/ftp/open_spec.rb
deleted file mode 100644
index 89187b9802..0000000000
--- a/spec/ruby/library/net/ftp/open_spec.rb
+++ /dev/null
@@ -1,58 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
-
- describe "Net::FTP.open" do
- before :each do
- @ftp = mock("Net::FTP instance")
- Net::FTP.stub!(:new).and_return(@ftp)
- end
-
- describe "when passed no block" do
- it "returns a new Net::FTP instance" do
- Net::FTP.open("localhost").should equal(@ftp)
- end
-
- it "passes the passed arguments down to Net::FTP.new" do
- Net::FTP.should_receive(:new).with("localhost", "user", "password", "account")
- Net::FTP.open("localhost", "user", "password", "account")
- end
- end
-
- describe "when passed a block" do
- before :each do
- @ftp.stub!(:close)
- end
-
- it "yields a new Net::FTP instance to the passed block" do
- yielded = false
- Net::FTP.open("localhost") do |ftp|
- yielded = true
- ftp.should equal(@ftp)
- end
- yielded.should be_true
- end
-
- it "closes the Net::FTP instance after yielding" do
- Net::FTP.open("localhost") do |ftp|
- ftp.should_receive(:close)
- end
- end
-
- it "closes the Net::FTP instance even if an exception is raised while yielding" do
- begin
- Net::FTP.open("localhost") do |ftp|
- ftp.should_receive(:close)
- raise ArgumentError, "some exception"
- end
- rescue ArgumentError
- end
- end
-
- it "returns the block's return value" do
- Net::FTP.open("localhost") { :test }.should == :test
- end
- end
- end
-end
diff --git a/spec/ruby/library/net/ftp/passive_spec.rb b/spec/ruby/library/net/ftp/passive_spec.rb
deleted file mode 100644
index f9c34efb7d..0000000000
--- a/spec/ruby/library/net/ftp/passive_spec.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
-
- describe "Net::FTP#passive" do
- it "returns true when self is in passive mode" do
- ftp = Net::FTP.new
- ftp.passive.should be_false
-
- ftp.passive = true
- ftp.passive.should be_true
- end
-
- it "is the value of Net::FTP.default_value by default" do
- ruby_exe(fixture(__FILE__, "passive.rb")).should == "true"
- end
- end
-
- describe "Net::FTP#passive=" do
- it "sets self to passive mode when passed true" do
- ftp = Net::FTP.new
-
- ftp.passive = true
- ftp.passive.should be_true
-
- ftp.passive = false
- ftp.passive.should be_false
- end
- end
-end
diff --git a/spec/ruby/library/net/ftp/put_spec.rb b/spec/ruby/library/net/ftp/put_spec.rb
deleted file mode 100644
index 36ba6c1963..0000000000
--- a/spec/ruby/library/net/ftp/put_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
- require_relative 'fixtures/server'
- require_relative 'shared/puttextfile'
- require_relative 'shared/putbinaryfile'
-
- describe "Net::FTP#put (binary mode)" do
- before :each do
- @binary_mode = true
- end
-
- it_behaves_like :net_ftp_putbinaryfile, :put
- end
-
- describe "Net::FTP#put (text mode)" do
- before :each do
- @binary_mode = false
- end
-
- it_behaves_like :net_ftp_puttextfile, :put
- end
-end
diff --git a/spec/ruby/library/net/ftp/putbinaryfile_spec.rb b/spec/ruby/library/net/ftp/putbinaryfile_spec.rb
deleted file mode 100644
index 6ced5246fe..0000000000
--- a/spec/ruby/library/net/ftp/putbinaryfile_spec.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
- require_relative 'fixtures/server'
- require_relative 'shared/putbinaryfile'
-
- describe "Net::FTP#putbinaryfile" do
- it_behaves_like :net_ftp_putbinaryfile, :putbinaryfile
- end
-end
diff --git a/spec/ruby/library/net/ftp/puttextfile_spec.rb b/spec/ruby/library/net/ftp/puttextfile_spec.rb
deleted file mode 100644
index 0cab6bd3c3..0000000000
--- a/spec/ruby/library/net/ftp/puttextfile_spec.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
- require_relative 'fixtures/server'
- require_relative 'shared/puttextfile'
-
- describe "Net::FTP#puttextfile" do
- it_behaves_like :net_ftp_puttextfile, :puttextfile
- end
-end
diff --git a/spec/ruby/library/net/ftp/pwd_spec.rb b/spec/ruby/library/net/ftp/pwd_spec.rb
deleted file mode 100644
index 856ff5ff9b..0000000000
--- a/spec/ruby/library/net/ftp/pwd_spec.rb
+++ /dev/null
@@ -1,56 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
- require_relative 'fixtures/server'
-
- describe "Net::FTP#pwd" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "sends the PWD command to the server" do
- @ftp.pwd
- @ftp.last_response.should == "257 \"/some/dir/\" - current directory\n"
- end
-
- it "returns the current directory" do
- @ftp.pwd.should == "/some/dir/"
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:pwd).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.pwd }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:pwd).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.pwd }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:pwd).and_respond("502 Command not implemented.")
- -> { @ftp.pwd }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:pwd).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.pwd }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 550" do
- @server.should_receive(:pwd).and_respond("550 Requested action not taken.")
- -> { @ftp.pwd }.should raise_error(Net::FTPPermError)
- end
- end
-end
diff --git a/spec/ruby/library/net/ftp/quit_spec.rb b/spec/ruby/library/net/ftp/quit_spec.rb
deleted file mode 100644
index 12b9fd3cee..0000000000
--- a/spec/ruby/library/net/ftp/quit_spec.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
- require_relative 'fixtures/server'
-
- describe "Net::FTP#quit" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "sends the QUIT command to the server" do
- @ftp.quit
- @ftp.last_response.should == "221 OK, bye\n"
- end
-
- it "does not close the socket automatically" do
- @ftp.quit
- @ftp.closed?.should be_false
- end
-
- it "returns nil" do
- @ftp.quit.should be_nil
- end
- end
-end
diff --git a/spec/ruby/library/net/ftp/rename_spec.rb b/spec/ruby/library/net/ftp/rename_spec.rb
deleted file mode 100644
index aa7c1360b5..0000000000
--- a/spec/ruby/library/net/ftp/rename_spec.rb
+++ /dev/null
@@ -1,97 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
- require_relative 'fixtures/server'
-
- describe "Net::FTP#rename" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- describe "when passed from_name, to_name" do
- it "sends the RNFR command with the passed from_name and the RNTO command with the passed to_name to the server" do
- @ftp.rename("from.file", "to.file")
- @ftp.last_response.should == "250 Requested file action okay, completed. (Renamed from.file to to.file)\n"
- end
-
- it "returns something" do
- @ftp.rename("from.file", "to.file").should be_nil
- end
- end
-
- describe "when the RNFR command fails" do
- it "raises a Net::FTPTempError when the response code is 450" do
- @server.should_receive(:rnfr).and_respond("450 Requested file action not taken.")
- -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 550" do
- @server.should_receive(:rnfr).and_respond("550 Requested action not taken.")
- -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:rnfr).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:rnfr).and_respond("502 Command not implemented.")
- -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:rnfr).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:rnfr).and_respond("530 Not logged in.")
- -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPPermError)
- end
- end
-
- describe "when the RNTO command fails" do
- it "raises a Net::FTPPermError when the response code is 532" do
- @server.should_receive(:rnfr).and_respond("532 Need account for storing files.")
- -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 553" do
- @server.should_receive(:rnto).and_respond("553 Requested action not taken.")
- -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:rnto).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:rnto).and_respond("502 Command not implemented.")
- -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:rnto).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:rnto).and_respond("530 Not logged in.")
- -> { @ftp.rename("from.file", "to.file") }.should raise_error(Net::FTPPermError)
- end
- end
- end
-end
diff --git a/spec/ruby/library/net/ftp/resume_spec.rb b/spec/ruby/library/net/ftp/resume_spec.rb
deleted file mode 100644
index 1b575c29f1..0000000000
--- a/spec/ruby/library/net/ftp/resume_spec.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
-
- describe "Net::FTP#resume" do
- it "returns true when self is set to resume uploads/downloads" do
- ftp = Net::FTP.new
- ftp.resume.should be_false
-
- ftp.resume = true
- ftp.resume.should be_true
- end
- end
-
- describe "Net::FTP#resume=" do
- it "sets self to resume uploads/downloads when set to true" do
- ftp = Net::FTP.new
- ftp.resume = true
- ftp.resume.should be_true
-
- ftp.resume = false
- ftp.resume.should be_false
- end
- end
-end
diff --git a/spec/ruby/library/net/ftp/retrbinary_spec.rb b/spec/ruby/library/net/ftp/retrbinary_spec.rb
deleted file mode 100644
index 1f89f0d454..0000000000
--- a/spec/ruby/library/net/ftp/retrbinary_spec.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
- require_relative 'fixtures/server'
-
- describe "Net::FTP#retrbinary" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "sends the passed command to the server" do
- @ftp.retrbinary("RETR test", 4096) {}
- @ftp.last_response.should == "226 Closing data connection. (RETR test)\n"
- end
-
- it "yields the received content as binary blocks of the passed size" do
- res = []
- @ftp.retrbinary("RETR test", 10) { |bin| res << bin }
- res.should == [ "This is th", "e content\n", "of the fil", "e named 't", "est'.\n" ]
- end
- end
-end
diff --git a/spec/ruby/library/net/ftp/retrlines_spec.rb b/spec/ruby/library/net/ftp/retrlines_spec.rb
deleted file mode 100644
index f26b008680..0000000000
--- a/spec/ruby/library/net/ftp/retrlines_spec.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
- require_relative 'fixtures/server'
-
- describe "Net::FTP#retrlines" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "sends the passed command over the socket" do
- @ftp.retrlines("LIST test.dir") {}
- @ftp.last_response.should == "226 transfer complete (LIST test.dir)\n"
- end
-
- it "yields each received line to the passed block" do
- res = []
- @ftp.retrlines("LIST test.dir") { |x| res << x }
- res.should == [
- "-rw-r--r-- 1 spec staff 507 17 Jul 18:41 last_response_code.rb",
- "-rw-r--r-- 1 spec staff 50 17 Jul 18:41 list.rb",
- "-rw-r--r-- 1 spec staff 48 17 Jul 18:41 pwd.rb"
- ]
- end
- end
-end
diff --git a/spec/ruby/library/net/ftp/return_code_spec.rb b/spec/ruby/library/net/ftp/return_code_spec.rb
deleted file mode 100644
index 67fc9d3b19..0000000000
--- a/spec/ruby/library/net/ftp/return_code_spec.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
-
- describe "Net::FTP#return_code" do
- before :each do
- @ftp = Net::FTP.new
- end
-
- it "outputs a warning and returns a newline" do
- -> do
- @ftp.return_code.should == "\n"
- end.should complain(/warning: Net::FTP#return_code is obsolete and do nothing/)
- end
- end
-
- describe "Net::FTP#return_code=" do
- before :each do
- @ftp = Net::FTP.new
- end
-
- it "outputs a warning" do
- -> { @ftp.return_code = 123 }.should complain(/warning: Net::FTP#return_code= is obsolete and do nothing/)
- end
- end
-end
diff --git a/spec/ruby/library/net/ftp/rmdir_spec.rb b/spec/ruby/library/net/ftp/rmdir_spec.rb
deleted file mode 100644
index 5b9586c6f0..0000000000
--- a/spec/ruby/library/net/ftp/rmdir_spec.rb
+++ /dev/null
@@ -1,61 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
- require_relative 'fixtures/server'
-
- describe "Net::FTP#rmdir" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "sends the RMD command with the passed pathname to the server" do
- @ftp.rmdir("test.folder")
- @ftp.last_response.should == "250 Requested file action okay, completed. (RMD test.folder)\n"
- end
-
- it "returns nil" do
- @ftp.rmdir("test.folder").should be_nil
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:rmd).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.rmdir("test.folder") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:rmd).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.rmdir("test.folder") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:rmd).and_respond("502 Command not implemented.")
- -> { @ftp.rmdir("test.folder") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:rmd).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.rmdir("test.folder") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:rmd).and_respond("530 Not logged in.")
- -> { @ftp.rmdir("test.folder") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 550" do
- @server.should_receive(:rmd).and_respond("550 Requested action not taken.")
- -> { @ftp.rmdir("test.folder") }.should raise_error(Net::FTPPermError)
- end
- end
-end
diff --git a/spec/ruby/library/net/ftp/sendcmd_spec.rb b/spec/ruby/library/net/ftp/sendcmd_spec.rb
deleted file mode 100644
index fefb89ae0b..0000000000
--- a/spec/ruby/library/net/ftp/sendcmd_spec.rb
+++ /dev/null
@@ -1,57 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
- require_relative 'fixtures/server'
-
- describe "Net::FTP#sendcmd" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "sends the passed command to the server" do
- @ftp.sendcmd("HELP")
- @ftp.last_response.should == "211 System status, or system help reply. (HELP)\n"
- end
-
- it "returns the server's response" do
- @ftp.sendcmd("HELP").should == "211 System status, or system help reply. (HELP)\n"
- end
-
- it "raises no error when the response code is 1xx, 2xx or 3xx" do
- @server.should_receive(:help).and_respond("120 Service ready in nnn minutes.")
- -> { @ftp.sendcmd("HELP") }.should_not raise_error
-
- @server.should_receive(:help).and_respond("200 Command okay.")
- -> { @ftp.sendcmd("HELP") }.should_not raise_error
-
- @server.should_receive(:help).and_respond("350 Requested file action pending further information.")
- -> { @ftp.sendcmd("HELP") }.should_not raise_error
- end
-
- it "raises a Net::FTPTempError when the response code is 4xx" do
- @server.should_receive(:help).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.sendcmd("HELP") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 5xx" do
- @server.should_receive(:help).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.sendcmd("HELP") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPProtoError when the response code is not between 1xx-5xx" do
- @server.should_receive(:help).and_respond("999 Invalid response.")
- -> { @ftp.sendcmd("HELP") }.should raise_error(Net::FTPProtoError)
- end
- end
-end
diff --git a/spec/ruby/library/net/ftp/set_socket_spec.rb b/spec/ruby/library/net/ftp/set_socket_spec.rb
deleted file mode 100644
index 6c8b58fb79..0000000000
--- a/spec/ruby/library/net/ftp/set_socket_spec.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
-
- describe "Net::FTP#set_socket" do
- # TODO: I won't spec this method, as it is not used
- # anywhere and it should be private anyway.
- it "needs to be reviewed for spec completeness"
- end
-end
diff --git a/spec/ruby/library/net/ftp/shared/getbinaryfile.rb b/spec/ruby/library/net/ftp/shared/getbinaryfile.rb
deleted file mode 100644
index f324f5b85d..0000000000
--- a/spec/ruby/library/net/ftp/shared/getbinaryfile.rb
+++ /dev/null
@@ -1,150 +0,0 @@
-describe :net_ftp_getbinaryfile, shared: :true do
- before :each do
- @fixture_file = File.dirname(__FILE__) + "/../fixtures/getbinaryfile"
- @tmp_file = tmp("getbinaryfile")
-
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- @ftp.binary = @binary_mode
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
-
- rm_r @tmp_file
- end
-
- it "sends the RETR command to the server" do
- @ftp.send(@method, "test", @tmp_file)
- @ftp.last_response.should == "226 Closing data connection. (RETR test)\n"
- end
-
- it "returns nil" do
- @ftp.send(@method, "test", @tmp_file).should be_nil
- end
-
- it "saves the contents of the passed remote file to the passed local file" do
- @ftp.send(@method, "test", @tmp_file)
- File.read(@tmp_file).should == "This is the content\nof the file named 'test'.\n"
- end
-
- describe "when passed a block" do
- it "yields the received content as binary blocks of the passed size" do
- res = []
- @ftp.send(@method, "test", @tmp_file, 10) { |bin| res << bin }
- res.should == [ "This is th", "e content\n", "of the fil", "e named 't", "est'.\n" ]
- end
- end
-
- describe "when resuming an existing file" do
- before :each do
- @tmp_file = tmp("getbinaryfile_resume")
-
- File.open(@tmp_file, "wb") do |f|
- f << "This is the content\n"
- end
-
- @ftp.resume = true
- end
-
- it "saves the remaining content of the passed remote file to the passed local file" do
- @ftp.send(@method, "test", @tmp_file)
- File.read(@tmp_file).should == "This is the content\nof the file named 'test'.\n"
- end
-
- describe "and the REST command fails" do
- it "raises a Net::FTPProtoError when the response code is 550" do
- @server.should_receive(:rest).and_respond("Requested action not taken.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPProtoError)
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:rest).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:rest).and_respond("501 Syntax error, command unrecognized.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:rest).and_respond("502 Command not implemented.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:rest).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:rest).and_respond("530 Not logged in.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
- end
- end
- end
-
- describe "when the RETR command fails" do
- it "raises a Net::FTPTempError when the response code is 450" do
- @server.should_receive(:retr).and_respond("450 Requested file action not taken.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPProtoError when the response code is 550" do
- @server.should_receive(:retr).and_respond("Requested action not taken.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPProtoError)
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:retr).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:retr).and_respond("501 Syntax error, command unrecognized.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:retr).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:retr).and_respond("530 Not logged in.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
- end
- end
-
- describe "when opening the data port fails" do
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:eprt).and_respond("500 Syntax error, command unrecognized.")
- @server.should_receive(:port).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:eprt).and_respond("501 Syntax error in parameters or arguments.")
- @server.should_receive(:port).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:eprt).and_respond("421 Service not available, closing control connection.")
- @server.should_receive(:port).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:eprt).and_respond("530 Not logged in.")
- @server.should_receive(:port).and_respond("530 Not logged in.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
- end
- end
-end
diff --git a/spec/ruby/library/net/ftp/shared/gettextfile.rb b/spec/ruby/library/net/ftp/shared/gettextfile.rb
deleted file mode 100644
index 82bec2a4a7..0000000000
--- a/spec/ruby/library/net/ftp/shared/gettextfile.rb
+++ /dev/null
@@ -1,100 +0,0 @@
-describe :net_ftp_gettextfile, shared: :true do
- before :each do
- @tmp_file = tmp("gettextfile")
-
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- @ftp.binary = @binary_mode
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
-
- rm_r @tmp_file
- end
-
- it "sends the RETR command to the server" do
- @ftp.send(@method, "test", @tmp_file)
- @ftp.last_response.should == "226 Closing data connection. (RETR test)\n"
- end
-
- it "returns nil" do
- @ftp.send(@method, "test", @tmp_file).should be_nil
- end
-
- it "saves the contents of the passed remote file to the passed local file" do
- @ftp.send(@method, "test", @tmp_file)
- File.read(@tmp_file).should == "This is the content\nof the file named 'test'.\n"
- end
-
- describe "when passed a block" do
- it "yields each line of the retrieved file to the passed block" do
- res = []
- @ftp.send(@method, "test", @tmp_file) { |line| res << line }
- res.should == [ "This is the content", "of the file named 'test'."]
- end
- end
-
- describe "when the RETR command fails" do
- it "raises a Net::FTPTempError when the response code is 450" do
- @server.should_receive(:retr).and_respond("450 Requested file action not taken.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPProtoError when the response code is 550" do
- @server.should_receive(:retr).and_respond("Requested action not taken.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPProtoError)
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:retr).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:retr).and_respond("501 Syntax error, command unrecognized.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:retr).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:retr).and_respond("530 Not logged in.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
- end
- end
-
- describe "when opening the data port fails" do
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:eprt).and_respond("500 Syntax error, command unrecognized.")
- @server.should_receive(:port).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:eprt).and_respond("501 Syntax error in parameters or arguments.")
- @server.should_receive(:port).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:eprt).and_respond("421 Service not available, closing control connection.")
- @server.should_receive(:port).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:eprt).and_respond("530 Not logged in.")
- @server.should_receive(:port).and_respond("530 Not logged in.")
- -> { @ftp.send(@method, "test", @tmp_file) }.should raise_error(Net::FTPPermError)
- end
- end
-end
diff --git a/spec/ruby/library/net/ftp/shared/putbinaryfile.rb b/spec/ruby/library/net/ftp/shared/putbinaryfile.rb
deleted file mode 100644
index 1163a1cfea..0000000000
--- a/spec/ruby/library/net/ftp/shared/putbinaryfile.rb
+++ /dev/null
@@ -1,167 +0,0 @@
-describe :net_ftp_putbinaryfile, shared: :true do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @local_fixture_file = File.dirname(__FILE__) + "/../fixtures/putbinaryfile"
- @remote_tmp_file = tmp("binaryfile", false)
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- @ftp.binary = @binary_mode
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
-
- rm_r @remote_tmp_file
- end
-
- it "sends the STOR command to the server" do
- @ftp.send(@method, @local_fixture_file, "binary")
- @ftp.last_response.should == "200 OK, Data received. (STOR binary)\n"
- end
-
- it "sends the contents of the passed local_file, without modifications" do
- @ftp.send(@method, @local_fixture_file, "binary")
-
- remote_lines = File.readlines(@remote_tmp_file)
- local_lines = File.readlines(@local_fixture_file)
-
- remote_lines.should == local_lines
- end
-
- it "returns nil" do
- @ftp.send(@method, @local_fixture_file, "binary").should be_nil
- end
-
- describe "when passed a block" do
- it "yields the transmitted content as binary blocks of the passed size" do
- res = []
- @ftp.send(@method, @local_fixture_file, "binary", 10) { |x| res << x }
- res.should == [
- "This is an", " example f",
- "ile\nwhich ", "is going t",
- "o be trans", "mitted\nusi",
- "ng #putbin", "aryfile.\n"
- ]
- end
- end
-
- describe "when resuming an existing file" do
- before :each do
- File.open(@remote_tmp_file, "w") do |f|
- f << "This is an example file\n"
- end
-
- @ftp.resume = true
- end
-
- it "sends the remaining content of the passed local_file to the passed remote_file" do
- @ftp.send(@method, @local_fixture_file, "binary")
- File.read(@remote_tmp_file).should == File.read(@local_fixture_file)
- end
-
- describe "and the APPE command fails" do
- it "raises a Net::FTPProtoError when the response code is 550" do
- @server.should_receive(:appe).and_respond("Requested action not taken.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPProtoError)
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:appe).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:appe).and_respond("501 Syntax error, command unrecognized.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:appe).and_respond("502 Command not implemented.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:appe).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:appe).and_respond("530 Not logged in.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
- end
- end
- end
-
- describe "when the STOR command fails" do
- it "raises a Net::FTPPermError when the response code is 532" do
- @server.should_receive(:stor).and_respond("532 Need account for storing files.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 450" do
- @server.should_receive(:stor).and_respond("450 Requested file action not taken.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPTempError when the response code is 452" do
- @server.should_receive(:stor).and_respond("452 Requested action not taken.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 553" do
- @server.should_receive(:stor).and_respond("553 Requested action not taken.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:stor).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:stor).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:stor).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:stor).and_respond("530 Not logged in.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
- end
- end
-
- describe "when opening the data port fails" do
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:eprt).and_respond("500 Syntax error, command unrecognized.")
- @server.should_receive(:port).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:eprt).and_respond("501 Syntax error in parameters or arguments.")
- @server.should_receive(:port).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:eprt).and_respond("421 Service not available, closing control connection.")
- @server.should_receive(:port).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:eprt).and_respond("530 Not logged in.")
- @server.should_receive(:port).and_respond("530 Not logged in.")
- -> { @ftp.send(@method, @local_fixture_file, "binary") }.should raise_error(Net::FTPPermError)
- end
- end
-end
diff --git a/spec/ruby/library/net/ftp/shared/puttextfile.rb b/spec/ruby/library/net/ftp/shared/puttextfile.rb
deleted file mode 100644
index 50e8de28e6..0000000000
--- a/spec/ruby/library/net/ftp/shared/puttextfile.rb
+++ /dev/null
@@ -1,120 +0,0 @@
-describe :net_ftp_puttextfile, shared: true do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @local_fixture_file = File.dirname(__FILE__) + "/../fixtures/puttextfile"
- @remote_tmp_file = tmp("textfile", false)
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- @ftp.binary = @binary_mode
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
-
- rm_r @remote_tmp_file
- end
-
- it "sends the STOR command to the server" do
- @ftp.send(@method, @local_fixture_file, "text")
- @ftp.last_response.should == "200 OK, Data received. (STOR text)\n"
- end
-
- it "sends the contents of the passed local_file, using \\r\\n as the newline separator" do
- @ftp.send(@method, @local_fixture_file, "text")
-
- remote_lines = open(@remote_tmp_file, "rb") {|f| f.read }
- local_lines = open(@local_fixture_file, "rb") {|f| f.read }
-
- remote_lines.should_not == local_lines
- remote_lines.should == local_lines.gsub("\n", "\r\n")
- end
-
- it "returns nil" do
- @ftp.send(@method, @local_fixture_file, "text").should be_nil
- end
-
- describe "when passed a block" do
- it "yields each transmitted line" do
- res = []
- @ftp.send(@method, @local_fixture_file, "text") { |x| res << x }
- res.should == [
- "This is an example file\r\n",
- "which is going to be transmitted\r\n",
- "using #puttextfile.\r\n"
- ]
- end
- end
-
- describe "when the STOR command fails" do
- it "raises a Net::FTPPermError when the response code is 532" do
- @server.should_receive(:stor).and_respond("532 Need account for storing files.")
- -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 450" do
- @server.should_receive(:stor).and_respond("450 Requested file action not taken.")
- -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPTempError when the response code is 452" do
- @server.should_receive(:stor).and_respond("452 Requested action not taken.")
- -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 553" do
- @server.should_receive(:stor).and_respond("553 Requested action not taken.")
- -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:stor).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:stor).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:stor).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:stor).and_respond("530 Not logged in.")
- -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPPermError)
- end
- end
-
- describe "when opening the data port fails" do
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:eprt).and_respond("500 Syntax error, command unrecognized.")
- @server.should_receive(:port).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:eprt).and_respond("501 Syntax error in parameters or arguments.")
- @server.should_receive(:port).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:eprt).and_respond("421 Service not available, closing control connection.")
- @server.should_receive(:port).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:eprt).and_respond("530 Not logged in.")
- @server.should_receive(:port).and_respond("530 Not logged in.")
- -> { @ftp.send(@method, @local_fixture_file, "text") }.should raise_error(Net::FTPPermError)
- end
- end
-end
diff --git a/spec/ruby/library/net/ftp/site_spec.rb b/spec/ruby/library/net/ftp/site_spec.rb
deleted file mode 100644
index ca4f499112..0000000000
--- a/spec/ruby/library/net/ftp/site_spec.rb
+++ /dev/null
@@ -1,56 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
- require_relative 'fixtures/server'
-
- describe "Net::FTP#site" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "sends the SITE command with the passed argument to the server" do
- @ftp.site("param")
- @ftp.last_response.should == "200 Command okay. (SITE param)\n"
- end
-
- it "returns nil" do
- @ftp.site("param").should be_nil
- end
-
- it "does not raise an error when the response code is 202" do
- @server.should_receive(:site).and_respond("202 Command not implemented, superfluous at this site.")
- -> { @ftp.site("param") }.should_not raise_error
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:site).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.site("param") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:site).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.site("param") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:site).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.site("param") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:site).and_respond("530 Requested action not taken.")
- -> { @ftp.site("param") }.should raise_error(Net::FTPPermError)
- end
- end
-end
diff --git a/spec/ruby/library/net/ftp/size_spec.rb b/spec/ruby/library/net/ftp/size_spec.rb
deleted file mode 100644
index 0c20b10549..0000000000
--- a/spec/ruby/library/net/ftp/size_spec.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
- require_relative 'fixtures/server'
-
- describe "Net::FTP#size" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "sends the SIZE command to the server" do
- @ftp.size("test.file")
- @ftp.last_response.should == "213 1024\n"
- end
-
- it "returns the size of the passed file as Integer" do
- @ftp.size("test.file").should eql(1024)
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:size).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.size("test.file") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:size).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.size("test.file") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:size).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.size("test.file") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 550" do
- @server.should_receive(:size).and_respond("550 Requested action not taken.")
- -> { @ftp.size("test.file") }.should raise_error(Net::FTPPermError)
- end
- end
-end
diff --git a/spec/ruby/library/net/ftp/status_spec.rb b/spec/ruby/library/net/ftp/status_spec.rb
deleted file mode 100644
index 03bc5d6e05..0000000000
--- a/spec/ruby/library/net/ftp/status_spec.rb
+++ /dev/null
@@ -1,70 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
- require_relative 'fixtures/server'
-
- describe "Net::FTP#status" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "sends the STAT command to the server" do
- @ftp.status
- @ftp.last_response.should == "211 System status, or system help reply. (STAT)\n"
- end
-
- it "sends the STAT command with an optional parameter to the server" do
- @ftp.status("/pub").should == "211 System status, or system help reply. (STAT /pub)\n"
- end
-
- it "returns the received information" do
- @ftp.status.should == "211 System status, or system help reply. (STAT)\n"
- end
-
- it "does not raise an error when the response code is 212" do
- @server.should_receive(:stat).and_respond("212 Directory status.")
- -> { @ftp.status }.should_not raise_error
- end
-
- it "does not raise an error when the response code is 213" do
- @server.should_receive(:stat).and_respond("213 File status.")
- -> { @ftp.status }.should_not raise_error
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:stat).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.status }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:stat).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.status }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:stat).and_respond("502 Command not implemented.")
- -> { @ftp.status }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:stat).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.status }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 530" do
- @server.should_receive(:stat).and_respond("530 Requested action not taken.")
- -> { @ftp.status }.should raise_error(Net::FTPPermError)
- end
- end
-end
diff --git a/spec/ruby/library/net/ftp/storbinary_spec.rb b/spec/ruby/library/net/ftp/storbinary_spec.rb
deleted file mode 100644
index 64c9090760..0000000000
--- a/spec/ruby/library/net/ftp/storbinary_spec.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
- require_relative 'fixtures/server'
-
- describe "Net::FTP#storbinary" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @local_fixture_file = File.dirname(__FILE__) + "/fixtures/putbinaryfile"
- @tmp_file = tmp("binaryfile", false)
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
-
- rm_r @tmp_file
- end
-
- it "sends the passed command and the passed File object's content to the server" do
- File.open(@local_fixture_file) do |f|
- f.binmode
-
- @ftp.storbinary("STOR binary", f, 4096) {}
- @ftp.last_response.should == "200 OK, Data received. (STOR binary)\n"
- end
- end
-
- it "yields the transmitted content as binary blocks of the passed size" do
- File.open(@local_fixture_file) do |f|
- f.binmode
-
- res = []
- @ftp.storbinary("STOR binary", f, 10) { |x| res << x }
- res.should == [
- "This is an", " example f",
- "ile\nwhich ", "is going t",
- "o be trans", "mitted\nusi",
- "ng #putbin", "aryfile.\n"
- ]
- end
- end
- end
-end
diff --git a/spec/ruby/library/net/ftp/storlines_spec.rb b/spec/ruby/library/net/ftp/storlines_spec.rb
deleted file mode 100644
index a4bb7af799..0000000000
--- a/spec/ruby/library/net/ftp/storlines_spec.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
- require_relative 'fixtures/server'
-
- describe "Net::FTP#storlines" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @local_fixture_file = File.dirname(__FILE__) + "/fixtures/puttextfile"
- @tmp_file = tmp("textfile", false)
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
-
- rm_r @tmp_file
- end
-
- it "sends the passed command and the passed File object's content to the server" do
- File.open(@local_fixture_file) do |f|
- @ftp.storlines("STOR text", f) {}
- @ftp.last_response.should == "200 OK, Data received. (STOR text)\n"
- end
- end
-
- it "yields each line of the transmitted content" do
- File.open(@local_fixture_file) do |f|
- res = []
- @ftp.storlines("STOR text", f) { |x| res << x }
- res.should == [
- "This is an example file\r\n",
- "which is going to be transmitted\r\n",
- "using #puttextfile.\r\n"
- ]
- end
- end
- end
-end
diff --git a/spec/ruby/library/net/ftp/system_spec.rb b/spec/ruby/library/net/ftp/system_spec.rb
deleted file mode 100644
index 0630bbe1f6..0000000000
--- a/spec/ruby/library/net/ftp/system_spec.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
- require_relative 'fixtures/server'
-
- describe "Net::FTP#system" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "sends the SYST command to the server" do
- @ftp.system
- @ftp.last_response.should =~ /\A215 FTP Dummy Server \(SYST\)\Z/
- end
-
- it "returns the received information" do
- @ftp.system.should =~ /\AFTP Dummy Server \(SYST\)\Z/
- end
-
- it "raises a Net::FTPPermError when the response code is 500" do
- @server.should_receive(:syst).and_respond("500 Syntax error, command unrecognized.")
- -> { @ftp.system }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 501" do
- @server.should_receive(:syst).and_respond("501 Syntax error in parameters or arguments.")
- -> { @ftp.system }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPPermError when the response code is 502" do
- @server.should_receive(:syst).and_respond("502 Command not implemented.")
- -> { @ftp.system }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPTempError when the response code is 421" do
- @server.should_receive(:syst).and_respond("421 Service not available, closing control connection.")
- -> { @ftp.system }.should raise_error(Net::FTPTempError)
- end
- end
-end
diff --git a/spec/ruby/library/net/ftp/voidcmd_spec.rb b/spec/ruby/library/net/ftp/voidcmd_spec.rb
deleted file mode 100644
index ee74455d63..0000000000
--- a/spec/ruby/library/net/ftp/voidcmd_spec.rb
+++ /dev/null
@@ -1,57 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
- require_relative 'fixtures/server'
-
- describe "Net::FTP#voidcmd" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "sends the passed command to the server" do
- @server.should_receive(:help).and_respond("2xx Does not raise.")
- -> { @ftp.voidcmd("HELP") }.should_not raise_error
- end
-
- it "returns nil" do
- @server.should_receive(:help).and_respond("2xx Does not raise.")
- @ftp.voidcmd("HELP").should be_nil
- end
-
- it "raises a Net::FTPReplyError when the response code is 1xx" do
- @server.should_receive(:help).and_respond("1xx Does raise a Net::FTPReplyError.")
- -> { @ftp.voidcmd("HELP") }.should raise_error(Net::FTPReplyError)
- end
-
- it "raises a Net::FTPReplyError when the response code is 3xx" do
- @server.should_receive(:help).and_respond("3xx Does raise a Net::FTPReplyError.")
- -> { @ftp.voidcmd("HELP") }.should raise_error(Net::FTPReplyError)
- end
-
- it "raises a Net::FTPTempError when the response code is 4xx" do
- @server.should_receive(:help).and_respond("4xx Does raise a Net::FTPTempError.")
- -> { @ftp.voidcmd("HELP") }.should raise_error(Net::FTPTempError)
- end
-
- it "raises a Net::FTPPermError when the response code is 5xx" do
- @server.should_receive(:help).and_respond("5xx Does raise a Net::FTPPermError.")
- -> { @ftp.voidcmd("HELP") }.should raise_error(Net::FTPPermError)
- end
-
- it "raises a Net::FTPProtoError when the response code is not valid" do
- @server.should_receive(:help).and_respond("999 Does raise a Net::FTPProtoError.")
- -> { @ftp.voidcmd("HELP") }.should raise_error(Net::FTPProtoError)
- end
- end
-end
diff --git a/spec/ruby/library/net/ftp/welcome_spec.rb b/spec/ruby/library/net/ftp/welcome_spec.rb
deleted file mode 100644
index e5414ef607..0000000000
--- a/spec/ruby/library/net/ftp/welcome_spec.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.1" do
- require_relative 'spec_helper'
- require_relative 'fixtures/server'
-
- describe "Net::FTP#welcome" do
- before :each do
- @server = NetFTPSpecs::DummyFTP.new
- @server.serve_once
-
- @ftp = Net::FTP.new
- @ftp.connect(@server.hostname, @server.server_port)
- end
-
- after :each do
- @ftp.quit rescue nil
- @ftp.close
- @server.stop
- end
-
- it "returns the server's welcome message" do
- @ftp.welcome.should be_nil
- @ftp.login
- @ftp.welcome.should == "230 User logged in, proceed. (USER anonymous)\n"
- end
- end
-end
diff --git a/spec/ruby/library/net/http/HTTPBadResponse_spec.rb b/spec/ruby/library/net/http/HTTPBadResponse_spec.rb
deleted file mode 100644
index be644968f5..0000000000
--- a/spec/ruby/library/net/http/HTTPBadResponse_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPBadResponse" do
- it "is a subclass of StandardError" do
- Net::HTTPBadResponse.should < StandardError
- end
-end
diff --git a/spec/ruby/library/net/http/HTTPClientExcepton_spec.rb b/spec/ruby/library/net/http/HTTPClientExcepton_spec.rb
deleted file mode 100644
index d576349a57..0000000000
--- a/spec/ruby/library/net/http/HTTPClientExcepton_spec.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPClientException" do
- it "is a subclass of Net::ProtoServerError" do
- Net::HTTPClientException.should < Net::ProtoServerError
- end
-
- it "includes the Net::HTTPExceptions module" do
- Net::HTTPClientException.should < Net::HTTPExceptions
- end
-end
diff --git a/spec/ruby/library/net/http/HTTPError_spec.rb b/spec/ruby/library/net/http/HTTPError_spec.rb
deleted file mode 100644
index ab5f491bb7..0000000000
--- a/spec/ruby/library/net/http/HTTPError_spec.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPError" do
- it "is a subclass of Net::ProtocolError" do
- Net::HTTPError.should < Net::ProtocolError
- end
-
- it "includes the Net::HTTPExceptions module" do
- Net::HTTPError.should < Net::HTTPExceptions
- end
-end
diff --git a/spec/ruby/library/net/http/HTTPFatalError_spec.rb b/spec/ruby/library/net/http/HTTPFatalError_spec.rb
deleted file mode 100644
index 6ab36bff6c..0000000000
--- a/spec/ruby/library/net/http/HTTPFatalError_spec.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPFatalError" do
- it "is a subclass of Net::ProtoFatalError" do
- Net::HTTPFatalError.should < Net::ProtoFatalError
- end
-
- it "includes the Net::HTTPExceptions module" do
- Net::HTTPFatalError.should < Net::HTTPExceptions
- end
-end
diff --git a/spec/ruby/library/net/http/HTTPHeaderSyntaxError_spec.rb b/spec/ruby/library/net/http/HTTPHeaderSyntaxError_spec.rb
deleted file mode 100644
index 38e9454f99..0000000000
--- a/spec/ruby/library/net/http/HTTPHeaderSyntaxError_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPHeaderSyntaxError" do
- it "is a subclass of StandardError" do
- Net::HTTPHeaderSyntaxError.should < StandardError
- end
-end
diff --git a/spec/ruby/library/net/http/HTTPRetriableError_spec.rb b/spec/ruby/library/net/http/HTTPRetriableError_spec.rb
deleted file mode 100644
index 3a4bb9146c..0000000000
--- a/spec/ruby/library/net/http/HTTPRetriableError_spec.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPRetriableError" do
- it "is a subclass of Net::ProtoRetriableError" do
- Net::HTTPRetriableError.should < Net::ProtoRetriableError
- end
-
- it "includes the Net::HTTPExceptions module" do
- Net::HTTPRetriableError.should < Net::HTTPExceptions
- end
-end
diff --git a/spec/ruby/library/net/http/HTTPServerException_spec.rb b/spec/ruby/library/net/http/HTTPServerException_spec.rb
deleted file mode 100644
index 23b0657364..0000000000
--- a/spec/ruby/library/net/http/HTTPServerException_spec.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-require_relative '../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPServerException" do
- it "is a subclass of Net::ProtoServerError and is warned as deprecated" do
- -> { Net::HTTPServerException.should < Net::ProtoServerError }.should complain(/warning: constant Net::HTTPServerException is deprecated/)
- end
-
- it "includes the Net::HTTPExceptions module and is warned as deprecated" do
- -> { Net::HTTPServerException.should < Net::HTTPExceptions }.should complain(/warning: constant Net::HTTPServerException is deprecated/)
- end
-end
diff --git a/spec/ruby/library/net/http/http/Proxy_spec.rb b/spec/ruby/library/net/http/http/Proxy_spec.rb
deleted file mode 100644
index f85ccc0ee9..0000000000
--- a/spec/ruby/library/net/http/http/Proxy_spec.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTP.Proxy" do
- it "returns a new subclass of Net::HTTP" do
- Net::HTTP.Proxy("localhost").should < Net::HTTP
- end
-
- it "returns Net::HTTP when the passed address is nil" do
- Net::HTTP.Proxy(nil).should == Net::HTTP
- end
-
- it "sets the returned subclasses' proxy options based on the passed arguments" do
- http_with_proxy = Net::HTTP.Proxy("localhost", 1234, "rspec", "rocks")
- http_with_proxy.proxy_address.should == "localhost"
- http_with_proxy.proxy_port.should eql(1234)
- http_with_proxy.proxy_user.should == "rspec"
- http_with_proxy.proxy_pass.should == "rocks"
- end
-end
-
-describe "Net::HTTP#proxy?" do
- describe "when self is no proxy class instance" do
- it "returns false" do
- Net::HTTP.new("localhost", 3333).proxy?.should be_false
- end
- end
-
- describe "when self is a proxy class instance" do
- it "returns false" do
- http_with_proxy = Net::HTTP.Proxy("localhost", 1234, "rspec", "rocks")
- http_with_proxy.new("localhost", 3333).proxy?.should be_true
- end
- end
-end
diff --git a/spec/ruby/library/net/http/http/active_spec.rb b/spec/ruby/library/net/http/http/active_spec.rb
deleted file mode 100644
index ef657243ba..0000000000
--- a/spec/ruby/library/net/http/http/active_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-require_relative 'shared/started'
-
-describe "Net::HTTP#active?" do
- it_behaves_like :net_http_started_p, :active?
-end
diff --git a/spec/ruby/library/net/http/http/address_spec.rb b/spec/ruby/library/net/http/http/address_spec.rb
deleted file mode 100644
index 5fce76d767..0000000000
--- a/spec/ruby/library/net/http/http/address_spec.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTP#address" do
- it "returns the current host name" do
- net = Net::HTTP.new("localhost")
- net.address.should == "localhost"
- end
-end
diff --git a/spec/ruby/library/net/http/http/close_on_empty_response_spec.rb b/spec/ruby/library/net/http/http/close_on_empty_response_spec.rb
deleted file mode 100644
index a97b7b6c43..0000000000
--- a/spec/ruby/library/net/http/http/close_on_empty_response_spec.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTP#close_on_empty_response" do
- it "needs to be reviewed for spec completeness"
-end
-
-describe "Net::HTTP#close_on_empty_response=" do
- it "needs to be reviewed for spec completeness"
-end
diff --git a/spec/ruby/library/net/http/http/copy_spec.rb b/spec/ruby/library/net/http/http/copy_spec.rb
deleted file mode 100644
index 5ebfdc334e..0000000000
--- a/spec/ruby/library/net/http/http/copy_spec.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-
-describe "Net::HTTP#copy" do
- before :each do
- NetHTTPSpecs.start_server
- @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
- end
-
- after :each do
- @http.finish if @http.started?
- NetHTTPSpecs.stop_server
- end
-
- it "sends a COPY request to the passed path and returns the response" do
- response = @http.copy("/request")
- response.should be_kind_of(Net::HTTPResponse)
- response.body.should == "Request type: COPY"
- end
-end
diff --git a/spec/ruby/library/net/http/http/default_port_spec.rb b/spec/ruby/library/net/http/http/default_port_spec.rb
deleted file mode 100644
index 30db18efae..0000000000
--- a/spec/ruby/library/net/http/http/default_port_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTP.default_port" do
- it "returns 80" do
- Net::HTTP.http_default_port.should eql(80)
- end
-end
diff --git a/spec/ruby/library/net/http/http/delete_spec.rb b/spec/ruby/library/net/http/http/delete_spec.rb
deleted file mode 100644
index 160c653115..0000000000
--- a/spec/ruby/library/net/http/http/delete_spec.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-
-describe "Net::HTTP#delete" do
- before :each do
- NetHTTPSpecs.start_server
- @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
- end
-
- after :each do
- @http.finish if @http.started?
- NetHTTPSpecs.stop_server
- end
-
- it "sends a DELETE request to the passed path and returns the response" do
- response = @http.delete("/request")
- response.should be_kind_of(Net::HTTPResponse)
- response.body.should == "Request type: DELETE"
- end
-end
diff --git a/spec/ruby/library/net/http/http/finish_spec.rb b/spec/ruby/library/net/http/http/finish_spec.rb
deleted file mode 100644
index f98bc7be13..0000000000
--- a/spec/ruby/library/net/http/http/finish_spec.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-
-describe "Net::HTTP#finish" do
- before :each do
- NetHTTPSpecs.start_server
- @http = Net::HTTP.new("localhost", NetHTTPSpecs.port)
- end
-
- after :each do
- @http.finish if @http.started?
- NetHTTPSpecs.stop_server
- end
-
- describe "when self has been started" do
- it "closes the tcp connection" do
- @http.start
- @http.finish
- @http.started?.should be_false
- end
- end
-
- describe "when self has not been started yet" do
- it "raises an IOError" do
- -> { @http.finish }.should raise_error(IOError)
- end
- end
-end
diff --git a/spec/ruby/library/net/http/http/get2_spec.rb b/spec/ruby/library/net/http/http/get2_spec.rb
deleted file mode 100644
index 519e4c2599..0000000000
--- a/spec/ruby/library/net/http/http/get2_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-require_relative 'shared/request_get'
-
-describe "Net::HTTP#get2" do
- it_behaves_like :net_http_request_get, :get2
-end
diff --git a/spec/ruby/library/net/http/http/get_print_spec.rb b/spec/ruby/library/net/http/http/get_print_spec.rb
deleted file mode 100644
index f59dd68c81..0000000000
--- a/spec/ruby/library/net/http/http/get_print_spec.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-
-describe "Net::HTTP.get_print" do
- before :each do
- NetHTTPSpecs.start_server
- @port = NetHTTPSpecs.port
- end
-
- after :each do
- NetHTTPSpecs.stop_server
- end
-
- describe "when passed URI" do
- it "it prints the body of the specified uri to $stdout" do
- -> do
- Net::HTTP.get_print URI.parse("http://localhost:#{@port}/")
- end.should output(/This is the index page\./)
- end
- end
-
- describe "when passed host, path, port" do
- it "it prints the body of the specified uri to $stdout" do
- -> do
- Net::HTTP.get_print 'localhost', "/", @port
- end.should output(/This is the index page\./)
- end
- end
-end
diff --git a/spec/ruby/library/net/http/http/get_response_spec.rb b/spec/ruby/library/net/http/http/get_response_spec.rb
deleted file mode 100644
index 941b35e773..0000000000
--- a/spec/ruby/library/net/http/http/get_response_spec.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-
-describe "Net::HTTP.get_response" do
- before :each do
- NetHTTPSpecs.start_server
- @port = NetHTTPSpecs.port
- end
-
- after :each do
- NetHTTPSpecs.stop_server
- end
-
- describe "when passed URI" do
- it "returns the response for the specified uri" do
- res = Net::HTTP.get_response(URI.parse("http://localhost:#{@port}/"))
- res.content_type.should == "text/plain"
- res.body.should == "This is the index page."
- end
- end
-
- describe "when passed host, path, port" do
- it "returns the response for the specified host-path-combination" do
- res = Net::HTTP.get_response('localhost', "/", @port)
- res.content_type.should == "text/plain"
- res.body.should == "This is the index page."
- end
- end
-end
diff --git a/spec/ruby/library/net/http/http/get_spec.rb b/spec/ruby/library/net/http/http/get_spec.rb
deleted file mode 100644
index 9f6c45f26b..0000000000
--- a/spec/ruby/library/net/http/http/get_spec.rb
+++ /dev/null
@@ -1,96 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-
-describe "Net::HTTP.get" do
- before :each do
- NetHTTPSpecs.start_server
- @port = NetHTTPSpecs.port
- end
-
- after :each do
- NetHTTPSpecs.stop_server
- end
-
- describe "when passed URI" do
- it "returns the body of the specified uri" do
- Net::HTTP.get(URI.parse("http://localhost:#{@port}/")).should == "This is the index page."
- end
- end
-
- describe "when passed host, path, port" do
- it "returns the body of the specified host-path-combination" do
- Net::HTTP.get('localhost', "/", @port).should == "This is the index page."
- end
- end
-end
-
-quarantine! do # These specs fail frequently with CHECK_LEAKS=true
-describe "Net::HTTP.get" do
- describe "when reading gzipped contents" do
- def start_threads
- require 'zlib'
- require 'stringio'
-
- server = nil
- server_thread = Thread.new do
- server = TCPServer.new("127.0.0.1", 0)
- begin
- c = server.accept
- ensure
- server.close
- end
- c.print "HTTP/1.1 200\r\n"
- c.print "Content-Type: text/plain\r\n"
- c.print "Content-Encoding: gzip\r\n"
- s = StringIO.new
- z = Zlib::GzipWriter.new(s)
- begin
- z.write 'Hello World!'
- ensure
- z.close
- end
- c.print "Content-Length: #{s.length}\r\n\r\n"
- # Write partial gzip content
- c.write s.string.byteslice(0..-2)
- c.flush
- c
- end
- Thread.pass until server && server_thread.stop?
-
- client_thread = Thread.new do
- Thread.current.report_on_exception = false
- Net::HTTP.get("127.0.0.1", '/', server.connect_address.ip_port)
- end
-
- socket = server_thread.value
- Thread.pass until client_thread.stop?
-
- [socket, client_thread]
- end
-
- it "propagates exceptions interrupting the thread and does not replace it with Zlib::BufError" do
- my_exception = Class.new(RuntimeError)
- socket, client_thread = start_threads
- begin
- client_thread.raise my_exception, "my exception"
- -> { client_thread.value }.should raise_error(my_exception)
- ensure
- socket.close
- end
- end
-
- ruby_version_is "3.0" do # https://bugs.ruby-lang.org/issues/13882#note-6
- it "lets the kill Thread exception goes through and does not replace it with Zlib::BufError" do
- socket, client_thread = start_threads
- begin
- client_thread.kill
- client_thread.value.should == nil
- ensure
- socket.close
- end
- end
- end
- end
-end
-end
diff --git a/spec/ruby/library/net/http/http/head2_spec.rb b/spec/ruby/library/net/http/http/head2_spec.rb
deleted file mode 100644
index 6958204ee1..0000000000
--- a/spec/ruby/library/net/http/http/head2_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-require_relative 'shared/request_head'
-
-describe "Net::HTTP#head2" do
- it_behaves_like :net_http_request_head, :head2
-end
diff --git a/spec/ruby/library/net/http/http/head_spec.rb b/spec/ruby/library/net/http/http/head_spec.rb
deleted file mode 100644
index 925a8e6043..0000000000
--- a/spec/ruby/library/net/http/http/head_spec.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-
-describe "Net::HTTP#head" do
- before :each do
- NetHTTPSpecs.start_server
- @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
- end
-
- after :each do
- @http.finish if @http.started?
- NetHTTPSpecs.stop_server
- end
-
- it "sends a HEAD request to the passed path and returns the response" do
- response = @http.head("/request")
- # HEAD requests have no responses
- response.body.should be_nil
- end
-
- it "returns a Net::HTTPResponse" do
- @http.head("/request").should be_kind_of(Net::HTTPResponse)
- end
-end
diff --git a/spec/ruby/library/net/http/http/http_default_port_spec.rb b/spec/ruby/library/net/http/http/http_default_port_spec.rb
deleted file mode 100644
index cf7f73e630..0000000000
--- a/spec/ruby/library/net/http/http/http_default_port_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTP.http_default_port" do
- it "returns 80" do
- Net::HTTP.http_default_port.should eql(80)
- end
-end
diff --git a/spec/ruby/library/net/http/http/https_default_port_spec.rb b/spec/ruby/library/net/http/http/https_default_port_spec.rb
deleted file mode 100644
index fbf0bd1abc..0000000000
--- a/spec/ruby/library/net/http/http/https_default_port_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTP.https_default_port" do
- it "returns 443" do
- Net::HTTP.https_default_port.should eql(443)
- end
-end
diff --git a/spec/ruby/library/net/http/http/initialize_spec.rb b/spec/ruby/library/net/http/http/initialize_spec.rb
deleted file mode 100644
index 7683713a0e..0000000000
--- a/spec/ruby/library/net/http/http/initialize_spec.rb
+++ /dev/null
@@ -1,46 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTP#initialize" do
- it "is private" do
- Net::HTTP.should have_private_instance_method(:initialize)
- end
-
- describe "when passed address" do
- before :each do
- @net = Net::HTTP.allocate
- @net.send(:initialize, "localhost")
- end
-
- it "sets the new Net::HTTP instance's address to the passed address" do
- @net.address.should == "localhost"
- end
-
- it "sets the new Net::HTTP instance's port to the default HTTP port" do
- @net.port.should eql(Net::HTTP.default_port)
- end
-
- it "does not start the new Net::HTTP instance" do
- @net.started?.should be_false
- end
- end
-
- describe "when passed address, port" do
- before :each do
- @net = Net::HTTP.allocate
- @net.send(:initialize, "localhost", 3333)
- end
-
- it "sets the new Net::HTTP instance's address to the passed address" do
- @net.address.should == "localhost"
- end
-
- it "sets the new Net::HTTP instance's port to the passed port" do
- @net.port.should eql(3333)
- end
-
- it "does not start the new Net::HTTP instance" do
- @net.started?.should be_false
- end
- end
-end
diff --git a/spec/ruby/library/net/http/http/inspect_spec.rb b/spec/ruby/library/net/http/http/inspect_spec.rb
deleted file mode 100644
index b1e799ca34..0000000000
--- a/spec/ruby/library/net/http/http/inspect_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-
-describe "Net::HTTP#inspect" do
- before :each do
- NetHTTPSpecs.start_server
- @port = NetHTTPSpecs.port
- @http = Net::HTTP.new("localhost", @port)
- end
-
- after :each do
- @http.finish if @http.started?
- NetHTTPSpecs.stop_server
- end
-
- it "returns a String representation of self" do
- @http.inspect.should be_kind_of(String)
- @http.inspect.should == "#<Net::HTTP localhost:#{@port} open=false>"
-
- @http.start
- @http.inspect.should == "#<Net::HTTP localhost:#{@port} open=true>"
- end
-end
diff --git a/spec/ruby/library/net/http/http/is_version_1_1_spec.rb b/spec/ruby/library/net/http/http/is_version_1_1_spec.rb
deleted file mode 100644
index f37695b777..0000000000
--- a/spec/ruby/library/net/http/http/is_version_1_1_spec.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'shared/version_1_1'
-
-describe "Net::HTTP.is_version_1_1?" do
- it_behaves_like :net_http_version_1_1_p, :is_version_1_1?
-end
diff --git a/spec/ruby/library/net/http/http/is_version_1_2_spec.rb b/spec/ruby/library/net/http/http/is_version_1_2_spec.rb
deleted file mode 100644
index 82dbdc87aa..0000000000
--- a/spec/ruby/library/net/http/http/is_version_1_2_spec.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'shared/version_1_2'
-
-describe "Net::HTTP.is_version_1_2?" do
- it_behaves_like :net_http_version_1_2_p, :is_version_1_2?
-end
diff --git a/spec/ruby/library/net/http/http/lock_spec.rb b/spec/ruby/library/net/http/http/lock_spec.rb
deleted file mode 100644
index bb76607a8b..0000000000
--- a/spec/ruby/library/net/http/http/lock_spec.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-
-describe "Net::HTTP#lock" do
- before :each do
- NetHTTPSpecs.start_server
- @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
- end
-
- after :each do
- @http.finish if @http.started?
- NetHTTPSpecs.stop_server
- end
-
- it "sends a LOCK request to the passed path and returns the response" do
- response = @http.lock("/request", "test=test")
- response.should be_kind_of(Net::HTTPResponse)
- response.body.should == "Request type: LOCK"
- end
-end
diff --git a/spec/ruby/library/net/http/http/mkcol_spec.rb b/spec/ruby/library/net/http/http/mkcol_spec.rb
deleted file mode 100644
index 33017625e2..0000000000
--- a/spec/ruby/library/net/http/http/mkcol_spec.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-
-describe "Net::HTTP#mkcol" do
- before :each do
- NetHTTPSpecs.start_server
- @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
- end
-
- after :each do
- @http.finish if @http.started?
- NetHTTPSpecs.stop_server
- end
-
- it "sends a MKCOL request to the passed path and returns the response" do
- response = @http.mkcol("/request")
- response.should be_kind_of(Net::HTTPResponse)
- response.body.should == "Request type: MKCOL"
- end
-end
diff --git a/spec/ruby/library/net/http/http/move_spec.rb b/spec/ruby/library/net/http/http/move_spec.rb
deleted file mode 100644
index 4d6b828150..0000000000
--- a/spec/ruby/library/net/http/http/move_spec.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-
-describe "Net::HTTP#head" do
- before :each do
- NetHTTPSpecs.start_server
- @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
- end
-
- after :each do
- @http.finish if @http.started?
- NetHTTPSpecs.stop_server
- end
-
- it "sends a MOVE request to the passed path and returns the response" do
- response = @http.move("/request")
- # HEAD requests have no responses
- response.body.should == "Request type: MOVE"
- end
-
- it "returns a Net::HTTPResponse" do
- @http.move("/request").should be_kind_of(Net::HTTPResponse)
- end
-end
diff --git a/spec/ruby/library/net/http/http/new_spec.rb b/spec/ruby/library/net/http/http/new_spec.rb
deleted file mode 100644
index 491d1d01fd..0000000000
--- a/spec/ruby/library/net/http/http/new_spec.rb
+++ /dev/null
@@ -1,86 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTP.new" do
- describe "when passed address" do
- before :each do
- @http = Net::HTTP.new("localhost")
- end
-
- it "returns a Net::HTTP instance" do
- @http.proxy?.should be_false
- @http.instance_of?(Net::HTTP).should be_true
- end
-
- it "sets the new Net::HTTP instance's address to the passed address" do
- @http.address.should == "localhost"
- end
-
- it "sets the new Net::HTTP instance's port to the default HTTP port" do
- @http.port.should eql(Net::HTTP.default_port)
- end
-
- it "does not start the new Net::HTTP instance" do
- @http.started?.should be_false
- end
- end
-
- describe "when passed address, port" do
- before :each do
- @http = Net::HTTP.new("localhost", 3333)
- end
-
- it "returns a Net::HTTP instance" do
- @http.proxy?.should be_false
- @http.instance_of?(Net::HTTP).should be_true
- end
-
- it "sets the new Net::HTTP instance's address to the passed address" do
- @http.address.should == "localhost"
- end
-
- it "sets the new Net::HTTP instance's port to the passed port" do
- @http.port.should eql(3333)
- end
-
- it "does not start the new Net::HTTP instance" do
- @http.started?.should be_false
- end
- end
-
- describe "when passed address, port, *proxy_options" do
- it "returns a Net::HTTP instance" do
- http = Net::HTTP.new("localhost", 3333, "localhost")
- http.proxy?.should be_true
- http.instance_of?(Net::HTTP).should be_true
- http.should be_kind_of(Net::HTTP)
- end
-
- it "correctly sets the passed Proxy options" do
- http = Net::HTTP.new("localhost", 3333, "localhost")
- http.proxy_address.should == "localhost"
- http.proxy_port.should eql(80)
- http.proxy_user.should be_nil
- http.proxy_pass.should be_nil
-
- http = Net::HTTP.new("localhost", 3333, "localhost", 1234)
- http.proxy_address.should == "localhost"
- http.proxy_port.should eql(1234)
- http.proxy_user.should be_nil
- http.proxy_pass.should be_nil
-
- http = Net::HTTP.new("localhost", 3333, "localhost", 1234, "rubyspec")
- http.proxy_address.should == "localhost"
- http.proxy_port.should eql(1234)
- http.proxy_user.should == "rubyspec"
- http.proxy_pass.should be_nil
-
- http = Net::HTTP.new("localhost", 3333, "localhost", 1234, "rubyspec", "rocks")
- http.proxy_address.should == "localhost"
- http.proxy_port.should eql(1234)
- http.proxy_user.should == "rubyspec"
- http.proxy_pass.should == "rocks"
- end
- end
-
-end
diff --git a/spec/ruby/library/net/http/http/newobj_spec.rb b/spec/ruby/library/net/http/http/newobj_spec.rb
deleted file mode 100644
index b261dcc5db..0000000000
--- a/spec/ruby/library/net/http/http/newobj_spec.rb
+++ /dev/null
@@ -1,48 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTP.newobj" do
- before :each do
- @net = Net::HTTP.newobj("localhost")
- end
-
- describe "when passed address" do
- it "returns a new Net::HTTP instance" do
- @net.should be_kind_of(Net::HTTP)
- end
-
- it "sets the new Net::HTTP instance's address to the passed address" do
- @net.address.should == "localhost"
- end
-
- it "sets the new Net::HTTP instance's port to the default HTTP port" do
- @net.port.should eql(Net::HTTP.default_port)
- end
-
- it "does not start the new Net::HTTP instance" do
- @net.started?.should be_false
- end
- end
-
- describe "when passed address, port" do
- before :each do
- @net = Net::HTTP.newobj("localhost", 3333)
- end
-
- it "returns a new Net::HTTP instance" do
- @net.should be_kind_of(Net::HTTP)
- end
-
- it "sets the new Net::HTTP instance's address to the passed address" do
- @net.address.should == "localhost"
- end
-
- it "sets the new Net::HTTP instance's port to the passed port" do
- @net.port.should eql(3333)
- end
-
- it "does not start the new Net::HTTP instance" do
- @net.started?.should be_false
- end
- end
-end
diff --git a/spec/ruby/library/net/http/http/open_timeout_spec.rb b/spec/ruby/library/net/http/http/open_timeout_spec.rb
deleted file mode 100644
index 44b33615e6..0000000000
--- a/spec/ruby/library/net/http/http/open_timeout_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTP#open_timeout" do
- it "returns the seconds to wait till the connection is open" do
- net = Net::HTTP.new("localhost")
- net.open_timeout.should eql(60)
- net.open_timeout = 10
- net.open_timeout.should eql(10)
- end
-end
-
-describe "Net::HTTP#open_timeout=" do
- it "sets the seconds to wait till the connection is open" do
- net = Net::HTTP.new("localhost")
- net.open_timeout = 10
- net.open_timeout.should eql(10)
- end
-
- it "returns the newly set value" do
- net = Net::HTTP.new("localhost")
- (net.open_timeout = 10).should eql(10)
- end
-end
diff --git a/spec/ruby/library/net/http/http/options_spec.rb b/spec/ruby/library/net/http/http/options_spec.rb
deleted file mode 100644
index d798e69197..0000000000
--- a/spec/ruby/library/net/http/http/options_spec.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-
-describe "Net::HTTP#options" do
- before :each do
- NetHTTPSpecs.start_server
- @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
- end
-
- after :each do
- @http.finish if @http.started?
- NetHTTPSpecs.stop_server
- end
-
- it "sends an options request to the passed path and returns the response" do
- response = @http.options("/request")
-
- response.body.should == "Request type: OPTIONS"
- end
-
- it "returns a Net::HTTPResponse" do
- @http.options("/request").should be_kind_of(Net::HTTPResponse)
- end
-end
diff --git a/spec/ruby/library/net/http/http/port_spec.rb b/spec/ruby/library/net/http/http/port_spec.rb
deleted file mode 100644
index 7de295ca75..0000000000
--- a/spec/ruby/library/net/http/http/port_spec.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTP#port" do
- it "returns the current port number" do
- net = Net::HTTP.new("localhost", 3333)
- net.port.should eql(3333)
- end
-end
diff --git a/spec/ruby/library/net/http/http/post2_spec.rb b/spec/ruby/library/net/http/http/post2_spec.rb
deleted file mode 100644
index ccc95068fb..0000000000
--- a/spec/ruby/library/net/http/http/post2_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-require_relative 'shared/request_post'
-
-describe "Net::HTTP#post2" do
- it_behaves_like :net_http_request_post, :post2
-end
diff --git a/spec/ruby/library/net/http/http/post_form_spec.rb b/spec/ruby/library/net/http/http/post_form_spec.rb
deleted file mode 100644
index 891e05e7af..0000000000
--- a/spec/ruby/library/net/http/http/post_form_spec.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-
-describe "Net::HTTP.post_form when passed URI" do
- before :each do
- NetHTTPSpecs.start_server
- @port = NetHTTPSpecs.port
- end
-
- after :each do
- NetHTTPSpecs.stop_server
- end
-
- it "POSTs the passed form data to the given uri" do
- uri = URI.parse("http://localhost:#{@port}/request/body")
- data = { test: :data }
-
- res = Net::HTTP.post_form(uri, data)
- res.body.should == "test=data"
- end
-end
diff --git a/spec/ruby/library/net/http/http/post_spec.rb b/spec/ruby/library/net/http/http/post_spec.rb
deleted file mode 100644
index 891e20aaca..0000000000
--- a/spec/ruby/library/net/http/http/post_spec.rb
+++ /dev/null
@@ -1,74 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require 'uri'
-require_relative 'fixtures/http_server'
-
-describe "Net::HTTP.post" do
- before :each do
- NetHTTPSpecs.start_server
- end
-
- after :each do
- NetHTTPSpecs.stop_server
- end
-
- it "sends post request to the specified URI and returns response" do
- response = Net::HTTP.post(
- URI("http://localhost:#{NetHTTPSpecs.port}/request"),
- '{ "q": "ruby", "max": "50" }',
- "Content-Type" => "application/json")
- response.body.should == "Request type: POST"
- end
-
- it "returns a Net::HTTPResponse" do
- response = Net::HTTP.post(URI("http://localhost:#{NetHTTPSpecs.port}/request"), "test=test")
- response.should be_kind_of(Net::HTTPResponse)
- end
-
- it "sends Content-Type: application/x-www-form-urlencoded by default" do
- response = Net::HTTP.post(URI("http://localhost:#{NetHTTPSpecs.port}/request/header"), "test=test")
- response.body.should include('"Content-Type"=>"application/x-www-form-urlencoded"')
- end
-
- it "does not support HTTP Basic Auth" do
- response = Net::HTTP.post(
- URI("http://john:qwerty@localhost:#{NetHTTPSpecs.port}/request/basic_auth"),
- "test=test")
- response.body.should == "username: \npassword: "
- end
-end
-
-describe "Net::HTTP#post" do
- before :each do
- NetHTTPSpecs.start_server
- @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
- end
-
- after :each do
- @http.finish if @http.started?
- NetHTTPSpecs.stop_server
- end
-
- it "sends an post request to the passed path and returns the response" do
- response = @http.post("/request", "test=test")
- response.body.should == "Request type: POST"
- end
-
- it "returns a Net::HTTPResponse" do
- @http.post("/request", "test=test").should be_kind_of(Net::HTTPResponse)
- end
-
- describe "when passed a block" do
- it "yields fragments of the response body to the passed block" do
- str = ""
- @http.post("/request", "test=test") do |res|
- str << res
- end
- str.should == "Request type: POST"
- end
-
- it "returns a Net::HTTPResponse" do
- @http.post("/request", "test=test") {}.should be_kind_of(Net::HTTPResponse)
- end
- end
-end
diff --git a/spec/ruby/library/net/http/http/propfind_spec.rb b/spec/ruby/library/net/http/http/propfind_spec.rb
deleted file mode 100644
index 5240171618..0000000000
--- a/spec/ruby/library/net/http/http/propfind_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-
-describe "Net::HTTP#propfind" do
- before :each do
- NetHTTPSpecs.start_server
- @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
- end
-
- after :each do
- @http.finish if @http.started?
- NetHTTPSpecs.stop_server
- end
-
- it "sends an propfind request to the passed path and returns the response" do
- response = @http.propfind("/request", "test=test")
- response.body.should == "Request type: PROPFIND"
- end
-
- it "returns a Net::HTTPResponse" do
- @http.propfind("/request", "test=test").should be_kind_of(Net::HTTPResponse)
- end
-end
diff --git a/spec/ruby/library/net/http/http/proppatch_spec.rb b/spec/ruby/library/net/http/http/proppatch_spec.rb
deleted file mode 100644
index 7a761a9f23..0000000000
--- a/spec/ruby/library/net/http/http/proppatch_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-
-describe "Net::HTTP#proppatch" do
- before :each do
- NetHTTPSpecs.start_server
- @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
- end
-
- after :each do
- @http.finish if @http.started?
- NetHTTPSpecs.stop_server
- end
-
- it "sends an proppatch request to the passed path and returns the response" do
- response = @http.proppatch("/request", "test=test")
- response.body.should == "Request type: PROPPATCH"
- end
-
- it "returns a Net::HTTPResponse" do
- @http.proppatch("/request", "test=test").should be_kind_of(Net::HTTPResponse)
- end
-end
diff --git a/spec/ruby/library/net/http/http/proxy_address_spec.rb b/spec/ruby/library/net/http/http/proxy_address_spec.rb
deleted file mode 100644
index 8d152b8d44..0000000000
--- a/spec/ruby/library/net/http/http/proxy_address_spec.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTP.proxy_address" do
- describe "when self is no proxy class" do
- it "returns nil" do
- Net::HTTP.proxy_address.should be_nil
- end
- end
-
- describe "when self is a proxy class" do
- it "returns the address for self's proxy connection" do
- Net::HTTP.Proxy("localhost", 1234, "rspec", "rocks").proxy_address.should == "localhost"
- end
- end
-end
-
-describe "Net::HTTP#proxy_address" do
- describe "when self is no proxy class instance" do
- it "returns nil" do
- Net::HTTP.new("localhost", 3333).proxy_address.should be_nil
- end
- end
-
- describe "when self is a proxy class instance" do
- it "returns the password for self's proxy connection" do
- http_with_proxy = Net::HTTP.Proxy("localhost", 1234, "rspec", "rocks")
- http_with_proxy.new("localhost", 3333).proxy_address.should == "localhost"
- end
- end
-end
diff --git a/spec/ruby/library/net/http/http/proxy_class_spec.rb b/spec/ruby/library/net/http/http/proxy_class_spec.rb
deleted file mode 100644
index 2d32a39f01..0000000000
--- a/spec/ruby/library/net/http/http/proxy_class_spec.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTP.proxy_class?" do
- it "returns true if self is a class created with Net::HTTP.Proxy" do
- Net::HTTP.proxy_class?.should be_false
- Net::HTTP.Proxy("localhost").proxy_class?.should be_true
- end
-end
diff --git a/spec/ruby/library/net/http/http/proxy_pass_spec.rb b/spec/ruby/library/net/http/http/proxy_pass_spec.rb
deleted file mode 100644
index 94a0034544..0000000000
--- a/spec/ruby/library/net/http/http/proxy_pass_spec.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTP.proxy_pass" do
- describe "when self is no proxy class" do
- it "returns nil" do
- Net::HTTP.proxy_pass.should be_nil
- end
- end
-
- describe "when self is a proxy class" do
- it "returns nil if no password was set for self's proxy connection" do
- Net::HTTP.Proxy("localhost").proxy_pass.should be_nil
- end
-
- it "returns the password for self's proxy connection" do
- Net::HTTP.Proxy("localhost", 1234, "rspec", "rocks").proxy_pass.should == "rocks"
- end
- end
-end
-
-describe "Net::HTTP#proxy_pass" do
- describe "when self is no proxy class instance" do
- it "returns nil" do
- Net::HTTP.new("localhost", 3333).proxy_pass.should be_nil
- end
- end
-
- describe "when self is a proxy class instance" do
- it "returns nil if no password was set for self's proxy connection" do
- Net::HTTP.Proxy("localhost").new("localhost", 3333).proxy_pass.should be_nil
- end
-
- it "returns the password for self's proxy connection" do
- http_with_proxy = Net::HTTP.Proxy("localhost", 1234, "rspec", "rocks")
- http_with_proxy.new("localhost", 3333).proxy_pass.should == "rocks"
- end
- end
-end
diff --git a/spec/ruby/library/net/http/http/proxy_port_spec.rb b/spec/ruby/library/net/http/http/proxy_port_spec.rb
deleted file mode 100644
index 339f7ee850..0000000000
--- a/spec/ruby/library/net/http/http/proxy_port_spec.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTP.proxy_port" do
- describe "when self is no proxy class" do
- it "returns nil" do
- Net::HTTP.proxy_port.should be_nil
- end
- end
-
- describe "when self is a proxy class" do
- it "returns 80 if no port was set for self's proxy connection" do
- Net::HTTP.Proxy("localhost").proxy_port.should eql(80)
- end
-
- it "returns the port for self's proxy connection" do
- Net::HTTP.Proxy("localhost", 1234, "rspec", "rocks").proxy_port.should eql(1234)
- end
- end
-end
-
-describe "Net::HTTP#proxy_port" do
- describe "when self is no proxy class instance" do
- it "returns nil" do
- Net::HTTP.new("localhost", 3333).proxy_port.should be_nil
- end
- end
-
- describe "when self is a proxy class instance" do
- it "returns 80 if no port was set for self's proxy connection" do
- Net::HTTP.Proxy("localhost").new("localhost", 3333).proxy_port.should eql(80)
- end
-
- it "returns the port for self's proxy connection" do
- http_with_proxy = Net::HTTP.Proxy("localhost", 1234, "rspec", "rocks")
- http_with_proxy.new("localhost", 3333).proxy_port.should eql(1234)
- end
- end
-end
diff --git a/spec/ruby/library/net/http/http/proxy_user_spec.rb b/spec/ruby/library/net/http/http/proxy_user_spec.rb
deleted file mode 100644
index 01fda400e9..0000000000
--- a/spec/ruby/library/net/http/http/proxy_user_spec.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTP.proxy_user" do
- describe "when self is no proxy class" do
- it "returns nil" do
- Net::HTTP.proxy_user.should be_nil
- end
- end
-
- describe "when self is a proxy class" do
- it "returns nil if no username was set for self's proxy connection" do
- Net::HTTP.Proxy("localhost").proxy_user.should be_nil
- end
-
- it "returns the username for self's proxy connection" do
- Net::HTTP.Proxy("localhost", 1234, "rspec", "rocks").proxy_user.should == "rspec"
- end
- end
-end
-
-describe "Net::HTTP#proxy_user" do
- describe "when self is no proxy class instance" do
- it "returns nil" do
- Net::HTTP.new("localhost", 3333).proxy_user.should be_nil
- end
- end
-
- describe "when self is a proxy class instance" do
- it "returns nil if no username was set for self's proxy connection" do
- Net::HTTP.Proxy("localhost").new("localhost", 3333).proxy_user.should be_nil
- end
-
- it "returns the username for self's proxy connection" do
- http_with_proxy = Net::HTTP.Proxy("localhost", 1234, "rspec", "rocks")
- http_with_proxy.new("localhost", 3333).proxy_user.should == "rspec"
- end
- end
-end
diff --git a/spec/ruby/library/net/http/http/put2_spec.rb b/spec/ruby/library/net/http/http/put2_spec.rb
deleted file mode 100644
index 99329a5fd9..0000000000
--- a/spec/ruby/library/net/http/http/put2_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-require_relative 'shared/request_put'
-
-describe "Net::HTTP#put2" do
- it_behaves_like :net_http_request_put, :put2
-end
diff --git a/spec/ruby/library/net/http/http/put_spec.rb b/spec/ruby/library/net/http/http/put_spec.rb
deleted file mode 100644
index 3ca0d0963e..0000000000
--- a/spec/ruby/library/net/http/http/put_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-
-describe "Net::HTTP#put" do
- before :each do
- NetHTTPSpecs.start_server
- @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
- end
-
- after :each do
- @http.finish if @http.started?
- NetHTTPSpecs.stop_server
- end
-
- it "sends an put request to the passed path and returns the response" do
- response = @http.put("/request", "test=test")
- response.body.should == "Request type: PUT"
- end
-
- it "returns a Net::HTTPResponse" do
- @http.put("/request", "test=test").should be_kind_of(Net::HTTPResponse)
- end
-end
diff --git a/spec/ruby/library/net/http/http/read_timeout_spec.rb b/spec/ruby/library/net/http/http/read_timeout_spec.rb
deleted file mode 100644
index e23ee76025..0000000000
--- a/spec/ruby/library/net/http/http/read_timeout_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTP#read_timeout" do
- it "returns the seconds to wait until reading one block" do
- net = Net::HTTP.new("localhost")
- net.read_timeout.should eql(60)
- net.read_timeout = 10
- net.read_timeout.should eql(10)
- end
-end
-
-describe "Net::HTTP#read_timeout=" do
- it "sets the seconds to wait till the connection is open" do
- net = Net::HTTP.new("localhost")
- net.read_timeout = 10
- net.read_timeout.should eql(10)
- end
-
- it "returns the newly set value" do
- net = Net::HTTP.new("localhost")
- (net.read_timeout = 10).should eql(10)
- end
-end
diff --git a/spec/ruby/library/net/http/http/request_get_spec.rb b/spec/ruby/library/net/http/http/request_get_spec.rb
deleted file mode 100644
index 9932ef0beb..0000000000
--- a/spec/ruby/library/net/http/http/request_get_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-require_relative 'shared/request_get'
-
-describe "Net::HTTP#request_get" do
- it_behaves_like :net_http_request_get, :get2
-end
diff --git a/spec/ruby/library/net/http/http/request_head_spec.rb b/spec/ruby/library/net/http/http/request_head_spec.rb
deleted file mode 100644
index 788101c951..0000000000
--- a/spec/ruby/library/net/http/http/request_head_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-require_relative 'shared/request_head'
-
-describe "Net::HTTP#request_head" do
- it_behaves_like :net_http_request_head, :request_head
-end
diff --git a/spec/ruby/library/net/http/http/request_post_spec.rb b/spec/ruby/library/net/http/http/request_post_spec.rb
deleted file mode 100644
index 7ac67cf95d..0000000000
--- a/spec/ruby/library/net/http/http/request_post_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-require_relative 'shared/request_post'
-
-describe "Net::HTTP#request_post" do
- it_behaves_like :net_http_request_post, :request_post
-end
diff --git a/spec/ruby/library/net/http/http/request_put_spec.rb b/spec/ruby/library/net/http/http/request_put_spec.rb
deleted file mode 100644
index 110ac43ca6..0000000000
--- a/spec/ruby/library/net/http/http/request_put_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-require_relative 'shared/request_put'
-
-describe "Net::HTTP#request_put" do
- it_behaves_like :net_http_request_put, :request_put
-end
diff --git a/spec/ruby/library/net/http/http/request_spec.rb b/spec/ruby/library/net/http/http/request_spec.rb
deleted file mode 100644
index e63dde9c8d..0000000000
--- a/spec/ruby/library/net/http/http/request_spec.rb
+++ /dev/null
@@ -1,109 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-
-describe "Net::HTTP#request" do
- before :each do
- NetHTTPSpecs.start_server
- @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
- end
-
- after :each do
- @http.finish if @http.started?
- NetHTTPSpecs.stop_server
- end
-
- describe "when passed request_object" do
- it "makes a HTTP Request based on the passed request_object" do
- response = @http.request(Net::HTTP::Get.new("/request"), "test=test")
- response.body.should == "Request type: GET"
-
- response = @http.request(Net::HTTP::Head.new("/request"), "test=test")
- response.body.should be_nil
-
- response = @http.request(Net::HTTP::Post.new("/request"), "test=test")
- response.body.should == "Request type: POST"
-
- response = @http.request(Net::HTTP::Put.new("/request"), "test=test")
- response.body.should == "Request type: PUT"
-
- response = @http.request(Net::HTTP::Proppatch.new("/request"), "test=test")
- response.body.should == "Request type: PROPPATCH"
-
- response = @http.request(Net::HTTP::Lock.new("/request"), "test=test")
- response.body.should == "Request type: LOCK"
-
- response = @http.request(Net::HTTP::Unlock.new("/request"), "test=test")
- response.body.should == "Request type: UNLOCK"
-
- # TODO: Does not work?
- #response = @http.request(Net::HTTP::Options.new("/request"), "test=test")
- #response.body.should be_nil
-
- response = @http.request(Net::HTTP::Propfind.new("/request"), "test=test")
- response.body.should == "Request type: PROPFIND"
-
- response = @http.request(Net::HTTP::Delete.new("/request"), "test=test")
- response.body.should == "Request type: DELETE"
-
- response = @http.request(Net::HTTP::Move.new("/request"), "test=test")
- response.body.should == "Request type: MOVE"
-
- response = @http.request(Net::HTTP::Copy.new("/request"), "test=test")
- response.body.should == "Request type: COPY"
-
- response = @http.request(Net::HTTP::Mkcol.new("/request"), "test=test")
- response.body.should == "Request type: MKCOL"
-
- response = @http.request(Net::HTTP::Trace.new("/request"), "test=test")
- response.body.should == "Request type: TRACE"
- end
- end
-
- describe "when passed request_object and request_body" do
- it "sends the passed request_body when making the HTTP Request" do
- response = @http.request(Net::HTTP::Get.new("/request/body"), "test=test")
- response.body.should == "test=test"
-
- response = @http.request(Net::HTTP::Head.new("/request/body"), "test=test")
- response.body.should be_nil
-
- response = @http.request(Net::HTTP::Post.new("/request/body"), "test=test")
- response.body.should == "test=test"
-
- response = @http.request(Net::HTTP::Put.new("/request/body"), "test=test")
- response.body.should == "test=test"
-
- response = @http.request(Net::HTTP::Proppatch.new("/request/body"), "test=test")
- response.body.should == "test=test"
-
- response = @http.request(Net::HTTP::Lock.new("/request/body"), "test=test")
- response.body.should == "test=test"
-
- response = @http.request(Net::HTTP::Unlock.new("/request/body"), "test=test")
- response.body.should == "test=test"
-
- # TODO: Does not work?
- #response = @http.request(Net::HTTP::Options.new("/request/body"), "test=test")
- #response.body.should be_nil
-
- response = @http.request(Net::HTTP::Propfind.new("/request/body"), "test=test")
- response.body.should == "test=test"
-
- response = @http.request(Net::HTTP::Delete.new("/request/body"), "test=test")
- response.body.should == "test=test"
-
- response = @http.request(Net::HTTP::Move.new("/request/body"), "test=test")
- response.body.should == "test=test"
-
- response = @http.request(Net::HTTP::Copy.new("/request/body"), "test=test")
- response.body.should == "test=test"
-
- response = @http.request(Net::HTTP::Mkcol.new("/request/body"), "test=test")
- response.body.should == "test=test"
-
- response = @http.request(Net::HTTP::Trace.new("/request/body"), "test=test")
- response.body.should == "test=test"
- end
- end
-end
diff --git a/spec/ruby/library/net/http/http/request_types_spec.rb b/spec/ruby/library/net/http/http/request_types_spec.rb
deleted file mode 100644
index 99d754d3d1..0000000000
--- a/spec/ruby/library/net/http/http/request_types_spec.rb
+++ /dev/null
@@ -1,254 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTP::Get" do
- it "is a subclass of Net::HTTPRequest" do
- Net::HTTP::Get.should < Net::HTTPRequest
- end
-
- it "represents the 'GET'-Request-Method" do
- Net::HTTP::Get::METHOD.should == "GET"
- end
-
- it "has no Request Body" do
- Net::HTTP::Get::REQUEST_HAS_BODY.should be_false
- end
-
- it "has a Response Body" do
- Net::HTTP::Get::RESPONSE_HAS_BODY.should be_true
- end
-end
-
-describe "Net::HTTP::Head" do
- it "is a subclass of Net::HTTPRequest" do
- Net::HTTP::Head.should < Net::HTTPRequest
- end
-
- it "represents the 'HEAD'-Request-Method" do
- Net::HTTP::Head::METHOD.should == "HEAD"
- end
-
- it "has no Request Body" do
- Net::HTTP::Head::REQUEST_HAS_BODY.should be_false
- end
-
- it "has no Response Body" do
- Net::HTTP::Head::RESPONSE_HAS_BODY.should be_false
- end
-end
-
-describe "Net::HTTP::Post" do
- it "is a subclass of Net::HTTPRequest" do
- Net::HTTP::Post.should < Net::HTTPRequest
- end
-
- it "represents the 'POST'-Request-Method" do
- Net::HTTP::Post::METHOD.should == "POST"
- end
-
- it "has a Request Body" do
- Net::HTTP::Post::REQUEST_HAS_BODY.should be_true
- end
-
- it "has a Response Body" do
- Net::HTTP::Post::RESPONSE_HAS_BODY.should be_true
- end
-end
-
-describe "Net::HTTP::Put" do
- it "is a subclass of Net::HTTPRequest" do
- Net::HTTP::Put.should < Net::HTTPRequest
- end
-
- it "represents the 'PUT'-Request-Method" do
- Net::HTTP::Put::METHOD.should == "PUT"
- end
-
- it "has a Request Body" do
- Net::HTTP::Put::REQUEST_HAS_BODY.should be_true
- end
-
- it "has a Response Body" do
- Net::HTTP::Put::RESPONSE_HAS_BODY.should be_true
- end
-end
-
-describe "Net::HTTP::Delete" do
- it "is a subclass of Net::HTTPRequest" do
- Net::HTTP::Delete.should < Net::HTTPRequest
- end
-
- it "represents the 'DELETE'-Request-Method" do
- Net::HTTP::Delete::METHOD.should == "DELETE"
- end
-
- it "has no Request Body" do
- Net::HTTP::Delete::REQUEST_HAS_BODY.should be_false
- end
-
- it "has a Response Body" do
- Net::HTTP::Delete::RESPONSE_HAS_BODY.should be_true
- end
-end
-
-describe "Net::HTTP::Options" do
- it "is a subclass of Net::HTTPRequest" do
- Net::HTTP::Options.should < Net::HTTPRequest
- end
-
- it "represents the 'OPTIONS'-Request-Method" do
- Net::HTTP::Options::METHOD.should == "OPTIONS"
- end
-
- it "has no Request Body" do
- Net::HTTP::Options::REQUEST_HAS_BODY.should be_false
- end
-
- it "has no Response Body" do
- Net::HTTP::Options::RESPONSE_HAS_BODY.should be_true
- end
-end
-
-describe "Net::HTTP::Trace" do
- it "is a subclass of Net::HTTPRequest" do
- Net::HTTP::Trace.should < Net::HTTPRequest
- end
-
- it "represents the 'TRACE'-Request-Method" do
- Net::HTTP::Trace::METHOD.should == "TRACE"
- end
-
- it "has no Request Body" do
- Net::HTTP::Trace::REQUEST_HAS_BODY.should be_false
- end
-
- it "has a Response Body" do
- Net::HTTP::Trace::RESPONSE_HAS_BODY.should be_true
- end
-end
-
-describe "Net::HTTP::Propfind" do
- it "is a subclass of Net::HTTPRequest" do
- Net::HTTP::Propfind.should < Net::HTTPRequest
- end
-
- it "represents the 'PROPFIND'-Request-Method" do
- Net::HTTP::Propfind::METHOD.should == "PROPFIND"
- end
-
- it "has a Request Body" do
- Net::HTTP::Propfind::REQUEST_HAS_BODY.should be_true
- end
-
- it "has a Response Body" do
- Net::HTTP::Propfind::RESPONSE_HAS_BODY.should be_true
- end
-end
-
-describe "Net::HTTP::Proppatch" do
- it "is a subclass of Net::HTTPRequest" do
- Net::HTTP::Proppatch.should < Net::HTTPRequest
- end
-
- it "represents the 'PROPPATCH'-Request-Method" do
- Net::HTTP::Proppatch::METHOD.should == "PROPPATCH"
- end
-
- it "has a Request Body" do
- Net::HTTP::Proppatch::REQUEST_HAS_BODY.should be_true
- end
-
- it "has a Response Body" do
- Net::HTTP::Proppatch::RESPONSE_HAS_BODY.should be_true
- end
-end
-
-describe "Net::HTTP::Mkcol" do
- it "is a subclass of Net::HTTPRequest" do
- Net::HTTP::Mkcol.should < Net::HTTPRequest
- end
-
- it "represents the 'MKCOL'-Request-Method" do
- Net::HTTP::Mkcol::METHOD.should == "MKCOL"
- end
-
- it "has a Request Body" do
- Net::HTTP::Mkcol::REQUEST_HAS_BODY.should be_true
- end
-
- it "has a Response Body" do
- Net::HTTP::Mkcol::RESPONSE_HAS_BODY.should be_true
- end
-end
-
-describe "Net::HTTP::Copy" do
- it "is a subclass of Net::HTTPRequest" do
- Net::HTTP::Copy.should < Net::HTTPRequest
- end
-
- it "represents the 'COPY'-Request-Method" do
- Net::HTTP::Copy::METHOD.should == "COPY"
- end
-
- it "has no Request Body" do
- Net::HTTP::Copy::REQUEST_HAS_BODY.should be_false
- end
-
- it "has a Response Body" do
- Net::HTTP::Copy::RESPONSE_HAS_BODY.should be_true
- end
-end
-
-describe "Net::HTTP::Move" do
- it "is a subclass of Net::HTTPRequest" do
- Net::HTTP::Move.should < Net::HTTPRequest
- end
-
- it "represents the 'MOVE'-Request-Method" do
- Net::HTTP::Move::METHOD.should == "MOVE"
- end
-
- it "has no Request Body" do
- Net::HTTP::Move::REQUEST_HAS_BODY.should be_false
- end
-
- it "has a Response Body" do
- Net::HTTP::Move::RESPONSE_HAS_BODY.should be_true
- end
-end
-
-describe "Net::HTTP::Lock" do
- it "is a subclass of Net::HTTPRequest" do
- Net::HTTP::Lock.should < Net::HTTPRequest
- end
-
- it "represents the 'LOCK'-Request-Method" do
- Net::HTTP::Lock::METHOD.should == "LOCK"
- end
-
- it "has a Request Body" do
- Net::HTTP::Lock::REQUEST_HAS_BODY.should be_true
- end
-
- it "has a Response Body" do
- Net::HTTP::Lock::RESPONSE_HAS_BODY.should be_true
- end
-end
-
-describe "Net::HTTP::Unlock" do
- it "is a subclass of Net::HTTPRequest" do
- Net::HTTP::Unlock.should < Net::HTTPRequest
- end
-
- it "represents the 'UNLOCK'-Request-Method" do
- Net::HTTP::Unlock::METHOD.should == "UNLOCK"
- end
-
- it "has a Request Body" do
- Net::HTTP::Unlock::REQUEST_HAS_BODY.should be_true
- end
-
- it "has a Response Body" do
- Net::HTTP::Unlock::RESPONSE_HAS_BODY.should be_true
- end
-end
diff --git a/spec/ruby/library/net/http/http/send_request_spec.rb b/spec/ruby/library/net/http/http/send_request_spec.rb
deleted file mode 100644
index 83e9448b8b..0000000000
--- a/spec/ruby/library/net/http/http/send_request_spec.rb
+++ /dev/null
@@ -1,61 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-
-describe "Net::HTTP#send_request" do
- before :each do
- NetHTTPSpecs.start_server
- @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
-
- # HEAD is special so handled separately
- @methods = %w[
- GET POST PUT DELETE
- OPTIONS
- PROPFIND PROPPATCH LOCK UNLOCK
- ]
- end
-
- after :each do
- @http.finish if @http.started?
- NetHTTPSpecs.stop_server
- end
-
- # TODO: Does only work with GET and POST requests
- describe "when passed type, path" do
- it "sends a HTTP Request of the passed type to the passed path" do
- response = @http.send_request("HEAD", "/request")
- response.body.should be_nil
-
- (@methods - %w[POST PUT]).each do |method|
- response = @http.send_request(method, "/request")
- response.body.should == "Request type: #{method}"
- end
- end
- end
-
- describe "when passed type, path, body" do
- it "sends a HTTP Request with the passed body" do
- response = @http.send_request("HEAD", "/request/body", "test=test")
- response.body.should be_nil
-
- @methods.each do |method|
- response = @http.send_request(method, "/request/body", "test=test")
- response.body.should == "test=test"
- end
- end
- end
-
- describe "when passed type, path, body, headers" do
- it "sends a HTTP Request with the passed headers" do
- referer = 'https://www.ruby-lang.org/'.freeze
-
- response = @http.send_request("HEAD", "/request/header", "test=test", "referer" => referer)
- response.body.should be_nil
-
- @methods.each do |method|
- response = @http.send_request(method, "/request/header", "test=test", "referer" => referer)
- response.body.should include('"Referer"=>"' + referer + '"')
- end
- end
- end
-end
diff --git a/spec/ruby/library/net/http/http/set_debug_output_spec.rb b/spec/ruby/library/net/http/http/set_debug_output_spec.rb
deleted file mode 100644
index 94b6f4499d..0000000000
--- a/spec/ruby/library/net/http/http/set_debug_output_spec.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require "stringio"
-require_relative 'fixtures/http_server'
-
-describe "Net::HTTP#set_debug_output when passed io" do
- before :each do
- NetHTTPSpecs.start_server
- @http = Net::HTTP.new("localhost", NetHTTPSpecs.port)
- end
-
- after :each do
- @http.finish if @http.started?
- NetHTTPSpecs.stop_server
- end
-
- it "sets the passed io as output stream for debugging" do
- io = StringIO.new
-
- @http.set_debug_output(io)
- @http.start
- io.string.should_not be_empty
- size = io.string.size
-
- @http.get("/")
- io.string.size.should > size
- end
-
- it "outputs a warning when the connection has already been started" do
- @http.start
- -> { @http.set_debug_output(StringIO.new) }.should complain(/Net::HTTP#set_debug_output called after HTTP started/)
- end
-end
diff --git a/spec/ruby/library/net/http/http/socket_type_spec.rb b/spec/ruby/library/net/http/http/socket_type_spec.rb
deleted file mode 100644
index 5c844ddf94..0000000000
--- a/spec/ruby/library/net/http/http/socket_type_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTP.socket_type" do
- it "returns BufferedIO" do
- Net::HTTP.socket_type.should == Net::BufferedIO
- end
-end
diff --git a/spec/ruby/library/net/http/http/start_spec.rb b/spec/ruby/library/net/http/http/start_spec.rb
deleted file mode 100644
index a2768eed18..0000000000
--- a/spec/ruby/library/net/http/http/start_spec.rb
+++ /dev/null
@@ -1,111 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-
-describe "Net::HTTP.start" do
- before :each do
- NetHTTPSpecs.start_server
- @port = NetHTTPSpecs.port
- end
-
- after :each do
- NetHTTPSpecs.stop_server
- end
-
- describe "when not passed a block" do
- before :each do
- @http = Net::HTTP.start("localhost", @port)
- end
-
- after :each do
- @http.finish if @http.started?
- end
-
- it "returns a new Net::HTTP object for the passed address and port" do
- @http.should be_kind_of(Net::HTTP)
- @http.address.should == "localhost"
- @http.port.should == @port
- end
-
- it "opens the tcp connection" do
- @http.started?.should be_true
- end
- end
-
- describe "when passed a block" do
- it "returns the blocks return value" do
- Net::HTTP.start("localhost", @port) { :test }.should == :test
- end
-
- it "yields the new Net::HTTP object to the block" do
- yielded = false
- Net::HTTP.start("localhost", @port) do |net|
- yielded = true
- net.should be_kind_of(Net::HTTP)
- end
- yielded.should be_true
- end
-
- it "opens the tcp connection before yielding" do
- Net::HTTP.start("localhost", @port) { |http| http.started?.should be_true }
- end
-
- it "closes the tcp connection after yielding" do
- net = nil
- Net::HTTP.start("localhost", @port) { |x| net = x }
- net.started?.should be_false
- end
- end
-end
-
-describe "Net::HTTP#start" do
- before :each do
- NetHTTPSpecs.start_server
- @http = Net::HTTP.new("localhost", NetHTTPSpecs.port)
- end
-
- after :each do
- @http.finish if @http.started?
- NetHTTPSpecs.stop_server
- end
-
- it "returns self" do
- @http.start.should equal(@http)
- end
-
- it "opens the tcp connection" do
- @http.start
- @http.started?.should be_true
- end
-
- describe "when self has already been started" do
- it "raises an IOError" do
- @http.start
- -> { @http.start }.should raise_error(IOError)
- end
- end
-
- describe "when passed a block" do
- it "returns the blocks return value" do
- @http.start { :test }.should == :test
- end
-
- it "yields the new Net::HTTP object to the block" do
- yielded = false
- @http.start do |http|
- yielded = true
- http.should equal(@http)
- end
- yielded.should be_true
- end
-
- it "opens the tcp connection before yielding" do
- @http.start { |http| http.started?.should be_true }
- end
-
- it "closes the tcp connection after yielding" do
- @http.start { }
- @http.started?.should be_false
- end
- end
-end
diff --git a/spec/ruby/library/net/http/http/started_spec.rb b/spec/ruby/library/net/http/http/started_spec.rb
deleted file mode 100644
index ea441ed16a..0000000000
--- a/spec/ruby/library/net/http/http/started_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-require_relative 'shared/started'
-
-describe "Net::HTTP#started?" do
- it_behaves_like :net_http_started_p, :started?
-end
diff --git a/spec/ruby/library/net/http/http/trace_spec.rb b/spec/ruby/library/net/http/http/trace_spec.rb
deleted file mode 100644
index 94a1bf6655..0000000000
--- a/spec/ruby/library/net/http/http/trace_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-
-describe "Net::HTTP#trace" do
- before :each do
- NetHTTPSpecs.start_server
- @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
- end
-
- after :each do
- @http.finish if @http.started?
- NetHTTPSpecs.stop_server
- end
-
- it "sends a TRACE request to the passed path and returns the response" do
- response = @http.trace("/request")
- response.body.should == "Request type: TRACE"
- end
-
- it "returns a Net::HTTPResponse" do
- @http.trace("/request").should be_kind_of(Net::HTTPResponse)
- end
-end
diff --git a/spec/ruby/library/net/http/http/unlock_spec.rb b/spec/ruby/library/net/http/http/unlock_spec.rb
deleted file mode 100644
index a4f1b7a1d1..0000000000
--- a/spec/ruby/library/net/http/http/unlock_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/http_server'
-
-describe "Net::HTTP#unlock" do
- before :each do
- NetHTTPSpecs.start_server
- @http = Net::HTTP.start("localhost", NetHTTPSpecs.port)
- end
-
- after :each do
- @http.finish if @http.started?
- NetHTTPSpecs.stop_server
- end
-
- it "sends an UNLOCK request to the passed path and returns the response" do
- response = @http.unlock("/request", "test=test")
- response.body.should == "Request type: UNLOCK"
- end
-
- it "returns a Net::HTTPResponse" do
- @http.unlock("/request", "test=test").should be_kind_of(Net::HTTPResponse)
- end
-end
diff --git a/spec/ruby/library/net/http/http/use_ssl_spec.rb b/spec/ruby/library/net/http/http/use_ssl_spec.rb
deleted file mode 100644
index be1ec7fa25..0000000000
--- a/spec/ruby/library/net/http/http/use_ssl_spec.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTP#use_ssl?" do
- it "returns false" do
- http = Net::HTTP.new("localhost")
- http.use_ssl?.should be_false
- end
-end
diff --git a/spec/ruby/library/net/http/http/version_1_1_spec.rb b/spec/ruby/library/net/http/http/version_1_1_spec.rb
deleted file mode 100644
index 1c069e9ea6..0000000000
--- a/spec/ruby/library/net/http/http/version_1_1_spec.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'shared/version_1_1'
-
-describe "Net::HTTP.version_1_1?" do
- it_behaves_like :net_http_version_1_1_p, :version_1_1?
-end
diff --git a/spec/ruby/library/net/http/http/version_1_2_spec.rb b/spec/ruby/library/net/http/http/version_1_2_spec.rb
deleted file mode 100644
index 4e601462c9..0000000000
--- a/spec/ruby/library/net/http/http/version_1_2_spec.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'shared/version_1_2'
-
-describe "Net::HTTP.version_1_2" do
- it "turns on net/http 1.2 features" do
- Net::HTTP.version_1_2
-
- Net::HTTP.version_1_2?.should be_true
- Net::HTTP.version_1_1?.should be_false
- end
-
- it "returns true" do
- Net::HTTP.version_1_2.should be_true
- end
-end
-
-describe "Net::HTTP.version_1_2?" do
- it_behaves_like :net_http_version_1_2_p, :version_1_2?
-end
diff --git a/spec/ruby/library/net/http/httpexceptions/initialize_spec.rb b/spec/ruby/library/net/http/httpexceptions/initialize_spec.rb
deleted file mode 100644
index 8e3fd8cc02..0000000000
--- a/spec/ruby/library/net/http/httpexceptions/initialize_spec.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-
-describe "Net::HTTPExceptions#initialize when passed message, response" do
- before :each do
- @exception = NetHTTPExceptionsSpecs::Simple.new("error message", "a http response")
- end
-
- it "calls super with the passed message" do
- @exception.message.should == "error message"
- end
-
- it "sets self's response to the passed response" do
- @exception.response.should == "a http response"
- end
-end
diff --git a/spec/ruby/library/net/http/httpexceptions/response_spec.rb b/spec/ruby/library/net/http/httpexceptions/response_spec.rb
deleted file mode 100644
index 205b2bc212..0000000000
--- a/spec/ruby/library/net/http/httpexceptions/response_spec.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-
-describe "Net::HTTPExceptions#response" do
- it "returns self's response" do
- exception = NetHTTPExceptionsSpecs::Simple.new("error message", "a http response")
- exception.response.should == "a http response"
- end
-end
diff --git a/spec/ruby/library/net/http/httpgenericrequest/body_exist_spec.rb b/spec/ruby/library/net/http/httpgenericrequest/body_exist_spec.rb
deleted file mode 100644
index 7d081939b8..0000000000
--- a/spec/ruby/library/net/http/httpgenericrequest/body_exist_spec.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPGenericRequest#body_exist?" do
- it "returns true when the response is expected to have a body" do
- request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
- request.body_exist?.should be_true
-
- request = Net::HTTPGenericRequest.new("POST", true, false, "/some/path")
- request.body_exist?.should be_false
- end
-
- describe "when $VERBOSE is true" do
- it "emits a warning" do
- request = Net::HTTPGenericRequest.new("POST", true, false, "/some/path")
- -> {
- request.body_exist?
- }.should complain(/body_exist\? is obsolete/, verbose: true)
- end
- end
-end
diff --git a/spec/ruby/library/net/http/httpgenericrequest/body_spec.rb b/spec/ruby/library/net/http/httpgenericrequest/body_spec.rb
deleted file mode 100644
index a215895b57..0000000000
--- a/spec/ruby/library/net/http/httpgenericrequest/body_spec.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require "stringio"
-
-describe "Net::HTTPGenericRequest#body" do
- it "returns self's request body" do
- request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
- request.body.should be_nil
-
- request.body = "Some Content"
- request.body.should == "Some Content"
- end
-end
-
-describe "Net::HTTPGenericRequest#body=" do
- before :each do
- @request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
- end
-
- it "sets self's body content to the passed String" do
- @request.body = "Some Content"
- @request.body.should == "Some Content"
- end
-
- it "sets self's body stream to nil" do
- @request.body_stream = StringIO.new("")
- @request.body = "Some Content"
- @request.body_stream.should be_nil
- end
-end
diff --git a/spec/ruby/library/net/http/httpgenericrequest/body_stream_spec.rb b/spec/ruby/library/net/http/httpgenericrequest/body_stream_spec.rb
deleted file mode 100644
index c2a60e6836..0000000000
--- a/spec/ruby/library/net/http/httpgenericrequest/body_stream_spec.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require "stringio"
-
-describe "Net::HTTPGenericRequest#body_stream" do
- it "returns self's body stream Object" do
- request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
- request.body_stream.should be_nil
-
- stream = StringIO.new("test")
- request.body_stream = stream
- request.body_stream.should equal(stream)
- end
-end
-
-describe "Net::HTTPGenericRequest#body_stream=" do
- before :each do
- @request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
- @stream = StringIO.new("test")
- end
-
- it "sets self's body stream to the passed Object" do
- @request.body_stream = @stream
- @request.body_stream.should equal(@stream)
- end
-
- it "sets self's body to nil" do
- @request.body = "Some Content"
- @request.body_stream = @stream
- @request.body.should be_nil
- end
-end
diff --git a/spec/ruby/library/net/http/httpgenericrequest/exec_spec.rb b/spec/ruby/library/net/http/httpgenericrequest/exec_spec.rb
deleted file mode 100644
index da5b1a63be..0000000000
--- a/spec/ruby/library/net/http/httpgenericrequest/exec_spec.rb
+++ /dev/null
@@ -1,131 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require "stringio"
-
-describe "Net::HTTPGenericRequest#exec when passed socket, version, path" do
- before :each do
- @socket = StringIO.new("")
- @buffered_socket = Net::BufferedIO.new(@socket)
- end
-
- it "executes the request over the socket to the path using the HTTP version" do
- request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
-
- request.exec(@buffered_socket, "1.1", "/some/path")
- str = @socket.string
-
- str.should =~ %r[POST /some/path HTTP/1.1\r\n]
- str.should =~ %r[Accept: \*/\*\r\n]
- str[-4..-1].should == "\r\n\r\n"
-
- request = Net::HTTPGenericRequest.new("GET", true, true, "/some/path",
- "Content-Type" => "text/html")
-
- request.exec(@buffered_socket, "1.0", "/some/other/path")
- str = @socket.string
-
- str.should =~ %r[GET /some/other/path HTTP/1.0\r\n]
- str.should =~ %r[Accept: \*/\*\r\n]
- str.should =~ %r[Content-Type: text/html\r\n]
- str[-4..-1].should == "\r\n\r\n"
- end
-
- describe "when a request body is set" do
- it "sets the 'Content-Type' header to 'application/x-www-form-urlencoded' unless the 'Content-Type' header is supplied" do
- request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
- request.body = "Some Content"
-
- request.exec(@buffered_socket, "1.1", "/some/other/path")
- str = @socket.string
-
- str.should =~ %r[POST /some/other/path HTTP/1.1\r\n]
- str.should =~ %r[Accept: \*/\*\r\n]
- str.should =~ %r[Content-Type: application/x-www-form-urlencoded\r\n]
- str.should =~ %r[Content-Length: 12\r\n]
- str[-16..-1].should == "\r\n\r\nSome Content"
- end
-
- it "correctly sets the 'Content-Length' header and includes the body" do
- request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path",
- "Content-Type" => "text/html")
- request.body = "Some Content"
-
- request.exec(@buffered_socket, "1.1", "/some/other/path")
- str = @socket.string
-
- str.should =~ %r[POST /some/other/path HTTP/1.1\r\n]
- str.should =~ %r[Accept: \*/\*\r\n]
- str.should =~ %r[Content-Type: text/html\r\n]
- str.should =~ %r[Content-Length: 12\r\n]
- str[-16..-1].should == "\r\n\r\nSome Content"
- end
- end
-
- describe "when a body stream is set" do
- it "sets the 'Content-Type' header to 'application/x-www-form-urlencoded' unless the 'Content-Type' header is supplied" do
- request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path",
- "Content-Length" => "10")
- request.body_stream = StringIO.new("a" * 20)
-
- request.exec(@buffered_socket, "1.1", "/some/other/path")
- str = @socket.string
-
- str.should =~ %r[POST /some/other/path HTTP/1.1\r\n]
- str.should =~ %r[Accept: \*/\*\r\n]
- str.should =~ %r[Content-Type: application/x-www-form-urlencoded\r\n]
- str.should =~ %r[Content-Length: 10\r\n]
- str[-24..-1].should == "\r\n\r\naaaaaaaaaaaaaaaaaaaa"
- end
-
- it "sends the whole stream, regardless of the 'Content-Length' header" do
- request = Net::HTTPGenericRequest.new("POST", true, true,"/some/path",
- "Content-Type" => "text/html",
- "Content-Length" => "10")
- request.body_stream = StringIO.new("a" * 20)
-
- request.exec(@buffered_socket, "1.1", "/some/other/path")
- str = @socket.string
-
- str.should =~ %r[POST /some/other/path HTTP/1.1\r\n]
- str.should =~ %r[Accept: \*/\*\r\n]
- str.should =~ %r[Content-Type: text/html\r\n]
- str.should =~ %r[Content-Length: 10\r\n]
- str[-24..-1].should == "\r\n\r\naaaaaaaaaaaaaaaaaaaa"
- end
-
- it "sends the request in chunks when 'Transfer-Encoding' is set to 'chunked'" do
- request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path",
- "Content-Type" => "text/html",
- "Transfer-Encoding" => "chunked")
- datasize = 1024 * 10
- request.body_stream = StringIO.new("a" * datasize)
-
- request.exec(@buffered_socket, "1.1", "/some/other/path")
- str = @socket.string
-
- str.should =~ %r[POST /some/other/path HTTP/1.1\r\n]
- str.should =~ %r[Accept: \*/\*\r\n]
- str.should =~ %r[Content-Type: text/html\r\n]
- str.should =~ %r[Transfer-Encoding: chunked\r\n]
- str =~ %r[\r\n\r\n]
- str = $'
- while datasize > 0
- chunk_size_line, str = str.split(/\r\n/, 2)
- chunk_size = chunk_size_line[/\A[0-9A-Fa-f]+/].to_i(16)
- str.slice!(0, chunk_size).should == 'a' * chunk_size
- datasize -= chunk_size
- str.slice!(0, 2).should == "\r\n"
- end
- datasize.should == 0
- str.should == %"0\r\n\r\n"
- end
-
- it "raises an ArgumentError when the 'Content-Length' is not set or 'Transfer-Encoding' is not set to 'chunked'" do
- request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path",
- "Content-Type" => "text/html")
- request.body_stream = StringIO.new("Some Content")
-
- -> { request.exec(@buffered_socket, "1.1", "/some/other/path") }.should raise_error(ArgumentError)
- end
- end
-end
diff --git a/spec/ruby/library/net/http/httpgenericrequest/inspect_spec.rb b/spec/ruby/library/net/http/httpgenericrequest/inspect_spec.rb
deleted file mode 100644
index 36240949c3..0000000000
--- a/spec/ruby/library/net/http/httpgenericrequest/inspect_spec.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPGenericRequest#inspect" do
- it "returns a String representation of self" do
- request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
- request.inspect.should == "#<Net::HTTPGenericRequest POST>"
-
- request = Net::HTTPGenericRequest.new("GET", false, true, "/some/path")
- request.inspect.should == "#<Net::HTTPGenericRequest GET>"
-
- request = Net::HTTPGenericRequest.new("BLA", true, true, "/some/path")
- request.inspect.should == "#<Net::HTTPGenericRequest BLA>"
-
- # Subclasses
- request = Net::HTTP::Get.new("/some/path")
- request.inspect.should == "#<Net::HTTP::Get GET>"
-
- request = Net::HTTP::Post.new("/some/path")
- request.inspect.should == "#<Net::HTTP::Post POST>"
-
- request = Net::HTTP::Trace.new("/some/path")
- request.inspect.should == "#<Net::HTTP::Trace TRACE>"
- end
-end
diff --git a/spec/ruby/library/net/http/httpgenericrequest/method_spec.rb b/spec/ruby/library/net/http/httpgenericrequest/method_spec.rb
deleted file mode 100644
index 3f7c2cbf2b..0000000000
--- a/spec/ruby/library/net/http/httpgenericrequest/method_spec.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPGenericRequest#method" do
- it "returns self's request method" do
- request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
- request.method.should == "POST"
-
- request = Net::HTTPGenericRequest.new("GET", false, true, "/some/path")
- request.method.should == "GET"
-
- request = Net::HTTPGenericRequest.new("BLA", true, true, "/some/path")
- request.method.should == "BLA"
- end
-end
diff --git a/spec/ruby/library/net/http/httpgenericrequest/path_spec.rb b/spec/ruby/library/net/http/httpgenericrequest/path_spec.rb
deleted file mode 100644
index fc4cf9af53..0000000000
--- a/spec/ruby/library/net/http/httpgenericrequest/path_spec.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPGenericRequest#path" do
- it "returns self's request path" do
- request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
- request.path.should == "/some/path"
-
- request = Net::HTTPGenericRequest.new("POST", true, true, "/some/other/path")
- request.path.should == "/some/other/path"
- end
-end
diff --git a/spec/ruby/library/net/http/httpgenericrequest/request_body_permitted_spec.rb b/spec/ruby/library/net/http/httpgenericrequest/request_body_permitted_spec.rb
deleted file mode 100644
index 50cd1ff637..0000000000
--- a/spec/ruby/library/net/http/httpgenericrequest/request_body_permitted_spec.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPGenericRequest#request_body_permitted?" do
- it "returns true when the request is expected to have a body" do
- request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
- request.request_body_permitted?.should be_true
-
- request = Net::HTTPGenericRequest.new("POST", false, true, "/some/path")
- request.request_body_permitted?.should be_false
- end
-end
diff --git a/spec/ruby/library/net/http/httpgenericrequest/response_body_permitted_spec.rb b/spec/ruby/library/net/http/httpgenericrequest/response_body_permitted_spec.rb
deleted file mode 100644
index 0c4165d0ab..0000000000
--- a/spec/ruby/library/net/http/httpgenericrequest/response_body_permitted_spec.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPGenericRequest#response_body_permitted?" do
- it "returns true when the response is expected to have a body" do
- request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
- request.response_body_permitted?.should be_true
-
- request = Net::HTTPGenericRequest.new("POST", true, false, "/some/path")
- request.response_body_permitted?.should be_false
- end
-end
diff --git a/spec/ruby/library/net/http/httpgenericrequest/set_body_internal_spec.rb b/spec/ruby/library/net/http/httpgenericrequest/set_body_internal_spec.rb
deleted file mode 100644
index 7494c69173..0000000000
--- a/spec/ruby/library/net/http/httpgenericrequest/set_body_internal_spec.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPGenericRequest#set_body_internal when passed string" do
- before :each do
- @request = Net::HTTPGenericRequest.new("POST", true, true, "/some/path")
- end
-
- it "sets self's body to the passed string" do
- @request.set_body_internal("Some Content")
- @request.body.should == "Some Content"
- end
-
- it "raises an ArgumentError when the body or body_stream of self have already been set" do
- @request.body = "Some Content"
- -> { @request.set_body_internal("Some other Content") }.should raise_error(ArgumentError)
-
- @request.body_stream = "Some Content"
- -> { @request.set_body_internal("Some other Content") }.should raise_error(ArgumentError)
- end
-end
diff --git a/spec/ruby/library/net/http/httpheader/add_field_spec.rb b/spec/ruby/library/net/http/httpheader/add_field_spec.rb
deleted file mode 100644
index 882d5ac5bb..0000000000
--- a/spec/ruby/library/net/http/httpheader/add_field_spec.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-
-describe "Net::HTTPHeader#add_field when passed key, value" do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- end
-
- it "adds the passed value to the header entry with the passed key" do
- @headers.add_field("My-Header", "a")
- @headers.get_fields("My-Header").should == ["a"]
-
- @headers.add_field("My-Header", "b")
- @headers.get_fields("My-Header").should == ["a", "b"]
-
- @headers.add_field("My-Header", "c")
- @headers.get_fields("My-Header").should == ["a", "b", "c"]
- end
-
- it "is case-insensitive" do
- @headers.add_field("My-Header", "a")
- @headers.get_fields("My-Header").should == ["a"]
-
- @headers.add_field("my-header", "b")
- @headers.get_fields("My-Header").should == ["a", "b"]
-
- @headers.add_field("MY-HEADER", "c")
- @headers.get_fields("My-Header").should == ["a", "b", "c"]
- end
-end
diff --git a/spec/ruby/library/net/http/httpheader/basic_auth_spec.rb b/spec/ruby/library/net/http/httpheader/basic_auth_spec.rb
deleted file mode 100644
index fa2a710fe1..0000000000
--- a/spec/ruby/library/net/http/httpheader/basic_auth_spec.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-
-describe "Net::HTTPHeader#basic_auth when passed account, password" do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- end
-
- it "sets the 'Authorization' Header entry for basic authorization" do
- @headers.basic_auth("rubyspec", "rocks")
- @headers["Authorization"].should == "Basic cnVieXNwZWM6cm9ja3M="
- end
-end
diff --git a/spec/ruby/library/net/http/httpheader/canonical_each_spec.rb b/spec/ruby/library/net/http/httpheader/canonical_each_spec.rb
deleted file mode 100644
index 0dddd3049b..0000000000
--- a/spec/ruby/library/net/http/httpheader/canonical_each_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-require_relative 'shared/each_capitalized'
-
-describe "Net::HTTPHeader#canonical_each" do
- it_behaves_like :net_httpheader_each_capitalized, :canonical_each
-end
diff --git a/spec/ruby/library/net/http/httpheader/chunked_spec.rb b/spec/ruby/library/net/http/httpheader/chunked_spec.rb
deleted file mode 100644
index 96b758981b..0000000000
--- a/spec/ruby/library/net/http/httpheader/chunked_spec.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-
-describe "Net::HTTPHeader#chunked?" do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- end
-
- it "returns true if the 'Transfer-Encoding' header entry is set to chunked" do
- @headers.chunked?.should be_false
-
- @headers["Transfer-Encoding"] = "bla"
- @headers.chunked?.should be_false
-
- @headers["Transfer-Encoding"] = "blachunkedbla"
- @headers.chunked?.should be_false
-
- @headers["Transfer-Encoding"] = "chunked"
- @headers.chunked?.should be_true
- end
-end
diff --git a/spec/ruby/library/net/http/httpheader/content_length_spec.rb b/spec/ruby/library/net/http/httpheader/content_length_spec.rb
deleted file mode 100644
index e344817e82..0000000000
--- a/spec/ruby/library/net/http/httpheader/content_length_spec.rb
+++ /dev/null
@@ -1,54 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-
-describe "Net::HTTPHeader#content_length" do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- end
-
- it "returns nil if no 'Content-Length' header entry is set" do
- @headers.content_length.should be_nil
- end
-
- it "raises a Net::HTTPHeaderSyntaxError when the 'Content-Length' header entry has an invalid format" do
- @headers["Content-Length"] = "invalid"
- -> { @headers.content_length }.should raise_error(Net::HTTPHeaderSyntaxError)
- end
-
- it "returns the value of the 'Content-Length' header entry as an Integer" do
- @headers["Content-Length"] = "123"
- @headers.content_length.should eql(123)
-
- @headers["Content-Length"] = "123valid"
- @headers.content_length.should eql(123)
-
- @headers["Content-Length"] = "valid123"
- @headers.content_length.should eql(123)
- end
-end
-
-describe "Net::HTTPHeader#content_length=" do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- end
-
- it "removes the 'Content-Length' entry if passed false or nil" do
- @headers["Content-Length"] = "123"
- @headers.content_length = nil
- @headers["Content-Length"].should be_nil
- end
-
- it "sets the 'Content-Length' entry to the passed value" do
- @headers.content_length = "123"
- @headers["Content-Length"].should == "123"
-
- @headers.content_length = "123valid"
- @headers["Content-Length"].should == "123"
- end
-
- it "sets the 'Content-Length' entry to 0 if the passed value is not valid" do
- @headers.content_length = "invalid123"
- @headers["Content-Length"].should == "0"
- end
-end
diff --git a/spec/ruby/library/net/http/httpheader/content_range_spec.rb b/spec/ruby/library/net/http/httpheader/content_range_spec.rb
deleted file mode 100644
index ba75f9a9a1..0000000000
--- a/spec/ruby/library/net/http/httpheader/content_range_spec.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-
-describe "Net::HTTPHeader#content_range" do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- end
-
- it "returns a Range object that represents the 'Content-Range' header entry" do
- @headers["Content-Range"] = "bytes 0-499/1234"
- @headers.content_range.should == (0..499)
-
- @headers["Content-Range"] = "bytes 500-1233/1234"
- @headers.content_range.should == (500..1233)
- end
-
- it "returns nil when there is no 'Content-Range' header entry" do
- @headers.content_range.should be_nil
- end
-
- it "raises a Net::HTTPHeaderSyntaxError when the 'Content-Range' has an invalid format" do
- @headers["Content-Range"] = "invalid"
- -> { @headers.content_range }.should raise_error(Net::HTTPHeaderSyntaxError)
-
- @headers["Content-Range"] = "bytes 123-abc"
- -> { @headers.content_range }.should raise_error(Net::HTTPHeaderSyntaxError)
-
- @headers["Content-Range"] = "bytes abc-123"
- -> { @headers.content_range }.should raise_error(Net::HTTPHeaderSyntaxError)
- end
-end
diff --git a/spec/ruby/library/net/http/httpheader/content_type_spec.rb b/spec/ruby/library/net/http/httpheader/content_type_spec.rb
deleted file mode 100644
index 1f8b4ba326..0000000000
--- a/spec/ruby/library/net/http/httpheader/content_type_spec.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-require_relative 'shared/set_content_type'
-
-describe "Net::HTTPHeader#content_type" do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- end
-
- it "returns the content type string, as per 'Content-Type' header entry" do
- @headers["Content-Type"] = "text/html"
- @headers.content_type.should == "text/html"
-
- @headers["Content-Type"] = "text/html;charset=utf-8"
- @headers.content_type.should == "text/html"
- end
-
- it "returns nil if the 'Content-Type' header entry does not exist" do
- @headers.content_type.should be_nil
- end
-end
-
-describe "Net::HTTPHeader#content_type=" do
- it_behaves_like :net_httpheader_set_content_type, :content_type=
-end
diff --git a/spec/ruby/library/net/http/httpheader/delete_spec.rb b/spec/ruby/library/net/http/httpheader/delete_spec.rb
deleted file mode 100644
index 603ae198de..0000000000
--- a/spec/ruby/library/net/http/httpheader/delete_spec.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-
-describe "Net::HTTPHeader#delete when passed key" do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- end
-
- it "removes the header entry with the passed key" do
- @headers["My-Header"] = "test"
- @headers.delete("My-Header")
-
- @headers["My-Header"].should be_nil
- @headers.size.should eql(0)
- end
-
- it "returns the removed values" do
- @headers["My-Header"] = "test"
- @headers.delete("My-Header").should == ["test"]
- end
-
- it "is case-insensitive" do
- @headers["My-Header"] = "test"
- @headers.delete("my-header")
-
- @headers["My-Header"].should be_nil
- @headers.size.should eql(0)
- end
-end
diff --git a/spec/ruby/library/net/http/httpheader/each_capitalized_name_spec.rb b/spec/ruby/library/net/http/httpheader/each_capitalized_name_spec.rb
deleted file mode 100644
index 1af2c6939c..0000000000
--- a/spec/ruby/library/net/http/httpheader/each_capitalized_name_spec.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-
-describe "Net::HTTPHeader#each_capitalized_name" do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- @headers["My-Header"] = "test"
- @headers.add_field("My-Other-Header", "a")
- @headers.add_field("My-Other-Header", "b")
- end
-
- describe "when passed a block" do
- it "yields each header key to the passed block (keys capitalized)" do
- res = []
- @headers.each_capitalized_name do |key|
- res << key
- end
- res.sort.should == ["My-Header", "My-Other-Header"]
- end
- end
-
- describe "when passed no block" do
- it "returns an Enumerator" do
- enumerator = @headers.each_capitalized_name
- enumerator.should be_an_instance_of(Enumerator)
-
- res = []
- enumerator.each do |key|
- res << key
- end
- res.sort.should == ["My-Header", "My-Other-Header"]
- end
- end
-end
diff --git a/spec/ruby/library/net/http/httpheader/each_capitalized_spec.rb b/spec/ruby/library/net/http/httpheader/each_capitalized_spec.rb
deleted file mode 100644
index 961a2d051f..0000000000
--- a/spec/ruby/library/net/http/httpheader/each_capitalized_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-require_relative 'shared/each_capitalized'
-
-describe "Net::HTTPHeader#each_capitalized" do
- it_behaves_like :net_httpheader_each_capitalized, :each_capitalized
-end
diff --git a/spec/ruby/library/net/http/httpheader/each_header_spec.rb b/spec/ruby/library/net/http/httpheader/each_header_spec.rb
deleted file mode 100644
index 19634a001b..0000000000
--- a/spec/ruby/library/net/http/httpheader/each_header_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-require_relative 'shared/each_header'
-
-describe "Net::HTTPHeader#each_header" do
- it_behaves_like :net_httpheader_each_header, :each_header
-end
diff --git a/spec/ruby/library/net/http/httpheader/each_key_spec.rb b/spec/ruby/library/net/http/httpheader/each_key_spec.rb
deleted file mode 100644
index ebb17d2eac..0000000000
--- a/spec/ruby/library/net/http/httpheader/each_key_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-require_relative 'shared/each_name'
-
-describe "Net::HTTPHeader#each_key" do
- it_behaves_like :net_httpheader_each_name, :each_key
-end
diff --git a/spec/ruby/library/net/http/httpheader/each_name_spec.rb b/spec/ruby/library/net/http/httpheader/each_name_spec.rb
deleted file mode 100644
index f4533ebcfb..0000000000
--- a/spec/ruby/library/net/http/httpheader/each_name_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-require_relative 'shared/each_name'
-
-describe "Net::HTTPHeader#each_name" do
- it_behaves_like :net_httpheader_each_name, :each_name
-end
diff --git a/spec/ruby/library/net/http/httpheader/each_spec.rb b/spec/ruby/library/net/http/httpheader/each_spec.rb
deleted file mode 100644
index 7ba8434f75..0000000000
--- a/spec/ruby/library/net/http/httpheader/each_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-require_relative 'shared/each_header'
-
-describe "Net::HTTPHeader#each" do
- it_behaves_like :net_httpheader_each_header, :each
-end
diff --git a/spec/ruby/library/net/http/httpheader/each_value_spec.rb b/spec/ruby/library/net/http/httpheader/each_value_spec.rb
deleted file mode 100644
index 3224de7703..0000000000
--- a/spec/ruby/library/net/http/httpheader/each_value_spec.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-
-describe "Net::HTTPHeader#each_value" do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- @headers["My-Header"] = "test"
- @headers.add_field("My-Other-Header", "a")
- @headers.add_field("My-Other-Header", "b")
- end
-
- describe "when passed a block" do
- it "yields each header entry's joined values" do
- res = []
- @headers.each_value do |value|
- res << value
- end
- res.sort.should == ["a, b", "test"]
- end
- end
-
- describe "when passed no block" do
- it "returns an Enumerator" do
- enumerator = @headers.each_value
- enumerator.should be_an_instance_of(Enumerator)
-
- res = []
- enumerator.each do |key|
- res << key
- end
- res.sort.should == ["a, b", "test"]
- end
- end
-end
diff --git a/spec/ruby/library/net/http/httpheader/element_reference_spec.rb b/spec/ruby/library/net/http/httpheader/element_reference_spec.rb
deleted file mode 100644
index 4a35e20d20..0000000000
--- a/spec/ruby/library/net/http/httpheader/element_reference_spec.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-
-describe "Net::HTTPHeader#[] when passed key" do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- end
-
- it "returns the value of the header entry with the passed key" do
- @headers["My-Header"] = "test"
- @headers["My-Header"].should == "test"
- @headers["My-Other-Header"] = "another test"
- @headers["My-Other-Header"].should == "another test"
- end
-
- it "is case-insensitive" do
- @headers["My-Header"] = "test"
-
- @headers['My-Header'].should == "test"
- @headers['my-Header'].should == "test"
- @headers['My-header'].should == "test"
- @headers['my-header'].should == "test"
- @headers['MY-HEADER'].should == "test"
- end
-
- it "returns multi-element values joined together" do
- @headers["My-Header"] = "test"
- @headers.add_field("My-Header", "another test")
- @headers.add_field("My-Header", "and one more")
-
- @headers["My-Header"].should == "test, another test, and one more"
- end
-
- it "returns nil for non-existing entries" do
- @headers["My-Header"].should be_nil
- @headers["My-Other-Header"].should be_nil
- end
-end
diff --git a/spec/ruby/library/net/http/httpheader/element_set_spec.rb b/spec/ruby/library/net/http/httpheader/element_set_spec.rb
deleted file mode 100644
index e9ad64fafc..0000000000
--- a/spec/ruby/library/net/http/httpheader/element_set_spec.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-
-describe "Net::HTTPHeader#[]= when passed key, value" do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- end
-
- it "sets the header entry with the passed key to the passed value" do
- @headers["My-Header"] = "test"
- @headers["My-Header"].should == "test"
-
- @headers["My-Header"] = "overwritten"
- @headers["My-Header"].should == "overwritten"
-
- @headers["My-Other-Header"] = "another test"
- @headers["My-Other-Header"].should == "another test"
- end
-
- it "is case-insensitive" do
- @headers['My-Header'] = "test"
- @headers['my-Header'] = "another test"
- @headers['My-header'] = "and one more test"
- @headers['my-header'] = "and another one"
- @headers['MY-HEADER'] = "last one"
-
- @headers["My-Header"].should == "last one"
- @headers.size.should eql(1)
- end
-
- it "removes the header entry with the passed key when the value is false or nil" do
- @headers['My-Header'] = "test"
- @headers['My-Header'] = nil
- @headers['My-Header'].should be_nil
-
- @headers['My-Header'] = "test"
- @headers['My-Header'] = false
- @headers['My-Header'].should be_nil
- end
-end
diff --git a/spec/ruby/library/net/http/httpheader/fetch_spec.rb b/spec/ruby/library/net/http/httpheader/fetch_spec.rb
deleted file mode 100644
index ea15679acb..0000000000
--- a/spec/ruby/library/net/http/httpheader/fetch_spec.rb
+++ /dev/null
@@ -1,68 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-
-describe "Net::HTTPHeader#fetch" do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- end
-
- describe "when passed key" do
- it "returns the header entry for the passed key" do
- @headers["My-Header"] = "test"
- @headers.fetch("My-Header").should == "test"
-
- @headers.add_field("My-Other-Header", "a")
- @headers.add_field("My-Other-Header", "b")
- @headers.add_field("My-Other-Header", "c")
- @headers.fetch("My-Other-Header").should == "a, b, c"
- end
-
- it "is case-insensitive" do
- @headers["My-Header"] = "test"
- @headers.fetch("my-header").should == "test"
- @headers.fetch("MY-HEADER").should == "test"
- end
-
- it "returns nil when there is no entry for the passed key" do
- -> { @headers.fetch("my-header") }.should raise_error(IndexError)
- end
- end
-
- describe "when passed key, default" do
- it "returns the header entry for the passed key" do
- @headers["My-Header"] = "test"
- @headers.fetch("My-Header", "bla").should == "test"
-
- @headers.add_field("My-Other-Header", "a")
- @headers.add_field("My-Other-Header", "b")
- @headers.add_field("My-Other-Header", "c")
- @headers.fetch("My-Other-Header", "bla").should == "a, b, c"
- end
-
- # TODO: This raises a NoMethodError: undefined method `join' for "bla":String
- it "returns the default value when there is no entry for the passed key" do
- @headers.fetch("My-Header", "bla").should == "bla"
- end
- end
-
- describe "when passed key and block" do
- it "returns the header entry for the passed key" do
- @headers["My-Header"] = "test"
- @headers.fetch("My-Header") {}.should == "test"
-
- @headers.add_field("My-Other-Header", "a")
- @headers.add_field("My-Other-Header", "b")
- @headers.add_field("My-Other-Header", "c")
- -> {
- @result = @headers.fetch("My-Other-Header", "bla") {}
- }.should complain(/block supersedes default value argument/)
- @result.should == "a, b, c"
- end
-
- # TODO: This raises a NoMethodError: undefined method `join' for "redaeh-ym":String
- it "yieldsand returns the block's return value when there is no entry for the passed key" do
- @headers.fetch("My-Header") { |key| key.reverse }.should == "redaeh-ym"
- end
- end
-end
diff --git a/spec/ruby/library/net/http/httpheader/form_data_spec.rb b/spec/ruby/library/net/http/httpheader/form_data_spec.rb
deleted file mode 100644
index 9b29a03159..0000000000
--- a/spec/ruby/library/net/http/httpheader/form_data_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-require_relative 'shared/set_form_data'
-
-describe "Net::HTTPHeader#form_data=" do
- it_behaves_like :net_httpheader_set_form_data, :form_data=
-end
diff --git a/spec/ruby/library/net/http/httpheader/get_fields_spec.rb b/spec/ruby/library/net/http/httpheader/get_fields_spec.rb
deleted file mode 100644
index 1b623bf2a3..0000000000
--- a/spec/ruby/library/net/http/httpheader/get_fields_spec.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-
-describe "Net::HTTPHeader#get_fields when passed key" do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- end
-
- it "returns an Array containing the values of the header entry with the passed key" do
- @headers["My-Header"] = "a"
- @headers.get_fields("My-Header").should == ["a"]
-
- @headers.add_field("My-Header", "b")
- @headers.get_fields("My-Header").should == ["a", "b"]
- end
-
- it "returns a copy of the header entry values" do
- @headers["My-Header"] = "a"
-
- @headers.get_fields("My-Header").clear
- @headers.get_fields("My-Header").should == ["a"]
-
- @headers.get_fields("My-Header") << "b"
- @headers.get_fields("My-Header").should == ["a"]
- end
-
- it "returns nil for non-existing header entries" do
- @headers.get_fields("My-Header").should be_nil
- @headers.get_fields("My-Other-header").should be_nil
- end
-
- it "is case-insensitive" do
- @headers["My-Header"] = "test"
- @headers.get_fields("My-Header").should == ["test"]
- @headers.get_fields("my-header").should == ["test"]
- @headers.get_fields("MY-HEADER").should == ["test"]
- end
-end
diff --git a/spec/ruby/library/net/http/httpheader/initialize_http_header_spec.rb b/spec/ruby/library/net/http/httpheader/initialize_http_header_spec.rb
deleted file mode 100644
index efc5e7d0b2..0000000000
--- a/spec/ruby/library/net/http/httpheader/initialize_http_header_spec.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-
-describe "Net::HTTPHeader#initialize_http_header when passed Hash" do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.allocate
- end
-
- it "initializes the HTTP Header using the passed Hash" do
- @headers.initialize_http_header("My-Header" => "test", "My-Other-Header" => "another test")
- @headers["My-Header"].should == "test"
- @headers["My-Other-Header"].should == "another test"
- end
-
- it "complains about duplicate keys when in verbose mode" do
- -> do
- @headers.initialize_http_header("My-Header" => "test", "my-header" => "another test")
- end.should complain(/duplicated HTTP header/, verbose: true)
- end
-end
diff --git a/spec/ruby/library/net/http/httpheader/key_spec.rb b/spec/ruby/library/net/http/httpheader/key_spec.rb
deleted file mode 100644
index 9099024229..0000000000
--- a/spec/ruby/library/net/http/httpheader/key_spec.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-
-describe "Net::HTTPHeader#key? when passed key" do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- end
-
- it "returns true if the header entry with the passed key exists" do
- @headers.key?("My-Header").should be_false
- @headers["My-Header"] = "test"
- @headers.key?("My-Header").should be_true
- end
-
- it "is case-insensitive" do
- @headers["My-Header"] = "test"
- @headers.key?("my-header").should be_true
- @headers.key?("MY-HEADER").should be_true
- end
-end
diff --git a/spec/ruby/library/net/http/httpheader/length_spec.rb b/spec/ruby/library/net/http/httpheader/length_spec.rb
deleted file mode 100644
index 0d1da149f4..0000000000
--- a/spec/ruby/library/net/http/httpheader/length_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-require_relative 'shared/size'
-
-describe "Net::HTTPHeader#length" do
- it_behaves_like :net_httpheader_size, :length
-end
diff --git a/spec/ruby/library/net/http/httpheader/main_type_spec.rb b/spec/ruby/library/net/http/httpheader/main_type_spec.rb
deleted file mode 100644
index 3e18de6b5b..0000000000
--- a/spec/ruby/library/net/http/httpheader/main_type_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-
-describe "Net::HTTPHeader#main_type" do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- end
-
- it "returns the 'main-content-type', as per 'Content-Type' header entry" do
- @headers["Content-Type"] = "text/html"
- @headers.main_type.should == "text"
-
- @headers["Content-Type"] = "application/pdf"
- @headers.main_type.should == "application"
-
- @headers["Content-Type"] = "text/html;charset=utf-8"
- @headers.main_type.should == "text"
- end
-
- it "returns nil if the 'Content-Type' header entry does not exist" do
- @headers.main_type.should be_nil
- end
-end
diff --git a/spec/ruby/library/net/http/httpheader/proxy_basic_auth_spec.rb b/spec/ruby/library/net/http/httpheader/proxy_basic_auth_spec.rb
deleted file mode 100644
index 8b576ee164..0000000000
--- a/spec/ruby/library/net/http/httpheader/proxy_basic_auth_spec.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-
-describe "Net::HTTPHeader#proxy_basic_auth when passed account, password" do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- end
-
- it "sets the 'Proxy-Authorization' Header entry for basic authorization" do
- @headers.proxy_basic_auth("rubyspec", "rocks")
- @headers["Proxy-Authorization"].should == "Basic cnVieXNwZWM6cm9ja3M="
- end
-end
diff --git a/spec/ruby/library/net/http/httpheader/range_length_spec.rb b/spec/ruby/library/net/http/httpheader/range_length_spec.rb
deleted file mode 100644
index b8fce4f690..0000000000
--- a/spec/ruby/library/net/http/httpheader/range_length_spec.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-
-describe "Net::HTTPHeader#range_length" do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- end
-
- it "returns the length of the Range represented by the 'Content-Range' header entry" do
- @headers["Content-Range"] = "bytes 0-499/1234"
- @headers.range_length.should eql(500)
-
- @headers["Content-Range"] = "bytes 500-1233/1234"
- @headers.range_length.should eql(734)
- end
-
- it "returns nil when there is no 'Content-Range' header entry" do
- @headers.range_length.should be_nil
- end
-
- it "raises a Net::HTTPHeaderSyntaxError when the 'Content-Range' has an invalid format" do
- @headers["Content-Range"] = "invalid"
- -> { @headers.range_length }.should raise_error(Net::HTTPHeaderSyntaxError)
-
- @headers["Content-Range"] = "bytes 123-abc"
- -> { @headers.range_length }.should raise_error(Net::HTTPHeaderSyntaxError)
-
- @headers["Content-Range"] = "bytes abc-123"
- -> { @headers.range_length }.should raise_error(Net::HTTPHeaderSyntaxError)
- end
-end
diff --git a/spec/ruby/library/net/http/httpheader/range_spec.rb b/spec/ruby/library/net/http/httpheader/range_spec.rb
deleted file mode 100644
index 005177f6be..0000000000
--- a/spec/ruby/library/net/http/httpheader/range_spec.rb
+++ /dev/null
@@ -1,48 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-require_relative 'shared/set_range'
-
-describe "Net::HTTPHeader#range" do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- end
-
- it "returns a Range object that represents the 'Range' header entry" do
- @headers["Range"] = "bytes=0-499"
- @headers.range.should == [0..499]
-
- @headers["Range"] = "bytes=500-1233"
- @headers.range.should == [500..1233]
-
- @headers["Range"] = "bytes=10-"
- @headers.range.should == [10..-1]
-
- @headers["Range"] = "bytes=-10"
- @headers.range.should == [-10..-1]
- end
-
- it "returns nil when there is no 'Range' header entry" do
- @headers.range.should be_nil
- end
-
- it "raises a Net::HTTPHeaderSyntaxError when the 'Range' has an invalid format" do
- @headers["Range"] = "invalid"
- -> { @headers.range }.should raise_error(Net::HTTPHeaderSyntaxError)
-
- @headers["Range"] = "bytes 123-abc"
- -> { @headers.range }.should raise_error(Net::HTTPHeaderSyntaxError)
-
- @headers["Range"] = "bytes abc-123"
- -> { @headers.range }.should raise_error(Net::HTTPHeaderSyntaxError)
- end
-
- it "raises a Net::HTTPHeaderSyntaxError when the 'Range' was not specified" do
- @headers["Range"] = "bytes=-"
- -> { @headers.range }.should raise_error(Net::HTTPHeaderSyntaxError)
- end
-end
-
-describe "Net::HTTPHeader#range=" do
- it_behaves_like :net_httpheader_set_range, :range=
-end
diff --git a/spec/ruby/library/net/http/httpheader/set_content_type_spec.rb b/spec/ruby/library/net/http/httpheader/set_content_type_spec.rb
deleted file mode 100644
index 125f7a7e0d..0000000000
--- a/spec/ruby/library/net/http/httpheader/set_content_type_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-require_relative 'shared/set_content_type'
-
-describe "Net::HTTPHeader#set_content_type" do
- it_behaves_like :net_httpheader_set_content_type, :set_content_type
-end
diff --git a/spec/ruby/library/net/http/httpheader/set_form_data_spec.rb b/spec/ruby/library/net/http/httpheader/set_form_data_spec.rb
deleted file mode 100644
index 14c66ae01c..0000000000
--- a/spec/ruby/library/net/http/httpheader/set_form_data_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-require_relative 'shared/set_form_data'
-
-describe "Net::HTTPHeader#set_form_data" do
- it_behaves_like :net_httpheader_set_form_data, :set_form_data
-end
diff --git a/spec/ruby/library/net/http/httpheader/set_range_spec.rb b/spec/ruby/library/net/http/httpheader/set_range_spec.rb
deleted file mode 100644
index 85b9c50422..0000000000
--- a/spec/ruby/library/net/http/httpheader/set_range_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-require_relative 'shared/set_range'
-
-describe "Net::HTTPHeader#set_range" do
- it_behaves_like :net_httpheader_set_range, :set_range
-end
diff --git a/spec/ruby/library/net/http/httpheader/size_spec.rb b/spec/ruby/library/net/http/httpheader/size_spec.rb
deleted file mode 100644
index a7d78f96e0..0000000000
--- a/spec/ruby/library/net/http/httpheader/size_spec.rb
+++ /dev/null
@@ -1,8 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-require_relative 'shared/size'
-
-describe "Net::HTTPHeader#size" do
- it_behaves_like :net_httpheader_size, :size
-end
diff --git a/spec/ruby/library/net/http/httpheader/sub_type_spec.rb b/spec/ruby/library/net/http/httpheader/sub_type_spec.rb
deleted file mode 100644
index 3c73ca0027..0000000000
--- a/spec/ruby/library/net/http/httpheader/sub_type_spec.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-
-describe "Net::HTTPHeader#sub_type" do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- end
-
- it "returns the 'sub-content-type', as per 'Content-Type' header entry" do
- @headers["Content-Type"] = "text/html"
- @headers.sub_type.should == "html"
-
- @headers["Content-Type"] = "application/pdf"
- @headers.sub_type.should == "pdf"
-
- @headers["Content-Type"] = "text/html;charset=utf-8"
- @headers.sub_type.should == "html"
- end
-
- it "returns nil if no 'sub-content-type' is set" do
- @headers["Content-Type"] = "text"
- @headers.sub_type.should be_nil
-
- @headers["Content-Type"] = "text;charset=utf-8"
- @headers.sub_type.should be_nil
- end
-
- it "returns nil if the 'Content-Type' header entry does not exist" do
- @headers.sub_type.should be_nil
- end
-end
diff --git a/spec/ruby/library/net/http/httpheader/to_hash_spec.rb b/spec/ruby/library/net/http/httpheader/to_hash_spec.rb
deleted file mode 100644
index 8c1d36c30a..0000000000
--- a/spec/ruby/library/net/http/httpheader/to_hash_spec.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-
-describe "Net::HTTPHeader#to_hash" do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- end
-
- it "returns a Hash representing all Header entries (keys in lower case, values as arrays)" do
- @headers.to_hash.should == {}
-
- @headers["My-Header"] = "test"
- @headers.to_hash.should == { "my-header" => ["test"] }
-
- @headers.add_field("My-Header", "another test")
- @headers.to_hash.should == { "my-header" => ["test", "another test"] }
- end
-
- it "does not allow modifying the headers from the returned hash" do
- @headers.to_hash["my-header"] = ["test"]
- @headers.to_hash.should == {}
- @headers.key?("my-header").should be_false
- end
-end
diff --git a/spec/ruby/library/net/http/httpheader/type_params_spec.rb b/spec/ruby/library/net/http/httpheader/type_params_spec.rb
deleted file mode 100644
index e77be7ea85..0000000000
--- a/spec/ruby/library/net/http/httpheader/type_params_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'fixtures/classes'
-
-describe "Net::HTTPHeader#type_params" do
- before :each do
- @headers = NetHTTPHeaderSpecs::Example.new
- end
-
- it "returns additional 'Content-Type' information as a Hash" do
- @headers["Content-Type"] = "text/html;charset=utf-8"
- @headers.type_params.should == {"charset" => "utf-8"}
-
- @headers["Content-Type"] = "text/html; charset=utf-8; rubyspec=rocks"
- @headers.type_params.should == {"charset" => "utf-8", "rubyspec" => "rocks"}
- end
-
- it "returns an empty Hash when no additional 'Content-Type' information is set" do
- @headers.type_params.should == {}
-
- @headers["Content-Type"] = "text/html"
- @headers.type_params.should == {}
- end
-end
diff --git a/spec/ruby/library/net/http/httprequest/initialize_spec.rb b/spec/ruby/library/net/http/httprequest/initialize_spec.rb
deleted file mode 100644
index 88e9fb1c77..0000000000
--- a/spec/ruby/library/net/http/httprequest/initialize_spec.rb
+++ /dev/null
@@ -1,45 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-
-module NetHTTPRequestSpecs
- class TestRequest < Net::HTTPRequest
- METHOD = "TEST"
- REQUEST_HAS_BODY = false
- RESPONSE_HAS_BODY = true
- end
-end
-
-describe "Net::HTTPRequest#initialize" do
- before :each do
- @req = NetHTTPRequestSpecs::TestRequest.allocate
- end
-
- it "uses the METHOD constants to set the request method" do
- @req.send(:initialize, "/some/path")
- @req.method.should == "TEST"
- end
-
- it "uses the REQUEST_HAS_BODY to set whether the Request has a body or not" do
- @req.send(:initialize, "/some/path")
- @req.request_body_permitted?.should be_false
- end
-
- it "uses the RESPONSE_HAS_BODY to set whether the Response can have a body or not" do
- @req.send(:initialize, "/some/path")
- @req.response_body_permitted?.should be_true
- end
-
- describe "when passed path" do
- it "sets self's path to the passed path" do
- @req.send(:initialize, "/some/path")
- @req.path.should == "/some/path"
- end
- end
-
- describe "when passed path, headers" do
- it "uses the passed headers Hash to initialize self's header entries" do
- @req.send(:initialize, "/some/path", "Content-Type" => "text/html")
- @req["Content-Type"].should == "text/html"
- end
- end
-end
diff --git a/spec/ruby/library/net/http/httpresponse/body_permitted_spec.rb b/spec/ruby/library/net/http/httpresponse/body_permitted_spec.rb
deleted file mode 100644
index 8ade46689f..0000000000
--- a/spec/ruby/library/net/http/httpresponse/body_permitted_spec.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPResponse.body_permitted?" do
- it "returns true if this response type can have a response body" do
- Net::HTTPUnknownResponse.should.body_permitted?
- Net::HTTPInformation.should_not.body_permitted?
- Net::HTTPSuccess.should.body_permitted?
- Net::HTTPRedirection.should.body_permitted?
- Net::HTTPClientError.should.body_permitted?
- Net::HTTPServerError.should.body_permitted?
- end
-end
diff --git a/spec/ruby/library/net/http/httpresponse/body_spec.rb b/spec/ruby/library/net/http/httpresponse/body_spec.rb
deleted file mode 100644
index 79569441f1..0000000000
--- a/spec/ruby/library/net/http/httpresponse/body_spec.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'shared/body'
-
-describe "Net::HTTPResponse#body" do
- it_behaves_like :net_httpresponse_body, :body
-end
diff --git a/spec/ruby/library/net/http/httpresponse/code_spec.rb b/spec/ruby/library/net/http/httpresponse/code_spec.rb
deleted file mode 100644
index 114277cb43..0000000000
--- a/spec/ruby/library/net/http/httpresponse/code_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPResponse#code" do
- it "returns the result code string" do
- res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
- res.code.should == "???"
-
- res = Net::HTTPInformation.new("1.0", "1xx", "test response")
- res.code.should == "1xx"
-
- res = Net::HTTPSuccess.new("1.0", "2xx", "test response")
- res.code.should == "2xx"
-
- res = Net::HTTPRedirection.new("1.0", "3xx", "test response")
- res.code.should == "3xx"
-
- res = Net::HTTPClientError.new("1.0", "4xx", "test response")
- res.code.should == "4xx"
-
- res = Net::HTTPServerError.new("1.0", "5xx", "test response")
- res.code.should == "5xx"
- end
-end
diff --git a/spec/ruby/library/net/http/httpresponse/code_type_spec.rb b/spec/ruby/library/net/http/httpresponse/code_type_spec.rb
deleted file mode 100644
index fa2d572e9a..0000000000
--- a/spec/ruby/library/net/http/httpresponse/code_type_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPResponse#code_type" do
- it "returns self's class" do
- res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
- res.code_type.should == Net::HTTPUnknownResponse
-
- res = Net::HTTPInformation.new("1.0", "1xx", "test response")
- res.code_type.should == Net::HTTPInformation
-
- res = Net::HTTPSuccess.new("1.0", "2xx", "test response")
- res.code_type.should == Net::HTTPSuccess
-
- res = Net::HTTPRedirection.new("1.0", "3xx", "test response")
- res.code_type.should == Net::HTTPRedirection
-
- res = Net::HTTPClientError.new("1.0", "4xx", "test response")
- res.code_type.should == Net::HTTPClientError
-
- res = Net::HTTPServerError.new("1.0", "5xx", "test response")
- res.code_type.should == Net::HTTPServerError
- end
-end
diff --git a/spec/ruby/library/net/http/httpresponse/entity_spec.rb b/spec/ruby/library/net/http/httpresponse/entity_spec.rb
deleted file mode 100644
index f1639042c1..0000000000
--- a/spec/ruby/library/net/http/httpresponse/entity_spec.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require_relative 'shared/body'
-
-describe "Net::HTTPResponse#entity" do
- it_behaves_like :net_httpresponse_body, :entity
-end
diff --git a/spec/ruby/library/net/http/httpresponse/error_spec.rb b/spec/ruby/library/net/http/httpresponse/error_spec.rb
deleted file mode 100644
index 89f4a47f60..0000000000
--- a/spec/ruby/library/net/http/httpresponse/error_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPResponse#error!" do
- it "raises self's class 'EXCEPTION_TYPE' Exception" do
- res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
- -> { res.error! }.should raise_error(Net::HTTPError)
-
- res = Net::HTTPInformation.new("1.0", "1xx", "test response")
- -> { res.error! }.should raise_error(Net::HTTPError)
-
- res = Net::HTTPSuccess.new("1.0", "2xx", "test response")
- -> { res.error! }.should raise_error(Net::HTTPError)
-
- res = Net::HTTPRedirection.new("1.0", "3xx", "test response")
- -> { res.error! }.should raise_error(Net::HTTPRetriableError)
-
- res = Net::HTTPClientError.new("1.0", "4xx", "test response")
- -> { res.error! }.should raise_error(Net::HTTPClientException)
-
- res = Net::HTTPServerError.new("1.0", "5xx", "test response")
- -> { res.error! }.should raise_error(Net::HTTPFatalError)
- end
-end
diff --git a/spec/ruby/library/net/http/httpresponse/error_type_spec.rb b/spec/ruby/library/net/http/httpresponse/error_type_spec.rb
deleted file mode 100644
index 8885b7706b..0000000000
--- a/spec/ruby/library/net/http/httpresponse/error_type_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPResponse#error_type" do
- it "returns self's class 'EXCEPTION_TYPE' constant" do
- res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
- res.error_type.should == Net::HTTPError
-
- res = Net::HTTPInformation.new("1.0", "1xx", "test response")
- res.error_type.should == Net::HTTPError
-
- res = Net::HTTPSuccess.new("1.0", "2xx", "test response")
- res.error_type.should == Net::HTTPError
-
- res = Net::HTTPRedirection.new("1.0", "3xx", "test response")
- res.error_type.should == Net::HTTPRetriableError
-
- res = Net::HTTPClientError.new("1.0", "4xx", "test response")
- res.error_type.should == Net::HTTPClientException
-
- res = Net::HTTPServerError.new("1.0", "5xx", "test response")
- res.error_type.should == Net::HTTPFatalError
- end
-end
diff --git a/spec/ruby/library/net/http/httpresponse/exception_type_spec.rb b/spec/ruby/library/net/http/httpresponse/exception_type_spec.rb
deleted file mode 100644
index 0c9c11291f..0000000000
--- a/spec/ruby/library/net/http/httpresponse/exception_type_spec.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPResponse.exception_type" do
- it "returns self's 'EXCEPTION_TYPE' constant" do
- Net::HTTPUnknownResponse.exception_type.should == Net::HTTPError
- Net::HTTPInformation.exception_type.should == Net::HTTPError
- Net::HTTPSuccess.exception_type.should == Net::HTTPError
- Net::HTTPRedirection.exception_type.should == Net::HTTPRetriableError
- Net::HTTPClientError.exception_type.should == Net::HTTPClientException
- Net::HTTPServerError.exception_type.should == Net::HTTPFatalError
- end
-end
diff --git a/spec/ruby/library/net/http/httpresponse/header_spec.rb b/spec/ruby/library/net/http/httpresponse/header_spec.rb
deleted file mode 100644
index a9615feda8..0000000000
--- a/spec/ruby/library/net/http/httpresponse/header_spec.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPResponse#header" do
- it "returns self" do
- res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
- res.response.should equal(res)
- end
-end
diff --git a/spec/ruby/library/net/http/httpresponse/http_version_spec.rb b/spec/ruby/library/net/http/httpresponse/http_version_spec.rb
deleted file mode 100644
index db85696d77..0000000000
--- a/spec/ruby/library/net/http/httpresponse/http_version_spec.rb
+++ /dev/null
@@ -1,12 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPResponse#http_version" do
- it "returns self's http version" do
- res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
- res.http_version.should == "1.0"
-
- res = Net::HTTPUnknownResponse.new("1.1", "???", "test response")
- res.http_version.should == "1.1"
- end
-end
diff --git a/spec/ruby/library/net/http/httpresponse/initialize_spec.rb b/spec/ruby/library/net/http/httpresponse/initialize_spec.rb
deleted file mode 100644
index eb77e2e277..0000000000
--- a/spec/ruby/library/net/http/httpresponse/initialize_spec.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPResponse#initialize when passed http_version, response_code, response_message" do
- it "sets self http_version, response_code and response_message to the passed values" do
- res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
- res.http_version.should == "1.0"
- res.code.should == "???"
- res.message.should == "test response"
- end
-end
diff --git a/spec/ruby/library/net/http/httpresponse/inspect_spec.rb b/spec/ruby/library/net/http/httpresponse/inspect_spec.rb
deleted file mode 100644
index 1e1a2c7cc7..0000000000
--- a/spec/ruby/library/net/http/httpresponse/inspect_spec.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require "stringio"
-
-describe "Net::HTTPResponse#inspect" do
- it "returns a String representation of self" do
- res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
- res.inspect.should == "#<Net::HTTPUnknownResponse ??? test response readbody=false>"
-
- res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
- socket = Net::BufferedIO.new(StringIO.new("test body"))
- res.reading_body(socket, true) {}
- res.inspect.should == "#<Net::HTTPUnknownResponse ??? test response readbody=true>"
- end
-end
diff --git a/spec/ruby/library/net/http/httpresponse/message_spec.rb b/spec/ruby/library/net/http/httpresponse/message_spec.rb
deleted file mode 100644
index ae8e3678a1..0000000000
--- a/spec/ruby/library/net/http/httpresponse/message_spec.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPResponse#message" do
- it "returns self's response message" do
- res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
- res.message.should == "test response"
- end
-end
diff --git a/spec/ruby/library/net/http/httpresponse/msg_spec.rb b/spec/ruby/library/net/http/httpresponse/msg_spec.rb
deleted file mode 100644
index 0e5e7eb4aa..0000000000
--- a/spec/ruby/library/net/http/httpresponse/msg_spec.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPResponse#msg" do
- it "returns self's response message" do
- res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
- res.message.should == "test response"
- end
-end
diff --git a/spec/ruby/library/net/http/httpresponse/read_body_spec.rb b/spec/ruby/library/net/http/httpresponse/read_body_spec.rb
deleted file mode 100644
index ec9b42f919..0000000000
--- a/spec/ruby/library/net/http/httpresponse/read_body_spec.rb
+++ /dev/null
@@ -1,86 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require 'stringio'
-
-describe "Net::HTTPResponse#read_body" do
- before :each do
- @res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
- @socket = Net::BufferedIO.new(StringIO.new("test body"))
- end
-
- describe "when passed no arguments" do
- it "returns the read body" do
- @res.reading_body(@socket, true) do
- @res.read_body.should == "test body"
- end
- end
-
- it "returns the previously read body if called a second time" do
- @res.reading_body(@socket, true) do
- @res.read_body.should equal(@res.read_body)
- end
- end
- end
-
- describe "when passed a buffer" do
- it "reads the body to the passed buffer" do
- @res.reading_body(@socket, true) do
- buffer = ""
- @res.read_body(buffer)
- buffer.should == "test body"
- end
- end
-
- it "returns the passed buffer" do
- @res.reading_body(@socket, true) do
- buffer = ""
- @res.read_body(buffer).should equal(buffer)
- end
- end
-
- it "raises an IOError if called a second time" do
- @res.reading_body(@socket, true) do
- @res.read_body("")
- -> { @res.read_body("") }.should raise_error(IOError)
- end
- end
- end
-
- describe "when passed a block" do
- it "reads the body and yields it to the passed block (in chunks)" do
- @res.reading_body(@socket, true) do
- yielded = false
-
- buffer = ""
- @res.read_body do |body|
- yielded = true
- buffer << body
- end
-
- yielded.should be_true
- buffer.should == "test body"
- end
- end
-
- it "returns the ReadAdapter" do
- @res.reading_body(@socket, true) do
- @res.read_body { nil }.should be_kind_of(Net::ReadAdapter)
- end
- end
-
- it "raises an IOError if called a second time" do
- @res.reading_body(@socket, true) do
- @res.read_body {}
- -> { @res.read_body {} }.should raise_error(IOError)
- end
- end
- end
-
- describe "when passed buffer and block" do
- it "raises an ArgumentError" do
- @res.reading_body(@socket, true) do
- -> { @res.read_body("") {} }.should raise_error(ArgumentError)
- end
- end
- end
-end
diff --git a/spec/ruby/library/net/http/httpresponse/read_header_spec.rb b/spec/ruby/library/net/http/httpresponse/read_header_spec.rb
deleted file mode 100644
index 6af8c6bd6a..0000000000
--- a/spec/ruby/library/net/http/httpresponse/read_header_spec.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPResponse#read_header" do
- it "returns self" do
- res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
- res.response.should equal(res)
- end
-end
diff --git a/spec/ruby/library/net/http/httpresponse/read_new_spec.rb b/spec/ruby/library/net/http/httpresponse/read_new_spec.rb
deleted file mode 100644
index dc2cdc9621..0000000000
--- a/spec/ruby/library/net/http/httpresponse/read_new_spec.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require 'stringio'
-
-describe "Net::HTTPResponse.read_new" do
- it "creates a HTTPResponse object based on the response read from the passed socket" do
- socket = Net::BufferedIO.new(StringIO.new(<<EOS))
-HTTP/1.1 200 OK
-Content-Type: text/html; charset=utf-8
-
-test-body
-EOS
- response = Net::HTTPResponse.read_new(socket)
-
- response.should be_kind_of(Net::HTTPOK)
- response.code.should == "200"
- response["Content-Type"].should == "text/html; charset=utf-8"
-
- response.reading_body(socket, true) do
- response.body.should == "test-body\n"
- end
- end
-end
diff --git a/spec/ruby/library/net/http/httpresponse/reading_body_spec.rb b/spec/ruby/library/net/http/httpresponse/reading_body_spec.rb
deleted file mode 100644
index ebdab891e1..0000000000
--- a/spec/ruby/library/net/http/httpresponse/reading_body_spec.rb
+++ /dev/null
@@ -1,58 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-require "stringio"
-
-describe "Net::HTTPResponse#reading_body" do
- before :each do
- @res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
- @socket = Net::BufferedIO.new(StringIO.new("test body"))
- end
-
- describe "when body_allowed is true" do
- it "reads and returns the response body for self from the passed socket" do
- @res.reading_body(@socket, true) {}.should == "test body"
- @res.body.should == "test body"
- end
-
- it "yields the passed block before reading the body" do
- yielded = false
-
- @res.reading_body(@socket, true) do
- @res.inspect.should == "#<Net::HTTPUnknownResponse ??? test response readbody=false>"
- yielded = true
- end
-
- yielded.should be_true
- end
-
- describe "but the response type is not allowed to have a body" do
- before :each do
- @res = Net::HTTPInformation.new("1.0", "???", "test response")
- end
-
- it "returns nil" do
- @res.reading_body(@socket, false) {}.should be_nil
- @res.body.should be_nil
- end
-
- it "yields the passed block" do
- yielded = false
- @res.reading_body(@socket, true) { yielded = true }
- yielded.should be_true
- end
- end
- end
-
- describe "when body_allowed is false" do
- it "returns nil" do
- @res.reading_body(@socket, false) {}.should be_nil
- @res.body.should be_nil
- end
-
- it "yields the passed block" do
- yielded = false
- @res.reading_body(@socket, true) { yielded = true }
- yielded.should be_true
- end
- end
-end
diff --git a/spec/ruby/library/net/http/httpresponse/response_spec.rb b/spec/ruby/library/net/http/httpresponse/response_spec.rb
deleted file mode 100644
index f6035f3695..0000000000
--- a/spec/ruby/library/net/http/httpresponse/response_spec.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPResponse#response" do
- it "returns self" do
- res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
- res.response.should equal(res)
- end
-end
diff --git a/spec/ruby/library/net/http/httpresponse/value_spec.rb b/spec/ruby/library/net/http/httpresponse/value_spec.rb
deleted file mode 100644
index 5cd58316ef..0000000000
--- a/spec/ruby/library/net/http/httpresponse/value_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'net/http'
-
-describe "Net::HTTPResponse#value" do
- it "raises an HTTP error for non 2xx HTTP Responses" do
- res = Net::HTTPUnknownResponse.new("1.0", "???", "test response")
- -> { res.value }.should raise_error(Net::HTTPError)
-
- res = Net::HTTPInformation.new("1.0", "1xx", "test response")
- -> { res.value }.should raise_error(Net::HTTPError)
-
- res = Net::HTTPSuccess.new("1.0", "2xx", "test response")
- -> { res.value }.should_not raise_error(Net::HTTPError)
-
- res = Net::HTTPRedirection.new("1.0", "3xx", "test response")
- -> { res.value }.should raise_error(Net::HTTPRetriableError)
-
- res = Net::HTTPClientError.new("1.0", "4xx", "test response")
- -> { res.value }.should raise_error(Net::HTTPClientException)
-
- res = Net::HTTPServerError.new("1.0", "5xx", "test response")
- -> { res.value }.should raise_error(Net::HTTPFatalError)
- end
-end
diff --git a/spec/ruby/library/objectspace/dump_all_spec.rb b/spec/ruby/library/objectspace/dump_all_spec.rb
new file mode 100644
index 0000000000..e9b449a905
--- /dev/null
+++ b/spec/ruby/library/objectspace/dump_all_spec.rb
@@ -0,0 +1,112 @@
+require_relative '../../spec_helper'
+require 'objspace'
+
+describe "ObjectSpace.dump_all" do
+ it "dumps Ruby heap to string when passed output: :string" do
+ stdout = ruby_exe(<<~RUBY, options: "-robjspace")
+ string = "abc"
+ dump = ObjectSpace.dump_all(output: :string)
+ puts dump.class
+ puts dump.include?('"value":"abc"')
+ RUBY
+
+ stdout.should == "String\ntrue\n"
+ end
+
+ it "dumps Ruby heap to a temporary file when passed output: :file" do
+ stdout = ruby_exe(<<~RUBY, options: "-robjspace")
+ string = "abc"
+ file = ObjectSpace.dump_all(output: :file)
+
+ begin
+ file.flush
+ file.rewind
+ content = file.read
+
+ puts file.class
+ puts content.include?('"value":"abc"')
+ ensure
+ file.close
+ File.unlink file.path
+ end
+ RUBY
+
+ stdout.should == "File\ntrue\n"
+ end
+
+ it "dumps Ruby heap to a temporary file when :output not specified" do
+ stdout = ruby_exe(<<~RUBY, options: "-robjspace")
+ string = "abc"
+ file = ObjectSpace.dump_all
+
+ begin
+ file.flush
+ file.rewind
+ content = file.read
+
+ puts file.class
+ puts content.include?('"value":"abc"')
+ ensure
+ file.close
+ File.unlink file.path
+ end
+ RUBY
+
+ stdout.should == "File\ntrue\n"
+ end
+
+ it "dumps Ruby heap to a temporary file when passed output: :nil" do
+ stdout = ruby_exe(<<~RUBY, options: "-robjspace")
+ string = "abc"
+ file = ObjectSpace.dump_all(output: nil)
+
+ begin
+ file.flush
+ file.rewind
+ content = file.read
+
+ puts file.class
+ puts content.include?('"value":"abc"')
+ ensure
+ file.close
+ File.unlink file.path
+ end
+ RUBY
+
+ stdout.should == "File\ntrue\n"
+ end
+
+ it "dumps Ruby heap to stdout when passed output: :stdout" do
+ stdout = ruby_exe(<<~RUBY, options: "-robjspace")
+ string = "abc"
+ ObjectSpace.dump_all(output: :stdout)
+ RUBY
+
+ stdout.should include('"value":"abc"')
+ end
+
+ it "dumps Ruby heap to provided IO when passed output: IO" do
+ stdout = ruby_exe(<<~RUBY, options: "-robjspace -rtempfile")
+ string = "abc"
+ io = Tempfile.create("object_space_dump_all")
+
+ begin
+ result = ObjectSpace.dump_all(output: io)
+ io.rewind
+ content = io.read
+
+ puts result.equal?(io)
+ puts content.include?('"value":"abc"')
+ ensure
+ io.close
+ File.unlink io.path
+ end
+ RUBY
+
+ stdout.should == "true\ntrue\n"
+ end
+
+ it "raises ArgumentError when passed not supported :output value" do
+ -> { ObjectSpace.dump_all(output: Object.new) }.should raise_error(ArgumentError, /wrong output option/)
+ end
+end
diff --git a/spec/ruby/library/objectspace/dump_spec.rb b/spec/ruby/library/objectspace/dump_spec.rb
new file mode 100644
index 0000000000..e22ee3df1e
--- /dev/null
+++ b/spec/ruby/library/objectspace/dump_spec.rb
@@ -0,0 +1,70 @@
+require_relative '../../spec_helper'
+require 'objspace'
+
+describe "ObjectSpace.dump" do
+ it "dumps the content of object as JSON" do
+ require 'json'
+ string = ObjectSpace.dump("abc")
+ dump = JSON.parse(string)
+
+ dump['type'].should == "STRING"
+ dump['value'].should == "abc"
+ end
+
+ it "dumps to string when passed output: :string" do
+ string = ObjectSpace.dump("abc", output: :string)
+ string.should be_kind_of(String)
+ string.should include('"value":"abc"')
+ end
+
+ it "dumps to string when :output not specified" do
+ string = ObjectSpace.dump("abc")
+ string.should be_kind_of(String)
+ string.should include('"value":"abc"')
+ end
+
+ it "dumps to a temporary file when passed output: :file" do
+ file = ObjectSpace.dump("abc", output: :file)
+ file.should be_kind_of(File)
+
+ file.rewind
+ content = file.read
+ content.should include('"value":"abc"')
+ ensure
+ file.close
+ File.unlink file.path
+ end
+
+ it "dumps to a temporary file when passed output: :nil" do
+ file = ObjectSpace.dump("abc", output: nil)
+ file.should be_kind_of(File)
+
+ file.rewind
+ file.read.should include('"value":"abc"')
+ ensure
+ file.close
+ File.unlink file.path
+ end
+
+ it "dumps to stdout when passed output: :stdout" do
+ stdout = ruby_exe('ObjectSpace.dump("abc", output: :stdout)', options: "-robjspace").chomp
+ stdout.should include('"value":"abc"')
+ end
+
+ it "dumps to provided IO when passed output: IO" do
+ filename = tmp("io_read.txt")
+ io = File.open(filename, "w+")
+ result = ObjectSpace.dump("abc", output: io)
+ result.should.equal? io
+
+ io.rewind
+ io.read.should include('"value":"abc"')
+ ensure
+ io.close
+ rm_r filename
+ end
+
+ it "raises ArgumentError when passed not supported :output value" do
+ -> { ObjectSpace.dump("abc", output: Object.new) }.should raise_error(ArgumentError, /wrong output option/)
+ end
+end
diff --git a/spec/ruby/library/objectspace/fixtures/trace.rb b/spec/ruby/library/objectspace/fixtures/trace.rb
new file mode 100644
index 0000000000..e53a7a0cac
--- /dev/null
+++ b/spec/ruby/library/objectspace/fixtures/trace.rb
@@ -0,0 +1,6 @@
+# frozen_string_literal: false
+require "objspace/trace"
+a = "foo"
+b = "b" + "a" + "r"
+c = 42
+p a, b, c
diff --git a/spec/ruby/library/objectspace/reachable_objects_from_spec.rb b/spec/ruby/library/objectspace/reachable_objects_from_spec.rb
index 7e70bc8569..dee5961663 100644
--- a/spec/ruby/library/objectspace/reachable_objects_from_spec.rb
+++ b/spec/ruby/library/objectspace/reachable_objects_from_spec.rb
@@ -38,7 +38,6 @@ describe "ObjectSpace.reachable_objects_from" do
end
it "finds an object stored in a Queue" do
- require 'thread'
o = Object.new
q = Queue.new
q << o
@@ -49,7 +48,6 @@ describe "ObjectSpace.reachable_objects_from" do
end
it "finds an object stored in a SizedQueue" do
- require 'thread'
o = Object.new
q = SizedQueue.new(3)
q << o
diff --git a/spec/ruby/library/objectspace/trace_object_allocations_spec.rb b/spec/ruby/library/objectspace/trace_object_allocations_spec.rb
index 3100511dc9..612430e067 100644
--- a/spec/ruby/library/objectspace/trace_object_allocations_spec.rb
+++ b/spec/ruby/library/objectspace/trace_object_allocations_spec.rb
@@ -128,4 +128,22 @@ describe "ObjectSpace.trace_object_allocations" do
ObjectSpace.trace_object_allocations_stop
end
end
+
+ it "returns nil for class_path, generation, method_id, sourcefile, and sourceline for immutable objects" do
+ ObjectSpace.trace_object_allocations_start
+ begin
+ one = nil
+ two = 42
+ three = :foo
+ [one, two, three].each do |i|
+ ObjectSpace.allocation_class_path(i).should == nil
+ ObjectSpace.allocation_generation(i).should == nil
+ ObjectSpace.allocation_method_id(i).should == nil
+ ObjectSpace.allocation_sourcefile(i).should == nil
+ ObjectSpace.allocation_sourceline(i).should == nil
+ end
+ ensure
+ ObjectSpace.trace_object_allocations_stop
+ end
+ end
end
diff --git a/spec/ruby/library/objectspace/trace_spec.rb b/spec/ruby/library/objectspace/trace_spec.rb
new file mode 100644
index 0000000000..532c282ce4
--- /dev/null
+++ b/spec/ruby/library/objectspace/trace_spec.rb
@@ -0,0 +1,15 @@
+require_relative '../../spec_helper'
+
+ruby_version_is "3.1" do
+ describe 'require "objspace/trace"' do
+ it "shows object allocation sites" do
+ file = fixture(__FILE__ , "trace.rb")
+ ruby_exe(file, args: "2>&1").lines(chomp: true).should == [
+ "objspace/trace is enabled",
+ "\"foo\" @ #{file}:3",
+ "\"bar\" @ #{file}:4",
+ "42"
+ ]
+ end
+ end
+end
diff --git a/spec/ruby/library/openssl/config/freeze_spec.rb b/spec/ruby/library/openssl/config/freeze_spec.rb
deleted file mode 100644
index c814341b86..0000000000
--- a/spec/ruby/library/openssl/config/freeze_spec.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-require_relative '../../../spec_helper'
-require_relative '../shared/constants'
-
-require 'openssl'
-
-version_is(OpenSSL::VERSION, ""..."2.2") do
- describe "OpenSSL::Config#freeze" do
- it "needs to be reviewed for completeness"
-
- it "freezes" do
- c = OpenSSL::Config.new
- -> {
- c['foo'] = [ ['key', 'value'] ]
- }.should_not raise_error
- c.freeze
- c.frozen?.should be_true
- -> {
- c['foo'] = [ ['key', 'value'] ]
- }.should raise_error(TypeError)
- end
- end
-end
diff --git a/spec/ruby/library/openssl/digest/append_spec.rb b/spec/ruby/library/openssl/digest/append_spec.rb
new file mode 100644
index 0000000000..08802b7253
--- /dev/null
+++ b/spec/ruby/library/openssl/digest/append_spec.rb
@@ -0,0 +1,6 @@
+require_relative '../../../spec_helper'
+require_relative 'shared/update'
+
+describe "OpenSSL::Digest#<<" do
+ it_behaves_like :openssl_digest_update, :<<
+end
diff --git a/spec/ruby/library/openssl/digest/block_length_spec.rb b/spec/ruby/library/openssl/digest/block_length_spec.rb
new file mode 100644
index 0000000000..444ed9d20d
--- /dev/null
+++ b/spec/ruby/library/openssl/digest/block_length_spec.rb
@@ -0,0 +1,44 @@
+require_relative '../../../spec_helper'
+require_relative '../../../library/digest/sha1/shared/constants'
+require_relative '../../../library/digest/sha256/shared/constants'
+require_relative '../../../library/digest/sha384/shared/constants'
+require_relative '../../../library/digest/sha512/shared/constants'
+require 'openssl'
+
+describe "OpenSSL::Digest#block_length" do
+ context "when the digest object is created via a name argument" do
+ it "returns a SHA1 block length" do
+ OpenSSL::Digest.new('sha1').block_length.should == SHA1Constants::BlockLength
+ end
+
+ it "returns a SHA256 block length" do
+ OpenSSL::Digest.new('sha256').block_length.should == SHA256Constants::BlockLength
+ end
+
+ it "returns a SHA384 block length" do
+ OpenSSL::Digest.new('sha384').block_length.should == SHA384Constants::BlockLength
+ end
+
+ it "returns a SHA512 block length" do
+ OpenSSL::Digest.new('sha512').block_length.should == SHA512Constants::BlockLength
+ end
+ end
+
+ context "when the digest object is created via a subclass" do
+ it "returns a SHA1 block length" do
+ OpenSSL::Digest::SHA1.new.block_length.should == SHA1Constants::BlockLength
+ end
+
+ it "returns a SHA256 block length" do
+ OpenSSL::Digest::SHA256.new.block_length.should == SHA256Constants::BlockLength
+ end
+
+ it "returns a SHA384 block length" do
+ OpenSSL::Digest::SHA384.new.block_length.should == SHA384Constants::BlockLength
+ end
+
+ it "returns a SHA512 block length" do
+ OpenSSL::Digest::SHA512.new.block_length.should == SHA512Constants::BlockLength
+ end
+ end
+end
diff --git a/spec/ruby/library/openssl/digest/digest_length_spec.rb b/spec/ruby/library/openssl/digest/digest_length_spec.rb
new file mode 100644
index 0000000000..37d1cba9a7
--- /dev/null
+++ b/spec/ruby/library/openssl/digest/digest_length_spec.rb
@@ -0,0 +1,44 @@
+require_relative '../../../spec_helper'
+require_relative '../../../library/digest/sha1/shared/constants'
+require_relative '../../../library/digest/sha256/shared/constants'
+require_relative '../../../library/digest/sha384/shared/constants'
+require_relative '../../../library/digest/sha512/shared/constants'
+require 'openssl'
+
+describe "OpenSSL::Digest#digest_length" do
+ context "when the digest object is created via a name argument" do
+ it "returns a SHA1 digest length" do
+ OpenSSL::Digest.new('sha1').digest_length.should == SHA1Constants::DigestLength
+ end
+
+ it "returns a SHA256 digest length" do
+ OpenSSL::Digest.new('sha256').digest_length.should == SHA256Constants::DigestLength
+ end
+
+ it "returns a SHA384 digest length" do
+ OpenSSL::Digest.new('sha384').digest_length.should == SHA384Constants::DigestLength
+ end
+
+ it "returns a SHA512 digest length" do
+ OpenSSL::Digest.new('sha512').digest_length.should == SHA512Constants::DigestLength
+ end
+ end
+
+ context "when the digest object is created via a subclass" do
+ it "returns a SHA1 digest length" do
+ OpenSSL::Digest::SHA1.new.digest_length.should == SHA1Constants::DigestLength
+ end
+
+ it "returns a SHA256 digest length" do
+ OpenSSL::Digest::SHA256.new.digest_length.should == SHA256Constants::DigestLength
+ end
+
+ it "returns a SHA384 digest length" do
+ OpenSSL::Digest::SHA384.new.digest_length.should == SHA384Constants::DigestLength
+ end
+
+ it "returns a SHA512 digest length" do
+ OpenSSL::Digest::SHA512.new.digest_length.should == SHA512Constants::DigestLength
+ end
+ end
+end
diff --git a/spec/ruby/library/openssl/digest/digest_spec.rb b/spec/ruby/library/openssl/digest/digest_spec.rb
new file mode 100644
index 0000000000..cf27d01b6d
--- /dev/null
+++ b/spec/ruby/library/openssl/digest/digest_spec.rb
@@ -0,0 +1,62 @@
+require_relative '../../../spec_helper'
+require_relative '../../../library/digest/sha1/shared/constants'
+require_relative '../../../library/digest/sha256/shared/constants'
+require_relative '../../../library/digest/sha384/shared/constants'
+require_relative '../../../library/digest/sha512/shared/constants'
+require 'openssl'
+
+describe "OpenSSL::Digest class methods" do
+ describe ".digest" do
+ it "returns a SHA1 digest" do
+ OpenSSL::Digest.digest('sha1', SHA1Constants::Contents).should == SHA1Constants::Digest
+ end
+
+ it "returns a SHA256 digest" do
+ OpenSSL::Digest.digest('sha256', SHA256Constants::Contents).should == SHA256Constants::Digest
+ end
+
+ it "returns a SHA384 digest" do
+ OpenSSL::Digest.digest('sha384', SHA384Constants::Contents).should == SHA384Constants::Digest
+ end
+
+ it "returns a SHA512 digest" do
+ OpenSSL::Digest.digest('sha512', SHA512Constants::Contents).should == SHA512Constants::Digest
+ end
+ end
+
+ describe ".hexdigest" do
+ it "returns a SHA1 hexdigest" do
+ OpenSSL::Digest.hexdigest('sha1', SHA1Constants::Contents).should == SHA1Constants::Hexdigest
+ end
+
+ it "returns a SHA256 hexdigest" do
+ OpenSSL::Digest.hexdigest('sha256', SHA256Constants::Contents).should == SHA256Constants::Hexdigest
+ end
+
+ it "returns a SHA384 hexdigest" do
+ OpenSSL::Digest.hexdigest('sha384', SHA384Constants::Contents).should == SHA384Constants::Hexdigest
+ end
+
+ it "returns a SHA512 hexdigest" do
+ OpenSSL::Digest.hexdigest('sha512', SHA512Constants::Contents).should == SHA512Constants::Hexdigest
+ end
+ end
+
+ describe ".base64digest" do
+ it "returns a SHA1 base64digest" do
+ OpenSSL::Digest.base64digest('sha1', SHA1Constants::Contents).should == SHA1Constants::Base64digest
+ end
+
+ it "returns a SHA256 base64digest" do
+ OpenSSL::Digest.base64digest('sha256', SHA256Constants::Contents).should == SHA256Constants::Base64digest
+ end
+
+ it "returns a SHA384 base64digest" do
+ OpenSSL::Digest.base64digest('sha384', SHA384Constants::Contents).should == SHA384Constants::Base64digest
+ end
+
+ it "returns a SHA512 base64digest" do
+ OpenSSL::Digest.base64digest('sha512', SHA512Constants::Contents).should == SHA512Constants::Base64digest
+ end
+ end
+end
diff --git a/spec/ruby/library/openssl/digest/initialize_spec.rb b/spec/ruby/library/openssl/digest/initialize_spec.rb
new file mode 100644
index 0000000000..1cd0409c4d
--- /dev/null
+++ b/spec/ruby/library/openssl/digest/initialize_spec.rb
@@ -0,0 +1,141 @@
+require_relative '../../../spec_helper'
+require_relative '../../../library/digest/sha1/shared/constants'
+require_relative '../../../library/digest/sha256/shared/constants'
+require_relative '../../../library/digest/sha384/shared/constants'
+require_relative '../../../library/digest/sha512/shared/constants'
+require 'openssl'
+
+describe "OpenSSL::Digest#initialize" do
+ describe "can be called with a digest name" do
+ it "returns a SHA1 object" do
+ OpenSSL::Digest.new("sha1").name.should == "SHA1"
+ end
+
+ it "returns a SHA256 object" do
+ OpenSSL::Digest.new("sha256").name.should == "SHA256"
+ end
+
+ it "returns a SHA384 object" do
+ OpenSSL::Digest.new("sha384").name.should == "SHA384"
+ end
+
+ it "returns a SHA512 object" do
+ OpenSSL::Digest.new("sha512").name.should == "SHA512"
+ end
+
+ it "throws an error when called with an unknown digest" do
+ -> { OpenSSL::Digest.new("wd40") }.should raise_error(RuntimeError, /Unsupported digest algorithm \(wd40\)/)
+ end
+
+ it "cannot be called with a symbol" do
+ -> { OpenSSL::Digest.new(:SHA1) }.should raise_error(TypeError, /wrong argument type Symbol/)
+ end
+
+ it "does not call #to_str on the argument" do
+ name = mock("digest name")
+ name.should_not_receive(:to_str)
+ -> { OpenSSL::Digest.new(name) }.should raise_error(TypeError, /wrong argument type/)
+ end
+ end
+
+ describe "can be called with a digest object" do
+ it "returns a SHA1 object" do
+ OpenSSL::Digest.new(OpenSSL::Digest::SHA1.new).name.should == "SHA1"
+ end
+
+ it "returns a SHA256 object" do
+ OpenSSL::Digest.new(OpenSSL::Digest::SHA256.new).name.should == "SHA256"
+ end
+
+ it "returns a SHA384 object" do
+ OpenSSL::Digest.new(OpenSSL::Digest::SHA384.new).name.should == "SHA384"
+ end
+
+ it "returns a SHA512 object" do
+ OpenSSL::Digest.new(OpenSSL::Digest::SHA512.new).name.should == "SHA512"
+ end
+
+ it "ignores the state of the digest object" do
+ sha1 = OpenSSL::Digest.new('sha1', SHA1Constants::Contents)
+ OpenSSL::Digest.new(sha1).digest.should == SHA1Constants::BlankDigest
+ end
+ end
+
+ it "cannot be called with a digest class" do
+ -> { OpenSSL::Digest.new(OpenSSL::Digest::SHA1) }.should raise_error(TypeError, /wrong argument type Class/)
+ end
+
+ context "when called without an initial String argument" do
+ it "returns a SHA1 digest" do
+ OpenSSL::Digest.new("sha1").digest.should == SHA1Constants::BlankDigest
+ end
+
+ it "returns a SHA256 digest" do
+ OpenSSL::Digest.new("sha256").digest.should == SHA256Constants::BlankDigest
+ end
+
+ it "returns a SHA384 digest" do
+ OpenSSL::Digest.new("sha384").digest.should == SHA384Constants::BlankDigest
+ end
+
+ it "returns a SHA512 digest" do
+ OpenSSL::Digest.new("sha512").digest.should == SHA512Constants::BlankDigest
+ end
+ end
+
+ context "when called with an initial String argument" do
+ it "returns a SHA1 digest of that argument" do
+ OpenSSL::Digest.new("sha1", SHA1Constants::Contents).digest.should == SHA1Constants::Digest
+ end
+
+ it "returns a SHA256 digest of that argument" do
+ OpenSSL::Digest.new("sha256", SHA256Constants::Contents).digest.should == SHA256Constants::Digest
+ end
+
+ it "returns a SHA384 digest of that argument" do
+ OpenSSL::Digest.new("sha384", SHA384Constants::Contents).digest.should == SHA384Constants::Digest
+ end
+
+ it "returns a SHA512 digest of that argument" do
+ OpenSSL::Digest.new("sha512", SHA512Constants::Contents).digest.should == SHA512Constants::Digest
+ end
+ end
+
+ context "can be called on subclasses" do
+ describe "can be called without an initial String argument on subclasses" do
+ it "returns a SHA1 digest" do
+ OpenSSL::Digest::SHA1.new.digest.should == SHA1Constants::BlankDigest
+ end
+
+ it "returns a SHA256 digest" do
+ OpenSSL::Digest::SHA256.new.digest.should == SHA256Constants::BlankDigest
+ end
+
+ it "returns a SHA384 digest" do
+ OpenSSL::Digest::SHA384.new.digest.should == SHA384Constants::BlankDigest
+ end
+
+ it "returns a SHA512 digest" do
+ OpenSSL::Digest::SHA512.new.digest.should == SHA512Constants::BlankDigest
+ end
+ end
+
+ describe "can be called with an initial String argument on subclasses" do
+ it "returns a SHA1 digest" do
+ OpenSSL::Digest::SHA1.new(SHA1Constants::Contents).digest.should == SHA1Constants::Digest
+ end
+
+ it "returns a SHA256 digest" do
+ OpenSSL::Digest::SHA256.new(SHA256Constants::Contents).digest.should == SHA256Constants::Digest
+ end
+
+ it "returns a SHA384 digest" do
+ OpenSSL::Digest::SHA384.new(SHA384Constants::Contents).digest.should == SHA384Constants::Digest
+ end
+
+ it "returns a SHA512 digest" do
+ OpenSSL::Digest::SHA512.new(SHA512Constants::Contents).digest.should == SHA512Constants::Digest
+ end
+ end
+ end
+end
diff --git a/spec/ruby/library/openssl/digest/name_spec.rb b/spec/ruby/library/openssl/digest/name_spec.rb
new file mode 100644
index 0000000000..b379f35c1c
--- /dev/null
+++ b/spec/ruby/library/openssl/digest/name_spec.rb
@@ -0,0 +1,16 @@
+require_relative '../../../spec_helper'
+require 'openssl'
+
+describe "OpenSSL::Digest#name" do
+ it "returns the name of digest" do
+ OpenSSL::Digest.new('SHA1').name.should == 'SHA1'
+ end
+
+ it "converts the name to the internal representation of OpenSSL" do
+ OpenSSL::Digest.new('sha1').name.should == 'SHA1'
+ end
+
+ it "works on subclasses too" do
+ OpenSSL::Digest::SHA1.new.name.should == 'SHA1'
+ end
+end
diff --git a/spec/ruby/library/openssl/digest/reset_spec.rb b/spec/ruby/library/openssl/digest/reset_spec.rb
new file mode 100644
index 0000000000..c19bf46633
--- /dev/null
+++ b/spec/ruby/library/openssl/digest/reset_spec.rb
@@ -0,0 +1,36 @@
+require_relative '../../../spec_helper'
+require_relative '../../../library/digest/sha1/shared/constants'
+require_relative '../../../library/digest/sha256/shared/constants'
+require_relative '../../../library/digest/sha384/shared/constants'
+require_relative '../../../library/digest/sha512/shared/constants'
+require 'openssl'
+
+describe "OpenSSL::Digest#reset" do
+ it "works for a SHA1 digest" do
+ digest = OpenSSL::Digest.new('sha1', SHA1Constants::Contents)
+ digest.reset
+ digest.update(SHA1Constants::Contents)
+ digest.digest.should == SHA1Constants::Digest
+ end
+
+ it "works for a SHA256 digest" do
+ digest = OpenSSL::Digest.new('sha256', SHA256Constants::Contents)
+ digest.reset
+ digest.update(SHA256Constants::Contents)
+ digest.digest.should == SHA256Constants::Digest
+ end
+
+ it "works for a SHA384 digest" do
+ digest = OpenSSL::Digest.new('sha384', SHA384Constants::Contents)
+ digest.reset
+ digest.update(SHA384Constants::Contents)
+ digest.digest.should == SHA384Constants::Digest
+ end
+
+ it "works for a SHA512 digest" do
+ digest = OpenSSL::Digest.new('sha512', SHA512Constants::Contents)
+ digest.reset
+ digest.update(SHA512Constants::Contents)
+ digest.digest.should == SHA512Constants::Digest
+ end
+end
diff --git a/spec/ruby/library/openssl/digest/shared/update.rb b/spec/ruby/library/openssl/digest/shared/update.rb
new file mode 100644
index 0000000000..e5ff9dcb16
--- /dev/null
+++ b/spec/ruby/library/openssl/digest/shared/update.rb
@@ -0,0 +1,123 @@
+require_relative '../../../../library/digest/sha1/shared/constants'
+require_relative '../../../../library/digest/sha256/shared/constants'
+require_relative '../../../../library/digest/sha384/shared/constants'
+require_relative '../../../../library/digest/sha512/shared/constants'
+require 'openssl'
+
+describe :openssl_digest_update, shared: true do
+ context "when given input as a single string" do
+ it "returns a SHA1 digest" do
+ digest = OpenSSL::Digest.new('sha1')
+ digest.send(@method, SHA1Constants::Contents)
+ digest.digest.should == SHA1Constants::Digest
+ end
+
+ it "returns a SHA256 digest" do
+ digest = OpenSSL::Digest.new('sha256')
+ digest.send(@method, SHA256Constants::Contents)
+ digest.digest.should == SHA256Constants::Digest
+ end
+
+ it "returns a SHA384 digest" do
+ digest = OpenSSL::Digest.new('sha384')
+ digest.send(@method, SHA384Constants::Contents)
+ digest.digest.should == SHA384Constants::Digest
+ end
+
+ it "returns a SHA512 digest" do
+ digest = OpenSSL::Digest.new('sha512')
+ digest.send(@method, SHA512Constants::Contents)
+ digest.digest.should == SHA512Constants::Digest
+ end
+ end
+
+ context "when given input as multiple smaller substrings" do
+ it "returns a SHA1 digest" do
+ digest = OpenSSL::Digest.new('sha1')
+ SHA1Constants::Contents.each_char { |b| digest.send(@method, b) }
+ digest.digest.should == SHA1Constants::Digest
+ end
+
+ it "returns a SHA256 digest" do
+ digest = OpenSSL::Digest.new('sha256')
+ SHA256Constants::Contents.each_char { |b| digest.send(@method, b) }
+ digest.digest.should == SHA256Constants::Digest
+ end
+
+ it "returns a SHA384 digest" do
+ digest = OpenSSL::Digest.new('sha384')
+ SHA384Constants::Contents.each_char { |b| digest.send(@method, b) }
+ digest.digest.should == SHA384Constants::Digest
+ end
+
+ it "returns a SHA512 digest" do
+ digest = OpenSSL::Digest.new('sha512')
+ SHA512Constants::Contents.each_char { |b| digest.send(@method, b) }
+ digest.digest.should == SHA512Constants::Digest
+ end
+ end
+
+ context "when input is not a String and responds to #to_str" do
+ it "returns a SHA1 digest" do
+ str = mock('str')
+ str.should_receive(:to_str).and_return(SHA1Constants::Contents)
+ digest = OpenSSL::Digest.new('sha1')
+ digest.send(@method, str)
+ digest.digest.should == SHA1Constants::Digest
+ end
+
+ it "returns a SHA256 digest" do
+ str = mock('str')
+ str.should_receive(:to_str).and_return(SHA256Constants::Contents)
+ digest = OpenSSL::Digest.new('sha256')
+ digest.send(@method, str)
+ digest.digest.should == SHA256Constants::Digest
+ end
+
+ it "returns a SHA384 digest" do
+ str = mock('str')
+ str.should_receive(:to_str).and_return(SHA384Constants::Contents)
+ digest = OpenSSL::Digest.new('sha384')
+ digest.send(@method, str)
+ digest.digest.should == SHA384Constants::Digest
+ end
+
+ it "returns a SHA512 digest" do
+ str = mock('str')
+ str.should_receive(:to_str).and_return(SHA512Constants::Contents)
+ digest = OpenSSL::Digest.new('sha512')
+ digest.send(@method, str)
+ digest.digest.should == SHA512Constants::Digest
+ end
+ end
+
+ context "when input is not a String and does not respond to #to_str" do
+ it "raises a TypeError with SHA1" do
+ digest = OpenSSL::Digest.new('sha1')
+ -> {
+ digest.send(@method, Object.new)
+ }.should raise_error(TypeError, 'no implicit conversion of Object into String')
+ end
+
+ it "raises a TypeError with SHA256" do
+ digest = OpenSSL::Digest.new('sha256')
+ -> {
+ digest.send(@method, Object.new)
+ }.should raise_error(TypeError, 'no implicit conversion of Object into String')
+ end
+
+ it "raises a TypeError with SHA384" do
+ digest = OpenSSL::Digest.new('sha384')
+ -> {
+ digest.send(@method, Object.new)
+ }.should raise_error(TypeError, 'no implicit conversion of Object into String')
+ end
+
+ it "raises a TypeError with SHA512" do
+ digest = OpenSSL::Digest.new('sha512')
+ -> {
+ digest.send(@method, Object.new)
+ }.should raise_error(TypeError, 'no implicit conversion of Object into String')
+ end
+ end
+end
diff --git a/spec/ruby/library/openssl/digest/update_spec.rb b/spec/ruby/library/openssl/digest/update_spec.rb
new file mode 100644
index 0000000000..3a90b06c6b
--- /dev/null
+++ b/spec/ruby/library/openssl/digest/update_spec.rb
@@ -0,0 +1,6 @@
+require_relative '../../../spec_helper'
+require_relative 'shared/update'
+
+describe "OpenSSL::Digest#update" do
+ it_behaves_like :openssl_digest_update, :update
+end
diff --git a/spec/ruby/library/openssl/digest_spec.rb b/spec/ruby/library/openssl/digest_spec.rb
deleted file mode 100644
index b8e82d073f..0000000000
--- a/spec/ruby/library/openssl/digest_spec.rb
+++ /dev/null
@@ -1,63 +0,0 @@
-require_relative '../../spec_helper'
-require_relative '../../library/digest/sha1/shared/constants'
-require_relative '../../library/digest/sha256/shared/constants'
-require_relative '../../library/digest/sha384/shared/constants'
-require_relative '../../library/digest/sha512/shared/constants'
-require 'openssl'
-
-describe "OpenSSL::Digest" do
-
- describe ".digest" do
- it "returns a SHA1 digest" do
- OpenSSL::Digest.digest('sha1', SHA1Constants::Contents).should == SHA1Constants::Digest
- end
-
- it "returns a SHA256 digest" do
- OpenSSL::Digest.digest('sha256', SHA256Constants::Contents).should == SHA256Constants::Digest
- end
-
- it "returns a SHA384 digest" do
- OpenSSL::Digest.digest('sha384', SHA384Constants::Contents).should == SHA384Constants::Digest
- end
-
- it "returns a SHA512 digest" do
- OpenSSL::Digest.digest('sha512', SHA512Constants::Contents).should == SHA512Constants::Digest
- end
- end
-
- describe ".hexdigest" do
- it "returns a SHA1 hexdigest" do
- OpenSSL::Digest.hexdigest('sha1', SHA1Constants::Contents).should == SHA1Constants::Hexdigest
- end
-
- it "returns a SHA256 hexdigest" do
- OpenSSL::Digest.hexdigest('sha256', SHA256Constants::Contents).should == SHA256Constants::Hexdigest
- end
-
- it "returns a SHA384 hexdigest" do
- OpenSSL::Digest.hexdigest('sha384', SHA384Constants::Contents).should == SHA384Constants::Hexdigest
- end
-
- it "returns a SHA512 hexdigest" do
- OpenSSL::Digest.hexdigest('sha512', SHA512Constants::Contents).should == SHA512Constants::Hexdigest
- end
- end
-
- describe ".base64digest" do
- it "returns a SHA1 base64digest" do
- OpenSSL::Digest.base64digest('sha1', SHA1Constants::Contents).should == SHA1Constants::Base64digest
- end
-
- it "returns a SHA256 base64digest" do
- OpenSSL::Digest.base64digest('sha256', SHA256Constants::Contents).should == SHA256Constants::Base64digest
- end
-
- it "returns a SHA384 base64digest" do
- OpenSSL::Digest.base64digest('sha384', SHA384Constants::Contents).should == SHA384Constants::Base64digest
- end
-
- it "returns a SHA512 base64digest" do
- OpenSSL::Digest.base64digest('sha512', SHA512Constants::Contents).should == SHA512Constants::Base64digest
- end
- end
-end
diff --git a/spec/ruby/library/openssl/fixed_length_secure_compare_spec.rb b/spec/ruby/library/openssl/fixed_length_secure_compare_spec.rb
new file mode 100644
index 0000000000..5a2ca168b5
--- /dev/null
+++ b/spec/ruby/library/openssl/fixed_length_secure_compare_spec.rb
@@ -0,0 +1,42 @@
+require_relative '../../spec_helper'
+require 'openssl'
+
+describe "OpenSSL.fixed_length_secure_compare" do
+ it "returns true for two strings with the same content" do
+ input1 = "the quick brown fox jumps over the lazy dog"
+ input2 = "the quick brown fox jumps over the lazy dog"
+ OpenSSL.fixed_length_secure_compare(input1, input2).should be_true
+ end
+
+ it "returns false for two strings of equal size with different content" do
+ input1 = "the quick brown fox jumps over the lazy dog"
+ input2 = "the lazy dog jumps over the quick brown fox"
+ OpenSSL.fixed_length_secure_compare(input1, input2).should be_false
+ end
+
+ it "converts both arguments to strings using #to_str" do
+ input1 = mock("input1")
+ input1.should_receive(:to_str).and_return("the quick brown fox jumps over the lazy dog")
+ input2 = mock("input2")
+ input2.should_receive(:to_str).and_return("the quick brown fox jumps over the lazy dog")
+ OpenSSL.fixed_length_secure_compare(input1, input2).should be_true
+ end
+
+ it "does not accept arguments that are not string and cannot be coerced into strings" do
+ -> {
+ OpenSSL.fixed_length_secure_compare("input1", :input2)
+ }.should raise_error(TypeError, 'no implicit conversion of Symbol into String')
+
+ -> {
+ OpenSSL.fixed_length_secure_compare(Object.new, "input2")
+ }.should raise_error(TypeError, 'no implicit conversion of Object into String')
+ end
+
+ it "raises an ArgumentError for two strings of different size" do
+ input1 = "the quick brown fox jumps over the lazy dog"
+ input2 = "the quick brown fox"
+ -> {
+ OpenSSL.fixed_length_secure_compare(input1, input2)
+ }.should raise_error(ArgumentError, 'inputs must be of equal length')
+ end
+end
diff --git a/spec/ruby/library/openssl/kdf/pbkdf2_hmac_spec.rb b/spec/ruby/library/openssl/kdf/pbkdf2_hmac_spec.rb
new file mode 100644
index 0000000000..40f8597275
--- /dev/null
+++ b/spec/ruby/library/openssl/kdf/pbkdf2_hmac_spec.rb
@@ -0,0 +1,168 @@
+require_relative '../../../spec_helper'
+require 'openssl'
+
+describe "OpenSSL::KDF.pbkdf2_hmac" do
+ before :each do
+ @defaults = {
+ salt: "\x00".b * 16,
+ iterations: 20_000,
+ length: 16,
+ hash: "sha1"
+ }
+ end
+
+ it "creates the same value with the same input" do
+ key = OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults)
+ key.should == "!\x99+\xF0^\xD0\x8BM\x158\xC4\xAC\x9C\xF1\xF0\xE0".b
+ end
+
+ it "supports nullbytes embedded in the password" do
+ key = OpenSSL::KDF.pbkdf2_hmac("sec\x00ret".b, **@defaults)
+ key.should == "\xB9\x7F\xB0\xC2\th\xC8<\x86\xF3\x94Ij7\xEF\xF1".b
+ end
+
+ it "coerces the password into a String using #to_str" do
+ pass = mock("pass")
+ pass.should_receive(:to_str).and_return("secret")
+ key = OpenSSL::KDF.pbkdf2_hmac(pass, **@defaults)
+ key.should == "!\x99+\xF0^\xD0\x8BM\x158\xC4\xAC\x9C\xF1\xF0\xE0".b
+ end
+
+ it "coerces the salt into a String using #to_str" do
+ salt = mock("salt")
+ salt.should_receive(:to_str).and_return("\x00".b * 16)
+ key = OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, salt: salt)
+ key.should == "!\x99+\xF0^\xD0\x8BM\x158\xC4\xAC\x9C\xF1\xF0\xE0".b
+ end
+
+ it "coerces the iterations into an Integer using #to_int" do
+ iterations = mock("iterations")
+ iterations.should_receive(:to_int).and_return(20_000)
+ key = OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, iterations: iterations)
+ key.should == "!\x99+\xF0^\xD0\x8BM\x158\xC4\xAC\x9C\xF1\xF0\xE0".b
+ end
+
+ it "coerces the length into an Integer using #to_int" do
+ length = mock("length")
+ length.should_receive(:to_int).and_return(16)
+ key = OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, length: length)
+ key.should == "!\x99+\xF0^\xD0\x8BM\x158\xC4\xAC\x9C\xF1\xF0\xE0".b
+ end
+
+ it "accepts a OpenSSL::Digest object as hash" do
+ hash = OpenSSL::Digest.new("sha1")
+ key = OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, hash: hash)
+ key.should == "!\x99+\xF0^\xD0\x8BM\x158\xC4\xAC\x9C\xF1\xF0\xE0".b
+ end
+
+ it "accepts an empty password" do
+ key = OpenSSL::KDF.pbkdf2_hmac("", **@defaults)
+ key.should == "k\x9F-\xB1\xF7\x9A\v\xA1(C\xF9\x85!P\xEF\x8C".b
+ end
+
+ it "accepts an empty salt" do
+ key = OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, salt: "")
+ key.should == "\xD5f\xE5\xEA\xF91\x1D\xD3evD\xED\xDB\xE80\x80".b
+ end
+
+ it "accepts an empty length" do
+ key = OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, length: 0)
+ key.should.empty?
+ end
+
+ it "accepts an arbitrary length" do
+ key = OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, length: 19)
+ key.should == "!\x99+\xF0^\xD0\x8BM\x158\xC4\xAC\x9C\xF1\xF0\xE0\xCF\xBB\x7F".b
+ end
+
+ it "accepts any hash function known to OpenSSL" do
+ key = OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, hash: "sha512")
+ key.should == "N\x12}D\xCE\x99\xDBC\x8E\xEC\xAAr\xEA1\xDF\xFF".b
+ end
+
+ it "raises a TypeError when password is not a String and does not respond to #to_str" do
+ -> {
+ OpenSSL::KDF.pbkdf2_hmac(Object.new, **@defaults)
+ }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ end
+
+ it "raises a TypeError when salt is not a String and does not respond to #to_str" do
+ -> {
+ OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, salt: Object.new)
+ }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ end
+
+ it "raises a TypeError when iterations is not an Integer and does not respond to #to_int" do
+ -> {
+ OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, iterations: Object.new)
+ }.should raise_error(TypeError, "no implicit conversion of Object into Integer")
+ end
+
+ it "raises a TypeError when length is not an Integer and does not respond to #to_int" do
+ -> {
+ OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, length: Object.new)
+ }.should raise_error(TypeError, "no implicit conversion of Object into Integer")
+ end
+
+ it "raises a TypeError when hash is neither a String nor an OpenSSL::Digest" do
+ -> {
+ OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, hash: Object.new)
+ }.should raise_error(TypeError, "wrong argument type Object (expected OpenSSL/Digest)")
+ end
+
+ it "raises a TypeError when hash is neither a String nor an OpenSSL::Digest, it does not try to call #to_str" do
+ hash = mock("hash")
+ hash.should_not_receive(:to_str)
+ -> {
+ OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, hash: hash)
+ }.should raise_error(TypeError, "wrong argument type MockObject (expected OpenSSL/Digest)")
+ end
+
+ it "raises a RuntimeError for unknown digest algorithms" do
+ -> {
+ OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, hash: "wd40")
+ }.should raise_error(RuntimeError, /Unsupported digest algorithm \(wd40\)/)
+ end
+
+ it "treats salt as a required keyword" do
+ -> {
+ OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults.except(:salt))
+ }.should raise_error(ArgumentError, 'missing keyword: :salt')
+ end
+
+ it "treats iterations as a required keyword" do
+ -> {
+ OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults.except(:iterations))
+ }.should raise_error(ArgumentError, 'missing keyword: :iterations')
+ end
+
+ it "treats length as a required keyword" do
+ -> {
+ OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults.except(:length))
+ }.should raise_error(ArgumentError, 'missing keyword: :length')
+ end
+
+ it "treats hash as a required keyword" do
+ -> {
+ OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults.except(:hash))
+ }.should raise_error(ArgumentError, 'missing keyword: :hash')
+ end
+
+ it "treats all keywords as required" do
+ -> {
+ OpenSSL::KDF.pbkdf2_hmac("secret")
+ }.should raise_error(ArgumentError, 'missing keywords: :salt, :iterations, :length, :hash')
+ end
+
+ guard -> { OpenSSL::OPENSSL_VERSION_NUMBER >= 0x30000000 } do
+ it "raises an OpenSSL::KDF::KDFError for 0 or less iterations" do
+ -> {
+ OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, iterations: 0)
+ }.should raise_error(OpenSSL::KDF::KDFError, "PKCS5_PBKDF2_HMAC: invalid iteration count")
+
+ -> {
+ OpenSSL::KDF.pbkdf2_hmac("secret", **@defaults, iterations: -1)
+ }.should raise_error(OpenSSL::KDF::KDFError, /PKCS5_PBKDF2_HMAC/)
+ end
+ end
+end
diff --git a/spec/ruby/library/openssl/kdf/scrypt_spec.rb b/spec/ruby/library/openssl/kdf/scrypt_spec.rb
new file mode 100644
index 0000000000..5dc9f2f281
--- /dev/null
+++ b/spec/ruby/library/openssl/kdf/scrypt_spec.rb
@@ -0,0 +1,209 @@
+require_relative '../../../spec_helper'
+require 'openssl'
+
+guard -> { OpenSSL::KDF.respond_to?(:scrypt) } do
+ describe "OpenSSL::KDF.scrypt" do
+ before :each do
+ @defaults = {
+ salt: "\x00".b * 16,
+ N: 2**14,
+ r: 8,
+ p: 1,
+ length: 32
+ }
+ end
+
+ it "creates the same value with the same input" do
+ key = OpenSSL::KDF.scrypt("secret", **@defaults)
+ key.should == "h\xB2k\xDF]\xDA\xE1.-(\xCF\xAC\x91D\x8F\xC2a\x9C\x9D\x17}\xF2\x84T\xD4)\xC2>\xFE\x93\xE3\xF4".b
+ end
+
+ it "supports nullbytes embedded into the password" do
+ key = OpenSSL::KDF.scrypt("sec\x00ret".b, **@defaults)
+ key.should == "\xF9\xA4\xA0\xF1p\xF4\xF0\xCAT\xB4v\xEB\r7\x88N\xF7\x15]Ns\xFCwt4a\xC9\xC6\xA7\x13\x81&".b
+ end
+
+ it "coerces the password into a String using #to_str" do
+ pass = mock("pass")
+ pass.should_receive(:to_str).and_return("secret")
+ key = OpenSSL::KDF.scrypt(pass, **@defaults)
+ key.should == "h\xB2k\xDF]\xDA\xE1.-(\xCF\xAC\x91D\x8F\xC2a\x9C\x9D\x17}\xF2\x84T\xD4)\xC2>\xFE\x93\xE3\xF4".b
+ end
+
+ it "coerces the salt into a String using #to_str" do
+ salt = mock("salt")
+ salt.should_receive(:to_str).and_return("\x00".b * 16)
+ key = OpenSSL::KDF.scrypt("secret", **@defaults, salt: salt)
+ key.should == "h\xB2k\xDF]\xDA\xE1.-(\xCF\xAC\x91D\x8F\xC2a\x9C\x9D\x17}\xF2\x84T\xD4)\xC2>\xFE\x93\xE3\xF4".b
+ end
+
+ it "coerces the N into an Integer using #to_int" do
+ n = mock("N")
+ n.should_receive(:to_int).and_return(2**14)
+ key = OpenSSL::KDF.scrypt("secret", **@defaults, N: n)
+ key.should == "h\xB2k\xDF]\xDA\xE1.-(\xCF\xAC\x91D\x8F\xC2a\x9C\x9D\x17}\xF2\x84T\xD4)\xC2>\xFE\x93\xE3\xF4".b
+ end
+
+ it "coerces the r into an Integer using #to_int" do
+ r = mock("r")
+ r.should_receive(:to_int).and_return(8)
+ key = OpenSSL::KDF.scrypt("secret", **@defaults, r: r)
+ key.should == "h\xB2k\xDF]\xDA\xE1.-(\xCF\xAC\x91D\x8F\xC2a\x9C\x9D\x17}\xF2\x84T\xD4)\xC2>\xFE\x93\xE3\xF4".b
+ end
+
+ it "coerces the p into an Integer using #to_int" do
+ p = mock("p")
+ p.should_receive(:to_int).and_return(1)
+ key = OpenSSL::KDF.scrypt("secret", **@defaults, p: p)
+ key.should == "h\xB2k\xDF]\xDA\xE1.-(\xCF\xAC\x91D\x8F\xC2a\x9C\x9D\x17}\xF2\x84T\xD4)\xC2>\xFE\x93\xE3\xF4".b
+ end
+
+ it "coerces the length into an Integer using #to_int" do
+ length = mock("length")
+ length.should_receive(:to_int).and_return(32)
+ key = OpenSSL::KDF.scrypt("secret", **@defaults, length: length)
+ key.should == "h\xB2k\xDF]\xDA\xE1.-(\xCF\xAC\x91D\x8F\xC2a\x9C\x9D\x17}\xF2\x84T\xD4)\xC2>\xFE\x93\xE3\xF4".b
+ end
+
+ it "accepts an empty password" do
+ key = OpenSSL::KDF.scrypt("", **@defaults)
+ key.should == "\xAA\xFC\xF5^E\x94v\xFFk\xE6\xF0vR\xE7\x13\xA7\xF5\x15'\x9A\xE4C\x9Dn\x18F_E\xD2\v\e\xB3".b
+ end
+
+ it "accepts an empty salt" do
+ key = OpenSSL::KDF.scrypt("secret", **@defaults, salt: "")
+ key.should == "\x96\xACDl\xCB3/aN\xB0F\x8A#\xD7\x92\xD2O\x1E\v\xBB\xCE\xC0\xAA\xB9\x0F]\xB09\xEA8\xDD\e".b
+ end
+
+ it "accepts a zero length" do
+ key = OpenSSL::KDF.scrypt("secret", **@defaults, length: 0)
+ key.should.empty?
+ end
+
+ it "accepts an arbitrary length" do
+ key = OpenSSL::KDF.scrypt("secret", **@defaults, length: 19)
+ key.should == "h\xB2k\xDF]\xDA\xE1.-(\xCF\xAC\x91D\x8F\xC2a\x9C\x9D".b
+ end
+
+ it "raises a TypeError when password is not a String and does not respond to #to_str" do
+ -> {
+ OpenSSL::KDF.scrypt(Object.new, **@defaults)
+ }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ end
+
+ it "raises a TypeError when salt is not a String and does not respond to #to_str" do
+ -> {
+ OpenSSL::KDF.scrypt("secret", **@defaults, salt: Object.new)
+ }.should raise_error(TypeError, "no implicit conversion of Object into String")
+ end
+
+ it "raises a TypeError when N is not an Integer and does not respond to #to_int" do
+ -> {
+ OpenSSL::KDF.scrypt("secret", **@defaults, N: Object.new)
+ }.should raise_error(TypeError, "no implicit conversion of Object into Integer")
+ end
+
+ it "raises a TypeError when r is not an Integer and does not respond to #to_int" do
+ -> {
+ OpenSSL::KDF.scrypt("secret", **@defaults, r: Object.new)
+ }.should raise_error(TypeError, "no implicit conversion of Object into Integer")
+ end
+
+ it "raises a TypeError when p is not an Integer and does not respond to #to_int" do
+ -> {
+ OpenSSL::KDF.scrypt("secret", **@defaults, p: Object.new)
+ }.should raise_error(TypeError, "no implicit conversion of Object into Integer")
+ end
+
+ it "raises a TypeError when length is not an Integer and does not respond to #to_int" do
+ -> {
+ OpenSSL::KDF.scrypt("secret", **@defaults, length: Object.new)
+ }.should raise_error(TypeError, "no implicit conversion of Object into Integer")
+ end
+
+ it "treats salt as a required keyword" do
+ -> {
+ OpenSSL::KDF.scrypt("secret", **@defaults.except(:salt))
+ }.should raise_error(ArgumentError, 'missing keyword: :salt')
+ end
+
+ it "treats N as a required keyword" do
+ -> {
+ OpenSSL::KDF.scrypt("secret", **@defaults.except(:N))
+ }.should raise_error(ArgumentError, 'missing keyword: :N')
+ end
+
+ it "treats r as a required keyword" do
+ -> {
+ OpenSSL::KDF.scrypt("secret", **@defaults.except(:r))
+ }.should raise_error(ArgumentError, 'missing keyword: :r')
+ end
+
+ it "treats p as a required keyword" do
+ -> {
+ OpenSSL::KDF.scrypt("secret", **@defaults.except(:p))
+ }.should raise_error(ArgumentError, 'missing keyword: :p')
+ end
+
+ it "treats length as a required keyword" do
+ -> {
+ OpenSSL::KDF.scrypt("secret", **@defaults.except(:length))
+ }.should raise_error(ArgumentError, 'missing keyword: :length')
+ end
+
+ it "treats all keywords as required" do
+ -> {
+ OpenSSL::KDF.scrypt("secret")
+ }.should raise_error(ArgumentError, 'missing keywords: :salt, :N, :r, :p, :length')
+ end
+
+ it "requires N to be a power of 2" do
+ -> {
+ OpenSSL::KDF.scrypt("secret", **@defaults, N: 2**14 - 1)
+ }.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
+ end
+
+ it "requires N to be at least 2" do
+ key = OpenSSL::KDF.scrypt("secret", **@defaults, N: 2)
+ key.should == "\x06A$a\xA9!\xBE\x01\x85\xA7\x18\xBCEa\x82\xC5\xFEl\x93\xAB\xBD\xF7\x8B\x84\v\xFC\eN\xEBQ\xE6\xD2".b
+
+ -> {
+ OpenSSL::KDF.scrypt("secret", **@defaults, N: 1)
+ }.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
+
+ -> {
+ OpenSSL::KDF.scrypt("secret", **@defaults, N: 0)
+ }.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
+
+ -> {
+ OpenSSL::KDF.scrypt("secret", **@defaults, N: -1)
+ }.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
+ end
+
+ it "requires r to be positive" do
+ -> {
+ OpenSSL::KDF.scrypt("secret", **@defaults, r: 0)
+ }.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
+
+ -> {
+ OpenSSL::KDF.scrypt("secret", **@defaults, r: -1)
+ }.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
+ end
+
+ it "requires p to be positive" do
+ -> {
+ OpenSSL::KDF.scrypt("secret", **@defaults, p: 0)
+ }.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
+
+ -> {
+ OpenSSL::KDF.scrypt("secret", **@defaults, p: -1)
+ }.should raise_error(OpenSSL::KDF::KDFError, /EVP_PBE_scrypt/)
+ end
+
+ it "requires length to be not negative" do
+ -> {
+ OpenSSL::KDF.scrypt("secret", **@defaults, length: -1)
+ }.should raise_error(ArgumentError, "negative string size (or size too big)")
+ end
+ end
+end
diff --git a/spec/ruby/library/openssl/random/shared/random_bytes.rb b/spec/ruby/library/openssl/random/shared/random_bytes.rb
index 037f10d409..f97ccd9974 100644
--- a/spec/ruby/library/openssl/random/shared/random_bytes.rb
+++ b/spec/ruby/library/openssl/random/shared/random_bytes.rb
@@ -1,7 +1,7 @@
require_relative '../../../../spec_helper'
require 'openssl'
-describe :openssl_random_bytes, shared: true do |cmd|
+describe :openssl_random_bytes, shared: true do
it "generates a random binary string of specified length" do
(1..64).each do |idx|
bytes = OpenSSL::Random.send(@method, idx)
diff --git a/spec/ruby/library/openssl/secure_compare_spec.rb b/spec/ruby/library/openssl/secure_compare_spec.rb
new file mode 100644
index 0000000000..cec48e01e7
--- /dev/null
+++ b/spec/ruby/library/openssl/secure_compare_spec.rb
@@ -0,0 +1,38 @@
+require_relative '../../spec_helper'
+require 'openssl'
+
+describe "OpenSSL.secure_compare" do
+ it "returns true for two strings with the same content" do
+ input1 = "the quick brown fox jumps over the lazy dog"
+ input2 = "the quick brown fox jumps over the lazy dog"
+ OpenSSL.secure_compare(input1, input2).should be_true
+ end
+
+ it "returns false for two strings with different content" do
+ input1 = "the quick brown fox jumps over the lazy dog"
+ input2 = "the lazy dog jumps over the quick brown fox"
+ OpenSSL.secure_compare(input1, input2).should be_false
+ end
+
+ it "converts both arguments to strings using #to_str, but adds equality check for the original objects" do
+ input1 = mock("input1")
+ input1.should_receive(:to_str).and_return("the quick brown fox jumps over the lazy dog")
+ input2 = mock("input2")
+ input2.should_receive(:to_str).and_return("the quick brown fox jumps over the lazy dog")
+ OpenSSL.secure_compare(input1, input2).should be_false
+
+ input = mock("input")
+ input.should_receive(:to_str).twice.and_return("the quick brown fox jumps over the lazy dog")
+ OpenSSL.secure_compare(input, input).should be_true
+ end
+
+ it "does not accept arguments that are not string and cannot be coerced into strings" do
+ -> {
+ OpenSSL.secure_compare("input1", :input2)
+ }.should raise_error(TypeError, 'no implicit conversion of Symbol into String')
+
+ -> {
+ OpenSSL.secure_compare(Object.new, "input2")
+ }.should raise_error(TypeError, 'no implicit conversion of Object into String')
+ end
+end
diff --git a/spec/ruby/library/openssl/x509/store/verify_spec.rb b/spec/ruby/library/openssl/x509/store/verify_spec.rb
new file mode 100644
index 0000000000..6a6a53d992
--- /dev/null
+++ b/spec/ruby/library/openssl/x509/store/verify_spec.rb
@@ -0,0 +1,78 @@
+require_relative '../../../../spec_helper'
+require 'openssl'
+
+describe "OpenSSL::X509::Store#verify" do
+ it "returns true for valid certificate" do
+ key = OpenSSL::PKey::RSA.new 2048
+ cert = OpenSSL::X509::Certificate.new
+ cert.version = 2
+ cert.serial = 1
+ cert.subject = OpenSSL::X509::Name.parse "/DC=org/DC=truffleruby/CN=TruffleRuby CA"
+ cert.issuer = cert.subject
+ cert.public_key = key.public_key
+ cert.not_before = Time.now - 10
+ cert.not_after = cert.not_before + 365 * 24 * 60 * 60
+ cert.sign key, OpenSSL::Digest.new('SHA256')
+ store = OpenSSL::X509::Store.new
+ store.add_cert(cert)
+ [store.verify(cert), store.error, store.error_string].should == [true, 0, "ok"]
+ end
+
+ it "returns false for an expired certificate" do
+ key = OpenSSL::PKey::RSA.new 2048
+ cert = OpenSSL::X509::Certificate.new
+ cert.version = 2
+ cert.serial = 1
+ cert.subject = OpenSSL::X509::Name.parse "/DC=org/DC=truffleruby/CN=TruffleRuby CA"
+ cert.issuer = cert.subject
+ cert.public_key = key.public_key
+ cert.not_before = Time.now - 10
+ cert.not_after = Time.now - 5
+ cert.sign key, OpenSSL::Digest.new('SHA256')
+ store = OpenSSL::X509::Store.new
+ store.add_cert(cert)
+ store.verify(cert).should == false
+ end
+
+ it "returns false for an expired root certificate" do
+ root_key = OpenSSL::PKey::RSA.new 2048
+ root_cert = OpenSSL::X509::Certificate.new
+ root_cert.version = 2
+ root_cert.serial = 1
+ root_cert.subject = OpenSSL::X509::Name.parse "/DC=org/DC=truffleruby/CN=TruffleRuby CA"
+ root_cert.issuer = root_cert.subject
+ root_cert.public_key = root_key.public_key
+ root_cert.not_before = Time.now - 10
+ root_cert.not_after = Time.now - 5
+ ef = OpenSSL::X509::ExtensionFactory.new
+ ef.subject_certificate = root_cert
+ ef.issuer_certificate = root_cert
+ root_cert.add_extension(ef.create_extension("basicConstraints","CA:TRUE",true))
+ root_cert.add_extension(ef.create_extension("keyUsage","keyCertSign, cRLSign", true))
+ root_cert.add_extension(ef.create_extension("subjectKeyIdentifier","hash",false))
+ root_cert.add_extension(ef.create_extension("authorityKeyIdentifier","keyid:always",false))
+ root_cert.sign(root_key, OpenSSL::Digest.new('SHA256'))
+
+
+ key = OpenSSL::PKey::RSA.new 2048
+ cert = OpenSSL::X509::Certificate.new
+ cert.version = 2
+ cert.serial = 2
+ cert.subject = OpenSSL::X509::Name.parse "/DC=org/DC=truffleruby/CN=TruffleRuby certificate"
+ cert.issuer = root_cert.subject
+ cert.public_key = key.public_key
+ cert.not_before = Time.now
+ cert.not_after = cert.not_before + 1 * 365 * 24 * 60 * 60
+ ef = OpenSSL::X509::ExtensionFactory.new
+ ef.subject_certificate = cert
+ ef.issuer_certificate = root_cert
+ cert.add_extension(ef.create_extension("keyUsage","digitalSignature", true))
+ cert.add_extension(ef.create_extension("subjectKeyIdentifier","hash",false))
+ cert.sign(root_key, OpenSSL::Digest.new('SHA256'))
+
+ store = OpenSSL::X509::Store.new
+ store.add_cert(root_cert)
+ store.add_cert(cert)
+ store.verify(cert).should == false
+ end
+end
diff --git a/spec/ruby/library/openstruct/method_missing_spec.rb b/spec/ruby/library/openstruct/method_missing_spec.rb
index 212db015a9..89f83d07b3 100644
--- a/spec/ruby/library/openstruct/method_missing_spec.rb
+++ b/spec/ruby/library/openstruct/method_missing_spec.rb
@@ -17,10 +17,8 @@ describe "OpenStruct#method_missing when passed additional arguments" do
-> { os.test(1, 2, 3) }.should raise_error(NoMethodError)
end
- ruby_version_is "2.7" do
- it "raises an ArgumentError when the key exists" do
- os = OpenStruct.new(test: 20)
- -> { os.test(1, 2, 3) }.should raise_error(ArgumentError)
- end
+ it "raises an ArgumentError when the key exists" do
+ os = OpenStruct.new(test: 20)
+ -> { os.test(1, 2, 3) }.should raise_error(ArgumentError)
end
end
diff --git a/spec/ruby/library/pathname/birthtime_spec.rb b/spec/ruby/library/pathname/birthtime_spec.rb
new file mode 100644
index 0000000000..109c112303
--- /dev/null
+++ b/spec/ruby/library/pathname/birthtime_spec.rb
@@ -0,0 +1,16 @@
+require_relative '../../spec_helper'
+require 'pathname'
+
+describe "Pathname#birthtime" do
+ platform_is :windows, :darwin, :freebsd, :netbsd do
+ it "returns the birth time for self" do
+ Pathname.new(__FILE__).birthtime.should be_kind_of(Time)
+ end
+ end
+
+ platform_is :openbsd do
+ it "raises an NotImplementedError" do
+ -> { Pathname.new(__FILE__).birthtime }.should raise_error(NotImplementedError)
+ end
+ end
+end
diff --git a/spec/ruby/library/pathname/glob_spec.rb b/spec/ruby/library/pathname/glob_spec.rb
index f6dfd6cd58..ced810fa90 100644
--- a/spec/ruby/library/pathname/glob_spec.rb
+++ b/spec/ruby/library/pathname/glob_spec.rb
@@ -40,18 +40,45 @@ describe 'Pathname.glob' do
}.should raise_error(ArgumentError, /unknown keyword: :?foo/)
end
- ruby_version_is ''...'2.7' do
- it 'raises an ArgumentError when supplied a flag and :base keyword argument' do
- -> {
- Pathname.glob(@dir + 'lib/*i*.rb', File::FNM_DOTMATCH, base: 'lib')
- }.should raise_error(ArgumentError, 'wrong number of arguments (given 3, expected 1..2)')
- end
- end
-
- ruby_version_is "2.7" do
- it "does not raise an ArgumentError when supplied a flag and :base keyword argument" do
- expected = [Pathname.new('ipaddr.rb'), Pathname.new('irb.rb'), Pathname.new('.hidden.rb')].sort
- Pathname.glob('*i*.rb', File::FNM_DOTMATCH, base: @dir + 'lib').sort.should == expected
- end
+ it "does not raise an ArgumentError when supplied a flag and :base keyword argument" do
+ expected = [Pathname.new('ipaddr.rb'), Pathname.new('irb.rb'), Pathname.new('.hidden.rb')].sort
+ Pathname.glob('*i*.rb', File::FNM_DOTMATCH, base: @dir + 'lib').sort.should == expected
+ end
+end
+
+
+describe 'Pathname#glob' do
+ before :all do
+ @dir = tmp('pathname_glob') + '/'
+ @file_1 = @dir + 'lib/ipaddr.rb'
+ @file_2 = @dir + 'lib/irb.rb'
+ @file_3 = @dir + 'lib/.hidden.rb'
+
+ touch @file_1
+ touch @file_2
+ touch @file_3
+ end
+
+ after :all do
+ rm_r @dir[0...-1]
+ end
+
+ it 'returns [] for no match' do
+ Pathname.new(@dir).glob('lib/*.js').should == []
+ end
+
+ it 'returns matching file paths' do
+ Pathname.new(@dir).glob('lib/*i*.rb').sort.should == [Pathname.new(@file_1), Pathname.new(@file_2)].sort
+ end
+
+ it 'yields matching file paths to block' do
+ ary = []
+ Pathname.new(@dir).glob('lib/*i*.rb') { |p| ary << p }.should be_nil
+ ary.sort.should == [Pathname.new(@file_1), Pathname.new(@file_2)].sort
+ end
+
+ it 'returns matching file paths when a flag is provided' do
+ expected = [Pathname.new(@file_1), Pathname.new(@file_2), Pathname.new(@file_3)].sort
+ Pathname.new(@dir).glob('lib/*i*.rb', File::FNM_DOTMATCH).sort.should == expected
end
end
diff --git a/spec/ruby/library/pathname/new_spec.rb b/spec/ruby/library/pathname/new_spec.rb
index 760fd8638f..36226ed515 100644
--- a/spec/ruby/library/pathname/new_spec.rb
+++ b/spec/ruby/library/pathname/new_spec.rb
@@ -10,13 +10,6 @@ describe "Pathname.new" do
-> { Pathname.new("\0")}.should raise_error(ArgumentError)
end
- ruby_version_is ''...'2.7' do
- it "is tainted if path is tainted" do
- path = '/usr/local/bin'.taint
- Pathname.new(path).should.tainted?
- end
- end
-
it "raises a TypeError if not passed a String type" do
-> { Pathname.new(nil) }.should raise_error(TypeError)
-> { Pathname.new(0) }.should raise_error(TypeError)
diff --git a/spec/ruby/library/pathname/pathname_spec.rb b/spec/ruby/library/pathname/pathname_spec.rb
index 7d63fe86e3..0fb2881468 100644
--- a/spec/ruby/library/pathname/pathname_spec.rb
+++ b/spec/ruby/library/pathname/pathname_spec.rb
@@ -10,21 +10,10 @@ describe "Kernel#Pathname" do
Kernel.should have_method(:Pathname)
end
- ruby_version_is ''...'2.7' do
- it "returns a new pathname when called with a pathname argument" do
- path = Pathname('foo')
- new_path = Pathname(path)
+ it "returns same argument when called with a pathname argument" do
+ path = Pathname('foo')
+ new_path = Pathname(path)
- path.should_not.equal?(new_path)
- end
- end
-
- ruby_version_is '2.7' do
- it "returns same argument when called with a pathname argument" do
- path = Pathname('foo')
- new_path = Pathname(path)
-
- path.should.equal?(new_path)
- end
+ path.should.equal?(new_path)
end
end
diff --git a/spec/ruby/library/pathname/relative_path_from_spec.rb b/spec/ruby/library/pathname/relative_path_from_spec.rb
index abe9c80a45..133a149849 100644
--- a/spec/ruby/library/pathname/relative_path_from_spec.rb
+++ b/spec/ruby/library/pathname/relative_path_from_spec.rb
@@ -48,4 +48,8 @@ describe "Pathname#relative_path_from" do
relative_path_str('..', '..').should == '.'
relative_path_str('..', '.').should == '..'
end
+
+ it 'converts string argument to Pathname' do
+ Pathname.new('/usr/bin/ls').relative_path_from('/usr').to_s.should == 'bin/ls'
+ end
end
diff --git a/spec/ruby/library/prime/each_spec.rb b/spec/ruby/library/prime/each_spec.rb
index c89e871582..b99cf7cf0e 100644
--- a/spec/ruby/library/prime/each_spec.rb
+++ b/spec/ruby/library/prime/each_spec.rb
@@ -1,170 +1,167 @@
require_relative '../../spec_helper'
+require 'prime'
-ruby_version_is ""..."3.1" do
- require 'prime'
-
- describe :prime_each, shared: true do
- before :each do
- ScratchPad.record []
- end
+describe :prime_each, shared: true do
+ before :each do
+ ScratchPad.record []
+ end
- it "enumerates primes" do
- primes = Prime.instance
- result = []
+ it "enumerates primes" do
+ primes = Prime.instance
+ result = []
- primes.each { |p|
- result << p
- break if p > 10
- }
+ primes.each { |p|
+ result << p
+ break if p > 10
+ }
- result.should == [2, 3, 5, 7, 11]
- end
+ result.should == [2, 3, 5, 7, 11]
+ end
- it "yields ascending primes to the block" do
- previous = 1
- @object.each do |prime|
- break if prime > 1000
- ScratchPad << prime
- prime.should > previous
- previous = prime
- end
-
- all_prime = true
- ScratchPad.recorded.all? do |prime|
- all_prime &&= (2..Math.sqrt(prime)).all? { |d| prime % d != 0 }
- end
-
- all_prime.should be_true
+ it "yields ascending primes to the block" do
+ previous = 1
+ @object.each do |prime|
+ break if prime > 1000
+ ScratchPad << prime
+ prime.should > previous
+ previous = prime
end
- it "returns the last evaluated expression in the passed block" do
- @object.each { break :value }.should equal(:value)
+ all_prime = true
+ ScratchPad.recorded.all? do |prime|
+ all_prime &&= (2..Math.sqrt(prime)).all? { |d| prime % d != 0 }
end
- describe "when not passed a block" do
- before :each do
- @prime_enum = @object.each
- end
-
- it "returns an object that is Enumerable" do
- @prime_enum.each.should be_kind_of(Enumerable)
- end
-
- it "returns an object that responds to #with_index" do
- @prime_enum.should respond_to(:with_index)
- end
+ all_prime.should be_true
+ end
- it "returns an object that responds to #with_object" do
- @prime_enum.should respond_to(:with_object)
- end
+ it "returns the last evaluated expression in the passed block" do
+ @object.each { break :value }.should equal(:value)
+ end
- it "returns an object that responds to #next" do
- @prime_enum.should respond_to(:next)
- end
+ describe "when not passed a block" do
+ before :each do
+ @prime_enum = @object.each
+ end
- it "returns an object that responds to #rewind" do
- @prime_enum.should respond_to(:rewind)
- end
+ it "returns an object that is Enumerable" do
+ @prime_enum.each.should be_kind_of(Enumerable)
+ end
- it "yields primes starting at 2 independent of prior enumerators" do
- @prime_enum.next.should == 2
- @prime_enum.next.should == 3
+ it "returns an object that responds to #with_index" do
+ @prime_enum.should respond_to(:with_index)
+ end
- @object.each { |prime| break prime }.should == 2
- end
+ it "returns an object that responds to #with_object" do
+ @prime_enum.should respond_to(:with_object)
+ end
- it "returns an enumerator that yields previous primes when #rewind is called" do
- @prime_enum.next.should == 2
- @prime_enum.next.should == 3
- @prime_enum.rewind
- @prime_enum.next.should == 2
- end
+ it "returns an object that responds to #next" do
+ @prime_enum.should respond_to(:next)
+ end
- it "returns independent enumerators" do
- enum = @object.each
- enum.next.should == 2
- enum.next.should == 3
+ it "returns an object that responds to #rewind" do
+ @prime_enum.should respond_to(:rewind)
+ end
- @prime_enum.next.should == 2
+ it "yields primes starting at 2 independent of prior enumerators" do
+ @prime_enum.next.should == 2
+ @prime_enum.next.should == 3
- enum.next.should == 5
- end
+ @object.each { |prime| break prime }.should == 2
end
- end
- describe :prime_each_with_arguments, shared: true do
- before :each do
- ScratchPad.record []
+ it "returns an enumerator that yields previous primes when #rewind is called" do
+ @prime_enum.next.should == 2
+ @prime_enum.next.should == 3
+ @prime_enum.rewind
+ @prime_enum.next.should == 2
end
- it "yields ascending primes less than or equal to the argument" do
- bound = 1000
- previous = 1
- @object.each(bound) do |prime|
- ScratchPad << prime
- prime.should > previous
- previous = prime
- end
+ it "returns independent enumerators" do
+ enum = @object.each
+ enum.next.should == 2
+ enum.next.should == 3
- ScratchPad.recorded.all? do |prime|
- (2..Math.sqrt(prime)).all? { |d| prime % d != 0 }
- end.should be_true
+ @prime_enum.next.should == 2
- ScratchPad.recorded.all? { |prime| prime <= bound }.should be_true
+ enum.next.should == 5
end
+ end
+end
- it "returns nil when no prime is generated" do
- @object.each(1) { :value }.should be_nil
- end
+describe :prime_each_with_arguments, shared: true do
+ before :each do
+ ScratchPad.record []
+ end
- it "yields primes starting at 2 independent of prior enumeration" do
- @object.each(10) { |prime| prime }.should == 7
- @object.each(10) { |prime| break prime }.should == 2
+ it "yields ascending primes less than or equal to the argument" do
+ bound = 1000
+ previous = 1
+ @object.each(bound) do |prime|
+ ScratchPad << prime
+ prime.should > previous
+ previous = prime
end
- it "accepts a pseudo-prime generator as the second argument" do
- generator = mock('very bad pseudo-prime generator')
- generator.should_receive(:upper_bound=).with(100)
- generator.should_receive(:each).and_yield(2).and_yield(3).and_yield(4)
-
- @object.each(100, generator) { |prime| ScratchPad << prime }
- ScratchPad.recorded.should == [2, 3, 4]
- end
+ ScratchPad.recorded.all? do |prime|
+ (2..Math.sqrt(prime)).all? { |d| prime % d != 0 }
+ end.should be_true
- describe "when not passed a block" do
- it "returns an object that returns primes less than or equal to the bound" do
- bound = 100
- @object.each(bound).all? { |prime| prime <= bound }.should be_true
- end
- end
+ ScratchPad.recorded.all? { |prime| prime <= bound }.should be_true
end
- describe "Prime.each" do
- it_behaves_like :prime_each, :each, Prime
+ it "returns nil when no prime is generated" do
+ @object.each(1) { :value }.should be_nil
end
- describe "Prime.each" do
- it_behaves_like :prime_each_with_arguments, :each, Prime
+ it "yields primes starting at 2 independent of prior enumeration" do
+ @object.each(10) { |prime| prime }.should == 7
+ @object.each(10) { |prime| break prime }.should == 2
end
- describe "Prime#each with Prime.instance" do
- it_behaves_like :prime_each, :each, Prime.instance
- end
+ it "accepts a pseudo-prime generator as the second argument" do
+ generator = mock('very bad pseudo-prime generator')
+ generator.should_receive(:upper_bound=).with(100)
+ generator.should_receive(:each).and_yield(2).and_yield(3).and_yield(4)
- describe "Prime#each with Prime.instance" do
- it_behaves_like :prime_each_with_arguments, :each, Prime.instance
+ @object.each(100, generator) { |prime| ScratchPad << prime }
+ ScratchPad.recorded.should == [2, 3, 4]
end
- describe "Prime#each with Prime.instance" do
- before :each do
- @object = Prime.instance
+ describe "when not passed a block" do
+ it "returns an object that returns primes less than or equal to the bound" do
+ bound = 100
+ @object.each(bound).all? { |prime| prime <= bound }.should be_true
end
+ end
+end
- it_behaves_like :prime_each, :each
+describe "Prime.each" do
+ it_behaves_like :prime_each, :each, Prime
+end
- it "resets the enumerator with each call" do
- @object.each { |prime| break if prime > 10 }
- @object.each { |prime| break prime }.should == 2
- end
+describe "Prime.each" do
+ it_behaves_like :prime_each_with_arguments, :each, Prime
+end
+
+describe "Prime#each with Prime.instance" do
+ it_behaves_like :prime_each, :each, Prime.instance
+end
+
+describe "Prime#each with Prime.instance" do
+ it_behaves_like :prime_each_with_arguments, :each, Prime.instance
+end
+
+describe "Prime#each with Prime.instance" do
+ before :each do
+ @object = Prime.instance
+ end
+
+ it_behaves_like :prime_each, :each
+
+ it "resets the enumerator with each call" do
+ @object.each { |prime| break if prime > 10 }
+ @object.each { |prime| break prime }.should == 2
end
end
diff --git a/spec/ruby/library/prime/instance_spec.rb b/spec/ruby/library/prime/instance_spec.rb
index 82f21913b7..5183f36901 100644
--- a/spec/ruby/library/prime/instance_spec.rb
+++ b/spec/ruby/library/prime/instance_spec.rb
@@ -1,24 +1,21 @@
require_relative '../../spec_helper'
+require 'prime'
-ruby_version_is ""..."3.1" do
- require 'prime'
-
- describe "Prime.instance" do
- it "returns a object representing the set of prime numbers" do
- Prime.instance.should be_kind_of(Prime)
- end
+describe "Prime.instance" do
+ it "returns a object representing the set of prime numbers" do
+ Prime.instance.should be_kind_of(Prime)
+ end
- it "returns a object with no obsolete features" do
- Prime.instance.should_not respond_to(:succ)
- Prime.instance.should_not respond_to(:next)
- end
+ it "returns a object with no obsolete features" do
+ Prime.instance.should_not respond_to(:succ)
+ Prime.instance.should_not respond_to(:next)
+ end
- it "does not complain anything" do
- -> { Prime.instance }.should_not complain
- end
+ it "does not complain anything" do
+ -> { Prime.instance }.should_not complain
+ end
- it "raises a ArgumentError when is called with some arguments" do
- -> { Prime.instance(1) }.should raise_error(ArgumentError)
- end
+ it "raises a ArgumentError when is called with some arguments" do
+ -> { Prime.instance(1) }.should raise_error(ArgumentError)
end
end
diff --git a/spec/ruby/library/prime/int_from_prime_division_spec.rb b/spec/ruby/library/prime/int_from_prime_division_spec.rb
index 5c881aefa1..5abb7221df 100644
--- a/spec/ruby/library/prime/int_from_prime_division_spec.rb
+++ b/spec/ruby/library/prime/int_from_prime_division_spec.rb
@@ -1,16 +1,13 @@
require_relative '../../spec_helper'
+require 'prime'
-ruby_version_is ""..."3.1" do
- require 'prime'
-
- describe "Prime.int_from_prime_division" do
- it "returns the product of the given factorization" do
- Prime.int_from_prime_division([[2,3], [3,3], [5,3], [7,3], [11,3], [13,3], [17,3]]).
- should == 2**3 * 3**3 * 5**3 * 7**3 * 11**3 * 13**3 * 17**3
- end
+describe "Prime.int_from_prime_division" do
+ it "returns the product of the given factorization" do
+ Prime.int_from_prime_division([[2,3], [3,3], [5,3], [7,3], [11,3], [13,3], [17,3]]).
+ should == 2**3 * 3**3 * 5**3 * 7**3 * 11**3 * 13**3 * 17**3
+ end
- it "returns 1 for an empty factorization" do
- Prime.int_from_prime_division([]).should == 1
- end
+ it "returns 1 for an empty factorization" do
+ Prime.int_from_prime_division([]).should == 1
end
end
diff --git a/spec/ruby/library/prime/integer/each_prime_spec.rb b/spec/ruby/library/prime/integer/each_prime_spec.rb
index 6034802e73..a71296b0df 100644
--- a/spec/ruby/library/prime/integer/each_prime_spec.rb
+++ b/spec/ruby/library/prime/integer/each_prime_spec.rb
@@ -1,16 +1,13 @@
require_relative '../../../spec_helper'
+require 'prime'
-ruby_version_is ""..."3.1" do
- require 'prime'
-
- describe "Integer.each_prime" do
- it "is transferred to Prime.each" do
- Prime.should_receive(:each).with(100).and_yield(2).and_yield(3).and_yield(5)
- yielded = []
- Integer.each_prime(100) do |prime|
- yielded << prime
- end
- yielded.should == [2,3,5]
+describe "Integer.each_prime" do
+ it "is transferred to Prime.each" do
+ Prime.should_receive(:each).with(100).and_yield(2).and_yield(3).and_yield(5)
+ yielded = []
+ Integer.each_prime(100) do |prime|
+ yielded << prime
end
+ yielded.should == [2,3,5]
end
end
diff --git a/spec/ruby/library/prime/integer/from_prime_division_spec.rb b/spec/ruby/library/prime/integer/from_prime_division_spec.rb
index 5422bc651c..e0e74fb336 100644
--- a/spec/ruby/library/prime/integer/from_prime_division_spec.rb
+++ b/spec/ruby/library/prime/integer/from_prime_division_spec.rb
@@ -1,16 +1,13 @@
require_relative '../../../spec_helper'
+require 'prime'
-ruby_version_is ""..."3.1" do
- require 'prime'
-
- describe "Integer.from_prime_division" do
- it "returns the product of the given factorization" do
- Integer.from_prime_division([[2,3], [3,3], [5,3], [7,3], [11,3], [13,3], [17,3]]).
- should == 2**3 * 3**3 * 5**3 * 7**3 * 11**3 * 13**3 * 17**3
- end
+describe "Integer.from_prime_division" do
+ it "returns the product of the given factorization" do
+ Integer.from_prime_division([[2,3], [3,3], [5,3], [7,3], [11,3], [13,3], [17,3]]).
+ should == 2**3 * 3**3 * 5**3 * 7**3 * 11**3 * 13**3 * 17**3
+ end
- it "returns 1 for an empty factorization" do
- Integer.from_prime_division([]).should == 1
- end
+ it "returns 1 for an empty factorization" do
+ Integer.from_prime_division([]).should == 1
end
end
diff --git a/spec/ruby/library/prime/integer/prime_division_spec.rb b/spec/ruby/library/prime/integer/prime_division_spec.rb
index 03be0be27b..be03438a6f 100644
--- a/spec/ruby/library/prime/integer/prime_division_spec.rb
+++ b/spec/ruby/library/prime/integer/prime_division_spec.rb
@@ -1,22 +1,19 @@
require_relative '../../../spec_helper'
+require 'prime'
-ruby_version_is ""..."3.1" do
- require 'prime'
-
- describe "Integer#prime_division" do
- it "returns an array of a prime factor and a corresponding exponent" do
- (2*3*5*7*11*13*17).prime_division.should ==
- [[2,1], [3,1], [5,1], [7,1], [11,1], [13,1], [17,1]]
- end
+describe "Integer#prime_division" do
+ it "returns an array of a prime factor and a corresponding exponent" do
+ (2*3*5*7*11*13*17).prime_division.should ==
+ [[2,1], [3,1], [5,1], [7,1], [11,1], [13,1], [17,1]]
+ end
- it "returns an empty array for 1" do
- 1.prime_division.should == []
- end
- it "returns an empty array for -1" do
- -1.prime_division.should == [[-1, 1]]
- end
- it "raises ZeroDivisionError for 0" do
- -> { 0.prime_division }.should raise_error(ZeroDivisionError)
- end
+ it "returns an empty array for 1" do
+ 1.prime_division.should == []
+ end
+ it "returns an empty array for -1" do
+ -1.prime_division.should == [[-1, 1]]
+ end
+ it "raises ZeroDivisionError for 0" do
+ -> { 0.prime_division }.should raise_error(ZeroDivisionError)
end
end
diff --git a/spec/ruby/library/prime/integer/prime_spec.rb b/spec/ruby/library/prime/integer/prime_spec.rb
index 65b779e319..53de76d5ab 100644
--- a/spec/ruby/library/prime/integer/prime_spec.rb
+++ b/spec/ruby/library/prime/integer/prime_spec.rb
@@ -1,20 +1,17 @@
require_relative '../../../spec_helper'
+require 'prime'
-ruby_version_is ""..."3.1" do
- require 'prime'
-
- describe "Integer#prime?" do
- it "returns a true value for prime numbers" do
- 2.prime?.should be_true
- 3.prime?.should be_true
- (2**31-1).prime?.should be_true # 8th Mersenne prime (M8)
- end
+describe "Integer#prime?" do
+ it "returns a true value for prime numbers" do
+ 2.prime?.should be_true
+ 3.prime?.should be_true
+ (2**31-1).prime?.should be_true # 8th Mersenne prime (M8)
+ end
- it "returns a false value for composite numbers" do
- 4.prime?.should be_false
- 15.prime?.should be_false
- (2**32-1).prime?.should be_false
- ( (2**17-1)*(2**19-1) ).prime?.should be_false # M6*M7
- end
+ it "returns a false value for composite numbers" do
+ 4.prime?.should be_false
+ 15.prime?.should be_false
+ (2**32-1).prime?.should be_false
+ ( (2**17-1)*(2**19-1) ).prime?.should be_false # M6*M7
end
end
diff --git a/spec/ruby/library/prime/next_spec.rb b/spec/ruby/library/prime/next_spec.rb
index 8e805ed044..39c4ae16ae 100644
--- a/spec/ruby/library/prime/next_spec.rb
+++ b/spec/ruby/library/prime/next_spec.rb
@@ -1,10 +1,7 @@
require_relative '../../spec_helper'
+require_relative 'shared/next'
+require 'prime'
-ruby_version_is ""..."3.1" do
- require_relative 'shared/next'
- require 'prime'
-
- describe "Prime#next" do
- it_behaves_like :prime_next, :next
- end
+describe "Prime#next" do
+ it_behaves_like :prime_next, :next
end
diff --git a/spec/ruby/library/prime/prime_division_spec.rb b/spec/ruby/library/prime/prime_division_spec.rb
index 4c93d5936a..6293478f59 100644
--- a/spec/ruby/library/prime/prime_division_spec.rb
+++ b/spec/ruby/library/prime/prime_division_spec.rb
@@ -1,28 +1,25 @@
require_relative '../../spec_helper'
+require 'prime'
-ruby_version_is ""..."3.1" do
- require 'prime'
-
- describe "Prime.prime_division" do
- it "returns an array of a prime factor and a corresponding exponent" do
- Prime.prime_division(2*3*5*7*11*13*17).should ==
- [[2,1], [3,1], [5,1], [7,1], [11,1], [13,1], [17,1]]
- end
+describe "Prime.prime_division" do
+ it "returns an array of a prime factor and a corresponding exponent" do
+ Prime.prime_division(2*3*5*7*11*13*17).should ==
+ [[2,1], [3,1], [5,1], [7,1], [11,1], [13,1], [17,1]]
+ end
- it "returns an empty array for 1" do
- Prime.prime_division(1).should == []
- end
+ it "returns an empty array for 1" do
+ Prime.prime_division(1).should == []
+ end
- it "returns [[-1, 1]] for -1" do
- Prime.prime_division(-1).should == [[-1, 1]]
- end
+ it "returns [[-1, 1]] for -1" do
+ Prime.prime_division(-1).should == [[-1, 1]]
+ end
- it "includes [[-1, 1]] in the divisors of a negative number" do
- Prime.prime_division(-10).should include([-1, 1])
- end
+ it "includes [[-1, 1]] in the divisors of a negative number" do
+ Prime.prime_division(-10).should include([-1, 1])
+ end
- it "raises ZeroDivisionError for 0" do
- -> { Prime.prime_division(0) }.should raise_error(ZeroDivisionError)
- end
+ it "raises ZeroDivisionError for 0" do
+ -> { Prime.prime_division(0) }.should raise_error(ZeroDivisionError)
end
end
diff --git a/spec/ruby/library/prime/prime_spec.rb b/spec/ruby/library/prime/prime_spec.rb
index e2afddd5b2..0896c7f0f3 100644
--- a/spec/ruby/library/prime/prime_spec.rb
+++ b/spec/ruby/library/prime/prime_spec.rb
@@ -1,20 +1,17 @@
require_relative '../../spec_helper'
+require 'prime'
-ruby_version_is ""..."3.1" do
- require 'prime'
-
- describe "Prime#prime?" do
- it "returns a true value for prime numbers" do
- Prime.prime?(2).should be_true
- Prime.prime?(3).should be_true
- Prime.prime?(2**31-1).should be_true # 8th Mersenne prime (M8)
- end
+describe "Prime#prime?" do
+ it "returns a true value for prime numbers" do
+ Prime.prime?(2).should be_true
+ Prime.prime?(3).should be_true
+ Prime.prime?(2**31-1).should be_true # 8th Mersenne prime (M8)
+ end
- it "returns a false value for composite numbers" do
- Prime.prime?(4).should be_false
- Prime.prime?(15).should be_false
- Prime.prime?(2**32-1).should be_false
- Prime.prime?( (2**17-1)*(2**19-1) ).should be_false # M6*M7
- end
+ it "returns a false value for composite numbers" do
+ Prime.prime?(4).should be_false
+ Prime.prime?(15).should be_false
+ Prime.prime?(2**32-1).should be_false
+ Prime.prime?( (2**17-1)*(2**19-1) ).should be_false # M6*M7
end
end
diff --git a/spec/ruby/library/prime/succ_spec.rb b/spec/ruby/library/prime/succ_spec.rb
index 9843dae25d..34c18d2ba0 100644
--- a/spec/ruby/library/prime/succ_spec.rb
+++ b/spec/ruby/library/prime/succ_spec.rb
@@ -1,10 +1,7 @@
require_relative '../../spec_helper'
+require_relative 'shared/next'
+require 'prime'
-ruby_version_is ""..."3.1" do
- require_relative 'shared/next'
- require 'prime'
-
- describe "Prime#succ" do
- it_behaves_like :prime_next, :succ
- end
+describe "Prime#succ" do
+ it_behaves_like :prime_next, :succ
end
diff --git a/spec/ruby/library/rbconfig/unicode_emoji_version_spec.rb b/spec/ruby/library/rbconfig/unicode_emoji_version_spec.rb
index b7d9c7a8e4..3dc9900127 100644
--- a/spec/ruby/library/rbconfig/unicode_emoji_version_spec.rb
+++ b/spec/ruby/library/rbconfig/unicode_emoji_version_spec.rb
@@ -2,27 +2,22 @@ require_relative '../../spec_helper'
require 'rbconfig'
describe "RbConfig::CONFIG['UNICODE_EMOJI_VERSION']" do
- ruby_version_is "2.6"..."2.6.2" do
- it "is 11.0 for Ruby 2.6.0 and 2.6.1" do
- RbConfig::CONFIG['UNICODE_EMOJI_VERSION'].should == "11.0"
- end
- end
-
- ruby_version_is "2.6.2"..."2.7" do
- it "is 12.0 for Ruby 2.6.2+" do
- RbConfig::CONFIG['UNICODE_EMOJI_VERSION'].should == "12.0"
+ ruby_version_is ""..."3.1" do
+ it "is 12.1" do
+ RbConfig::CONFIG['UNICODE_EMOJI_VERSION'].should == "12.1"
end
end
- ruby_version_is "2.7"..."3.1" do
- it "is 12.1 for Ruby 2.7 and 3.0" do
- RbConfig::CONFIG['UNICODE_EMOJI_VERSION'].should == "12.1"
+ ruby_version_is "3.1"..."3.2" do
+ it "is 13.1" do
+ RbConfig::CONFIG['UNICODE_EMOJI_VERSION'].should == "13.1"
end
end
- ruby_version_is "3.1" do
- it "is 13.1 for Ruby 3.1" do
- RbConfig::CONFIG['UNICODE_EMOJI_VERSION'].should == "13.1"
+ # Caution: ruby_version_is means is_or_later
+ ruby_version_is "3.2" do
+ it "is 15.0" do
+ RbConfig::CONFIG['UNICODE_EMOJI_VERSION'].should == "15.0"
end
end
end
diff --git a/spec/ruby/library/rbconfig/unicode_version_spec.rb b/spec/ruby/library/rbconfig/unicode_version_spec.rb
index fe19b10293..458f13bf03 100644
--- a/spec/ruby/library/rbconfig/unicode_version_spec.rb
+++ b/spec/ruby/library/rbconfig/unicode_version_spec.rb
@@ -2,27 +2,22 @@ require_relative '../../spec_helper'
require 'rbconfig'
describe "RbConfig::CONFIG['UNICODE_VERSION']" do
- ruby_version_is "2.6"..."2.6.2" do
- it "is 11.0.0 for Ruby 2.6.0 and 2.6.1" do
- RbConfig::CONFIG['UNICODE_VERSION'].should == "11.0.0"
- end
- end
-
- ruby_version_is "2.6.2"..."2.6.3" do
- it "is 12.0.0 for Ruby 2.6.2" do
- RbConfig::CONFIG['UNICODE_VERSION'].should == "12.0.0"
+ ruby_version_is ""..."3.1" do
+ it "is 12.1.0" do
+ RbConfig::CONFIG['UNICODE_VERSION'].should == "12.1.0"
end
end
- ruby_version_is "2.6.3"..."3.1" do
- it "is 12.1.0 for Ruby 2.6.3+, Ruby 2.7, and Ruby 3.0" do
- RbConfig::CONFIG['UNICODE_VERSION'].should == "12.1.0"
+ ruby_version_is "3.1"..."3.2" do
+ it "is 13.0.0" do
+ RbConfig::CONFIG['UNICODE_VERSION'].should == "13.0.0"
end
end
- ruby_version_is "3.1" do
- it "is 13.0.0 for Ruby 3.1" do
- RbConfig::CONFIG['UNICODE_VERSION'].should == "13.0.0"
+ # Caution: ruby_version_is means is_or_later
+ ruby_version_is "3.2" do
+ it "is 15.0.0" do
+ RbConfig::CONFIG['UNICODE_VERSION'].should == "15.0.0"
end
end
end
diff --git a/spec/ruby/library/readline/history/delete_at_spec.rb b/spec/ruby/library/readline/history/delete_at_spec.rb
index c95a6a865e..3bd577e75c 100644
--- a/spec/ruby/library/readline/history/delete_at_spec.rb
+++ b/spec/ruby/library/readline/history/delete_at_spec.rb
@@ -34,14 +34,5 @@ with_feature :readline do
-> { Readline::HISTORY.delete_at(10) }.should raise_error(IndexError)
-> { Readline::HISTORY.delete_at(-10) }.should raise_error(IndexError)
end
-
- ruby_version_is ''...'2.7' do
- it "taints the returned strings" do
- Readline::HISTORY.push("1", "2", "3")
- Readline::HISTORY.delete_at(0).tainted?.should be_true
- Readline::HISTORY.delete_at(0).tainted?.should be_true
- Readline::HISTORY.delete_at(0).tainted?.should be_true
- end
- end
end
end
diff --git a/spec/ruby/library/readline/history/each_spec.rb b/spec/ruby/library/readline/history/each_spec.rb
index 23387bfc98..aa48dd46df 100644
--- a/spec/ruby/library/readline/history/each_spec.rb
+++ b/spec/ruby/library/readline/history/each_spec.rb
@@ -19,13 +19,5 @@ with_feature :readline do
end
result.should == ["1", "2", "3"]
end
-
- ruby_version_is ''...'2.7' do
- it "yields tainted Objects" do
- Readline::HISTORY.each do |x|
- x.tainted?.should be_true
- end
- end
- end
end
end
diff --git a/spec/ruby/library/readline/history/element_reference_spec.rb b/spec/ruby/library/readline/history/element_reference_spec.rb
index dfa5367cad..0a74f3d62d 100644
--- a/spec/ruby/library/readline/history/element_reference_spec.rb
+++ b/spec/ruby/library/readline/history/element_reference_spec.rb
@@ -12,13 +12,6 @@ with_feature :readline do
Readline::HISTORY.pop
end
- ruby_version_is ''...'2.7' do
- it "returns tainted objects" do
- Readline::HISTORY[0].tainted?.should be_true
- Readline::HISTORY[1].tainted?.should be_true
- end
- end
-
it "returns the history item at the passed index" do
Readline::HISTORY[0].should == "1"
Readline::HISTORY[1].should == "2"
diff --git a/spec/ruby/library/readline/history/pop_spec.rb b/spec/ruby/library/readline/history/pop_spec.rb
index e17be666d8..156a8a06f8 100644
--- a/spec/ruby/library/readline/history/pop_spec.rb
+++ b/spec/ruby/library/readline/history/pop_spec.rb
@@ -19,14 +19,5 @@ with_feature :readline do
Readline::HISTORY.pop.should == "1"
Readline::HISTORY.size.should == 0
end
-
- ruby_version_is ''...'2.7' do
- it "taints the returned strings" do
- Readline::HISTORY.push("1", "2", "3")
- Readline::HISTORY.pop.tainted?.should be_true
- Readline::HISTORY.pop.tainted?.should be_true
- Readline::HISTORY.pop.tainted?.should be_true
- end
- end
end
end
diff --git a/spec/ruby/library/readline/history/shift_spec.rb b/spec/ruby/library/readline/history/shift_spec.rb
index ccd90193fd..9aad7d5399 100644
--- a/spec/ruby/library/readline/history/shift_spec.rb
+++ b/spec/ruby/library/readline/history/shift_spec.rb
@@ -19,14 +19,5 @@ with_feature :readline do
Readline::HISTORY.shift.should == "3"
Readline::HISTORY.size.should == 0
end
-
- ruby_version_is ''...'2.7' do
- it "taints the returned strings" do
- Readline::HISTORY.push("1", "2", "3")
- Readline::HISTORY.shift.tainted?.should be_true
- Readline::HISTORY.shift.tainted?.should be_true
- Readline::HISTORY.shift.tainted?.should be_true
- end
- end
end
end
diff --git a/spec/ruby/library/readline/readline_spec.rb b/spec/ruby/library/readline/readline_spec.rb
index 24d2cbbe86..6e349ad543 100644
--- a/spec/ruby/library/readline/readline_spec.rb
+++ b/spec/ruby/library/readline/readline_spec.rb
@@ -21,13 +21,6 @@ with_feature :readline do
ruby_exe('File.write ARGV[0], Readline.readline', @options)
File.read(@out).should == "test"
end
-
- ruby_version_is ''...'2.7' do
- it "taints the returned strings" do
- ruby_exe('File.write ARGV[0], Readline.readline.tainted?', @options)
- File.read(@out).should == "true"
- end
- end
end
end
end
diff --git a/spec/ruby/library/rexml/attribute/clone_spec.rb b/spec/ruby/library/rexml/attribute/clone_spec.rb
deleted file mode 100644
index 5c86468d45..0000000000
--- a/spec/ruby/library/rexml/attribute/clone_spec.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Attribute#clone" do
- it "returns a copy of this Attribute" do
- orig = REXML::Attribute.new("name", "value&&")
- orig.should == orig.clone
- orig.clone.to_s.should == orig.to_s
- orig.clone.to_string.should == orig.to_string
- end
- end
-end
diff --git a/spec/ruby/library/rexml/attribute/element_spec.rb b/spec/ruby/library/rexml/attribute/element_spec.rb
deleted file mode 100644
index 0e4ce46a4f..0000000000
--- a/spec/ruby/library/rexml/attribute/element_spec.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Attribute#element" do
- it "returns the parent element" do
- e = REXML::Element.new "root"
-
- REXML::Attribute.new("name", "value", e).element.should == e
- REXML::Attribute.new("name", "default_constructor").element.should == nil
- end
- end
-
- describe "REXML::Attribute#element=" do
- it "sets the parent element" do
- e = REXML::Element.new "root"
- f = REXML::Element.new "temp"
- a = REXML::Attribute.new("name", "value", e)
- a.element.should == e
-
- a.element = f
- a.element.should == f
- end
- end
-end
diff --git a/spec/ruby/library/rexml/attribute/equal_value_spec.rb b/spec/ruby/library/rexml/attribute/equal_value_spec.rb
deleted file mode 100644
index 1498bae624..0000000000
--- a/spec/ruby/library/rexml/attribute/equal_value_spec.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Attribute#==" do
- it "returns true if other has equal name and value" do
- a1 = REXML::Attribute.new("foo", "bar")
- a1.should == a1.clone
-
- a2 = REXML::Attribute.new("foo", "bar")
- a1.should == a2
-
- a3 = REXML::Attribute.new("foo", "bla")
- a1.should_not == a3
-
- a4 = REXML::Attribute.new("baz", "bar")
- a1.should_not == a4
- end
- end
-end
diff --git a/spec/ruby/library/rexml/attribute/hash_spec.rb b/spec/ruby/library/rexml/attribute/hash_spec.rb
deleted file mode 100644
index 7e0cbcc1ea..0000000000
--- a/spec/ruby/library/rexml/attribute/hash_spec.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Attribute#hash" do
- # These are not really complete, any idea on how to make them more
- # "testable" will be appreciated.
- it "returns a hashcode made of the name and value of self" do
- a = REXML::Attribute.new("name", "value")
- a.hash.should be_kind_of(Numeric)
- b = REXML::Attribute.new(a)
- a.hash.should == b.hash
- end
- end
-end
diff --git a/spec/ruby/library/rexml/attribute/initialize_spec.rb b/spec/ruby/library/rexml/attribute/initialize_spec.rb
deleted file mode 100644
index 35b87b0733..0000000000
--- a/spec/ruby/library/rexml/attribute/initialize_spec.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Attribute#initialize" do
- before :each do
- @e = REXML::Element.new "root"
- @name = REXML::Attribute.new("name", "Nicko")
- @e.add_attribute @name
- end
-
- it "receives two strings for name and value" do
- @e.attributes["name"].should == "Nicko"
- @e.add_attribute REXML::Attribute.new("last_name", nil)
- @e.attributes["last_name"].should == ""
- end
-
- it "receives an Attribute and clones it" do
- copy = REXML::Attribute.new(@name)
- copy.should == @name
- end
-
- it "receives a parent node" do
- last_name = REXML::Attribute.new("last_name", "McBrain", @e)
- last_name.element.should == @e
-
- last_name = REXML::Attribute.new(@name, @e)
- last_name.element.should == @e
- end
- end
-end
diff --git a/spec/ruby/library/rexml/attribute/inspect_spec.rb b/spec/ruby/library/rexml/attribute/inspect_spec.rb
deleted file mode 100644
index ee5236b98e..0000000000
--- a/spec/ruby/library/rexml/attribute/inspect_spec.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Attribute#inspect" do
- it "returns the name and value as a string" do
- a = REXML::Attribute.new("my_name", "my_value")
- a.inspect.should == "my_name='my_value'"
- end
-
- it "accepts attributes with no value" do
- a = REXML::Attribute.new("my_name")
- a.inspect.should == "my_name=''"
- end
-
- it "does not escape text" do
- a = REXML::Attribute.new("name", "<>")
- a.inspect.should == "name='<>'"
- end
- end
-end
diff --git a/spec/ruby/library/rexml/attribute/namespace_spec.rb b/spec/ruby/library/rexml/attribute/namespace_spec.rb
deleted file mode 100644
index 645b3cd1b1..0000000000
--- a/spec/ruby/library/rexml/attribute/namespace_spec.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Attribute#namespace" do
- it "returns the namespace url" do
- e = REXML::Element.new("root")
- e.add_attribute REXML::Attribute.new("xmlns:ns", "http://some_uri")
- e.namespace("ns").should == "http://some_uri"
- end
-
- it "returns nil if namespace is not defined" do
- e = REXML::Element.new("root")
- e.add_attribute REXML::Attribute.new("test", "value")
- e.namespace("test").should == nil
- e.namespace("ns").should == nil
- end
-
- it "defaults arg to nil" do
- e = REXML::Element.new("root")
- e.add_attribute REXML::Attribute.new("xmlns:ns", "http://some_uri")
- e.namespace.should == ""
- e.namespace("ns").should == "http://some_uri"
- end
- end
-end
diff --git a/spec/ruby/library/rexml/attribute/node_type_spec.rb b/spec/ruby/library/rexml/attribute/node_type_spec.rb
deleted file mode 100644
index da055ae8f0..0000000000
--- a/spec/ruby/library/rexml/attribute/node_type_spec.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Attribute#node_type" do
- it "always returns :attribute" do
- attr = REXML::Attribute.new("foo", "bar")
- attr.node_type.should == :attribute
- REXML::Attribute.new(attr).node_type.should == :attribute
- end
- end
-end
diff --git a/spec/ruby/library/rexml/attribute/prefix_spec.rb b/spec/ruby/library/rexml/attribute/prefix_spec.rb
deleted file mode 100644
index 87bff4822b..0000000000
--- a/spec/ruby/library/rexml/attribute/prefix_spec.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Attribute#prefix" do
- it "returns the namespace of the Attribute" do
- ans = REXML::Attribute.new("ns:someattr", "some_value")
- out = REXML::Attribute.new("out:something", "some_other_value")
-
- ans.prefix.should == "ns"
- out.prefix.should == "out"
- end
-
- it "returns an empty string for Attributes with no prefixes" do
- attr = REXML::Attribute.new("foo", "bar")
-
- attr.prefix.should == ""
- end
- end
-end
diff --git a/spec/ruby/library/rexml/attribute/remove_spec.rb b/spec/ruby/library/rexml/attribute/remove_spec.rb
deleted file mode 100644
index 5f928b1286..0000000000
--- a/spec/ruby/library/rexml/attribute/remove_spec.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Attribute#remove" do
- before :each do
- @e = REXML::Element.new "Root"
- @attr = REXML::Attribute.new("foo", "bar")
- end
-
- it "deletes this Attribute from parent" do
- @e.add_attribute(@attr)
- @e.attributes["foo"].should_not == nil
- @attr.remove
- @e.attributes["foo"].should == nil
- end
-
- it "does not anything if element has no parent" do
- -> {@attr.remove}.should_not raise_error(Exception)
- end
- end
-end
diff --git a/spec/ruby/library/rexml/attribute/to_s_spec.rb b/spec/ruby/library/rexml/attribute/to_s_spec.rb
deleted file mode 100644
index e362cee8f1..0000000000
--- a/spec/ruby/library/rexml/attribute/to_s_spec.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Attribute#to_s" do
- it "returns the value of the Attribute" do
- REXML::Attribute.new("name", "some_value").to_s.should == "some_value"
- end
-
- it "returns the escaped value if it was created from Attribute" do
- orig = REXML::Attribute.new("name", "<&>")
- copy = REXML::Attribute.new(orig)
- copy.to_s.should == "&lt;&amp;&gt;"
- end
- end
-end
diff --git a/spec/ruby/library/rexml/attribute/to_string_spec.rb b/spec/ruby/library/rexml/attribute/to_string_spec.rb
deleted file mode 100644
index a9d249f5bb..0000000000
--- a/spec/ruby/library/rexml/attribute/to_string_spec.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Attribute#to_string" do
- it "returns the attribute as XML" do
- attr = REXML::Attribute.new("name", "value")
- attr_empty = REXML::Attribute.new("name")
- attr_ns = REXML::Attribute.new("xmlns:ns", "http://uri")
-
- attr.to_string.should == "name='value'"
- attr_empty.to_string.should == "name=''"
- attr_ns.to_string.should == "xmlns:ns='http://uri'"
- end
- end
-end
diff --git a/spec/ruby/library/rexml/attribute/value_spec.rb b/spec/ruby/library/rexml/attribute/value_spec.rb
deleted file mode 100644
index 77071f6f70..0000000000
--- a/spec/ruby/library/rexml/attribute/value_spec.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Attribute#value" do
- it "returns the value of the Attribute unnormalized" do
- attr = REXML::Attribute.new("name", "value")
- attr_ents = REXML::Attribute.new("name", "<&>")
- attr_empty = REXML::Attribute.new("name")
-
- attr.value.should == "value"
- attr_ents.value.should == "<&>"
- attr_empty.value.should == ""
- end
- end
-end
diff --git a/spec/ruby/library/rexml/attribute/write_spec.rb b/spec/ruby/library/rexml/attribute/write_spec.rb
deleted file mode 100644
index 0012b3cc77..0000000000
--- a/spec/ruby/library/rexml/attribute/write_spec.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Attribute#write" do
- before :each do
- @attr = REXML::Attribute.new("name", "Charlotte")
- @s = ""
- end
-
- it "writes the name and value to output" do
- @attr.write(@s)
- @s.should == "name='Charlotte'"
- end
-
- it "currently ignores the second argument" do
- @attr.write(@s, 3)
- @s.should == "name='Charlotte'"
-
- @s = ""
- @attr.write(@s, "foo")
- @s.should == "name='Charlotte'"
- end
- end
-end
diff --git a/spec/ruby/library/rexml/attribute/xpath_spec.rb b/spec/ruby/library/rexml/attribute/xpath_spec.rb
deleted file mode 100644
index 0a09046b01..0000000000
--- a/spec/ruby/library/rexml/attribute/xpath_spec.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Attribute#xpath" do
-
- before :each do
- @e = REXML::Element.new "root"
- @attr = REXML::Attribute.new("year", "1989")
- end
-
- it "returns the path for Attribute" do
- @e.add_attribute @attr
- @attr.xpath.should == "root/@year"
- end
-
- it "raises an error if attribute has no parent" do
- -> { @attr.xpath }.should raise_error(Exception)
- end
- end
-end
diff --git a/spec/ruby/library/rexml/attributes/add_spec.rb b/spec/ruby/library/rexml/attributes/add_spec.rb
deleted file mode 100644
index e24e9fabbc..0000000000
--- a/spec/ruby/library/rexml/attributes/add_spec.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require_relative 'shared/add'
- require 'rexml/document'
-
- describe "REXML::Attributes#add" do
- it_behaves_like :rexml_attribute_add, :add
- end
-end
diff --git a/spec/ruby/library/rexml/attributes/append_spec.rb b/spec/ruby/library/rexml/attributes/append_spec.rb
deleted file mode 100644
index f96a727f47..0000000000
--- a/spec/ruby/library/rexml/attributes/append_spec.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require_relative 'shared/add'
- require 'rexml/document'
-
- describe "REXML::Attributes#<<" do
- it_behaves_like :rexml_attribute_add, :<<
- end
-end
diff --git a/spec/ruby/library/rexml/attributes/delete_all_spec.rb b/spec/ruby/library/rexml/attributes/delete_all_spec.rb
deleted file mode 100644
index 707baa235b..0000000000
--- a/spec/ruby/library/rexml/attributes/delete_all_spec.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Attributes#delete_all" do
- before :each do
- @e = REXML::Element.new("root")
- end
-
- it "deletes all attributes that match name" do
- uri = REXML::Attribute.new("uri", "http://something")
- @e.attributes << uri
- @e.attributes.delete_all("uri")
- @e.attributes.should be_empty
- @e.attributes["uri"].should == nil
- end
-
- it "deletes all attributes that match name with a namespace" do
- ns_uri = REXML::Attribute.new("xmlns:uri", "http://something_here_too")
- @e.attributes << ns_uri
- @e.attributes.delete_all("xmlns:uri")
- @e.attributes.should be_empty
- @e.attributes["xmlns:uri"].should == nil
- end
-
- it "returns the removed attribute" do
- uri = REXML::Attribute.new("uri", "http://something_here_too")
- @e.attributes << uri
- attrs = @e.attributes.delete_all("uri")
- attrs.first.should == uri
- end
- end
-end
diff --git a/spec/ruby/library/rexml/attributes/delete_spec.rb b/spec/ruby/library/rexml/attributes/delete_spec.rb
deleted file mode 100644
index 723fa70751..0000000000
--- a/spec/ruby/library/rexml/attributes/delete_spec.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Attributes#delete" do
- before :each do
- @e = REXML::Element.new("root")
- @name = REXML::Attribute.new("name", "Pepe")
- end
-
- it "takes an attribute name and deletes the attribute" do
- @e.attributes.delete("name")
- @e.attributes["name"].should be_nil
- @e.attributes.should be_empty
- end
-
- it "takes an Attribute and deletes it" do
- @e.attributes.delete(@name)
- @e.attributes["name"].should be_nil
- @e.attributes.should be_empty
- end
-
- it "returns the element with the attribute removed" do
- ret_val = @e.attributes.delete(@name)
- ret_val.should == @e
- ret_val.attributes.should be_empty
- end
- end
-end
diff --git a/spec/ruby/library/rexml/attributes/each_attribute_spec.rb b/spec/ruby/library/rexml/attributes/each_attribute_spec.rb
deleted file mode 100644
index 692cf4f943..0000000000
--- a/spec/ruby/library/rexml/attributes/each_attribute_spec.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Attributes#each_attribute" do
- it "iterates over the attributes yielding actual Attribute objects" do
- e = REXML::Element.new("root")
- name = REXML::Attribute.new("name", "Joe")
- ns_uri = REXML::Attribute.new("xmlns:ns", "http://some_uri")
- e.add_attribute name
- e.add_attribute ns_uri
-
- attributes = []
-
- e.attributes.each_attribute do |attr|
- attributes << attr
- end
-
- attributes = attributes.sort_by {|a| a.name }
- attributes.first.should == name
- attributes.last.should == ns_uri
- end
- end
-end
diff --git a/spec/ruby/library/rexml/attributes/each_spec.rb b/spec/ruby/library/rexml/attributes/each_spec.rb
deleted file mode 100644
index 49add3b77b..0000000000
--- a/spec/ruby/library/rexml/attributes/each_spec.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Attributes#each" do
- before :each do
- @e = REXML::Element.new("root")
- @name = REXML::Attribute.new("name", "Joe")
- @ns_uri = REXML::Attribute.new("xmlns:ns", "http://some_uri")
- @e.add_attribute @name
- @e.add_attribute @ns_uri
- end
-
- it "iterates over the attributes yielding expanded-name/value" do
- attributes = []
- @e.attributes.each do |attr|
- attr.should be_kind_of(Array)
- attributes << attr
- end
- attributes = attributes.sort_by {|a| a.first }
- attributes.first.should == ["name", "Joe"]
- attributes.last.should == ["xmlns:ns", "http://some_uri"]
- end
- end
-end
diff --git a/spec/ruby/library/rexml/attributes/element_reference_spec.rb b/spec/ruby/library/rexml/attributes/element_reference_spec.rb
deleted file mode 100644
index 0d089eaab2..0000000000
--- a/spec/ruby/library/rexml/attributes/element_reference_spec.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Attributes#[]" do
- before :each do
- @e = REXML::Element.new("root")
- @lang = REXML::Attribute.new("language", "english")
- @e.attributes << @lang
- end
-
- it "returns the value of an attribute" do
- @e.attributes["language"].should == "english"
- end
-
- it "returns nil if the attribute does not exist" do
- @e.attributes["chunky bacon"].should == nil
- end
- end
-end
diff --git a/spec/ruby/library/rexml/attributes/element_set_spec.rb b/spec/ruby/library/rexml/attributes/element_set_spec.rb
deleted file mode 100644
index 834ad682a6..0000000000
--- a/spec/ruby/library/rexml/attributes/element_set_spec.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Attributes#[]=" do
- before :each do
- @e = REXML::Element.new("song")
- @name = REXML::Attribute.new("name", "Holy Smoke!")
- @e.attributes << @name
- end
-
- it "sets an attribute" do
- @e.attributes["author"] = "_why's foxes"
- @e.attributes["author"].should == "_why's foxes"
- end
-
- it "overwrites an existing attribute" do
- @e.attributes["name"] = "Chunky Bacon"
- @e.attributes["name"].should == "Chunky Bacon"
- end
-
- it "deletes an attribute is value is nil" do
- @e.attributes["name"] = nil
- @e.attributes.length.should == 0
- end
- end
-end
diff --git a/spec/ruby/library/rexml/attributes/get_attribute_ns_spec.rb b/spec/ruby/library/rexml/attributes/get_attribute_ns_spec.rb
deleted file mode 100644
index 1109ff519c..0000000000
--- a/spec/ruby/library/rexml/attributes/get_attribute_ns_spec.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Attributes#get_attribute_ns" do
- it "returns an attribute by name and namespace" do
- e = REXML::Element.new("root")
- attr = REXML::Attribute.new("xmlns:ns", "http://some_url")
- e.attributes << attr
- attr.prefix.should == "xmlns"
- # This might be a bug in Attribute, commenting until those specs
- # are ready
- # e.attributes.get_attribute_ns(attr.prefix, "name").should == "http://some_url"
- end
- end
-end
diff --git a/spec/ruby/library/rexml/attributes/get_attribute_spec.rb b/spec/ruby/library/rexml/attributes/get_attribute_spec.rb
deleted file mode 100644
index cc94191729..0000000000
--- a/spec/ruby/library/rexml/attributes/get_attribute_spec.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Attributes#get_attribute" do
- before :each do
- @e = REXML::Element.new("root")
- @name = REXML::Attribute.new("name", "Dave")
- @e.attributes << @name
- end
-
- it "fetches an attributes" do
- @e.attributes.get_attribute("name").should == @name
- end
-
- it "fetches an namespaced attribute" do
- ns_name = REXML::Attribute.new("im:name", "Murray")
- @e.attributes << ns_name
- @e.attributes.get_attribute("name").should == @name
- @e.attributes.get_attribute("im:name").should == ns_name
- end
-
- it "returns an Attribute" do
- @e.attributes.get_attribute("name").should be_kind_of(REXML::Attribute)
- end
-
- it "returns nil if it attribute does not exist" do
- @e.attributes.get_attribute("fake").should be_nil
- end
- end
-end
diff --git a/spec/ruby/library/rexml/attributes/initialize_spec.rb b/spec/ruby/library/rexml/attributes/initialize_spec.rb
deleted file mode 100644
index 42ec742e60..0000000000
--- a/spec/ruby/library/rexml/attributes/initialize_spec.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Attributes#initialize" do
- it "is auto initialized by Element" do
- e = REXML::Element.new "root"
- e.attributes.should be_kind_of(REXML::Attributes)
-
- e.attributes << REXML::Attribute.new("name", "Paul")
- e.attributes["name"].should == "Paul"
- end
-
- it "receives a parent node" do
- e = REXML::Element.new "root"
- e.attributes << REXML::Attribute.new("name", "Vic")
- e.attributes["name"].should == "Vic"
- end
- end
-end
diff --git a/spec/ruby/library/rexml/attributes/length_spec.rb b/spec/ruby/library/rexml/attributes/length_spec.rb
deleted file mode 100644
index 81733b4a96..0000000000
--- a/spec/ruby/library/rexml/attributes/length_spec.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require_relative 'shared/length'
- require 'rexml/document'
-
- describe "REXML::Attributes#length" do
- it_behaves_like :rexml_attribute_length, :length
- end
-end
diff --git a/spec/ruby/library/rexml/attributes/namespaces_spec.rb b/spec/ruby/library/rexml/attributes/namespaces_spec.rb
deleted file mode 100644
index b88346854f..0000000000
--- a/spec/ruby/library/rexml/attributes/namespaces_spec.rb
+++ /dev/null
@@ -1,9 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Attributes#namespaces" do
- it "needs to be reviewed for spec completeness"
- end
-end
diff --git a/spec/ruby/library/rexml/attributes/prefixes_spec.rb b/spec/ruby/library/rexml/attributes/prefixes_spec.rb
deleted file mode 100644
index 574b7ffbaf..0000000000
--- a/spec/ruby/library/rexml/attributes/prefixes_spec.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Attributes#prefixes" do
- before :each do
- @e = REXML::Element.new("root")
- a1 = REXML::Attribute.new("xmlns:a", "bar")
- a2 = REXML::Attribute.new("xmlns:b", "bla")
- a3 = REXML::Attribute.new("xmlns:c", "baz")
- @e.attributes << a1
- @e.attributes << a2
- @e.attributes << a3
-
- @e.attributes << REXML::Attribute.new("xmlns", "foo")
- end
-
- it "returns an array with the prefixes of each attribute" do
- @e.attributes.prefixes.sort.should == ["a", "b", "c"]
- end
-
- it "does not include the default namespace" do
- @e.attributes.prefixes.include?("xmlns").should == false
- end
- end
-end
diff --git a/spec/ruby/library/rexml/attributes/shared/add.rb b/spec/ruby/library/rexml/attributes/shared/add.rb
deleted file mode 100644
index 872f149f45..0000000000
--- a/spec/ruby/library/rexml/attributes/shared/add.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-describe :rexml_attribute_add, shared: true do
- before :each do
- @e = REXML::Element.new("root")
- @attr = REXML::Attributes.new(@e)
- @name = REXML::Attribute.new("name", "Joe")
- end
-
- it "adds an attribute" do
- @attr.send(@method, @name)
- @attr["name"].should == "Joe"
- end
-
- it "replaces an existing attribute" do
- @attr.send(@method, REXML::Attribute.new("name", "Bruce"))
- @attr["name"].should == "Bruce"
- end
-end
diff --git a/spec/ruby/library/rexml/attributes/shared/length.rb b/spec/ruby/library/rexml/attributes/shared/length.rb
deleted file mode 100644
index 7848f9bf33..0000000000
--- a/spec/ruby/library/rexml/attributes/shared/length.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'rexml/document'
-
-describe :rexml_attribute_length, shared: true do
- it "returns the number of attributes" do
- e = REXML::Element.new("root")
- e.attributes.send(@method).should == 0
-
- e.attributes << REXML::Attribute.new("name", "John")
- e.attributes << REXML::Attribute.new("another_name", "Leo")
- e.attributes.send(@method).should == 2
- end
-end
diff --git a/spec/ruby/library/rexml/attributes/size_spec.rb b/spec/ruby/library/rexml/attributes/size_spec.rb
deleted file mode 100644
index 13ef08f644..0000000000
--- a/spec/ruby/library/rexml/attributes/size_spec.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require_relative 'shared/length'
- require 'rexml/document'
-
- describe "REXML::Attributes#size" do
- it_behaves_like :rexml_attribute_length, :size
- end
-end
diff --git a/spec/ruby/library/rexml/attributes/to_a_spec.rb b/spec/ruby/library/rexml/attributes/to_a_spec.rb
deleted file mode 100644
index 902cd86a29..0000000000
--- a/spec/ruby/library/rexml/attributes/to_a_spec.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Attributes#to_a" do
- it "returns an array with the attributes" do
- e = REXML::Element.new("root")
- name = REXML::Attribute.new("name", "Dave")
- last = REXML::Attribute.new("last_name", "Murray")
-
- e.attributes << name
- e.attributes << last
-
- e.attributes.to_a.sort{|a,b|a.to_s<=>b.to_s}.should == [name, last]
- end
-
- it "returns an empty array if it has no attributes" do
- REXML::Element.new("root").attributes.to_a.should == []
- end
- end
-end
diff --git a/spec/ruby/library/rexml/cdata/clone_spec.rb b/spec/ruby/library/rexml/cdata/clone_spec.rb
deleted file mode 100644
index abe1a0b062..0000000000
--- a/spec/ruby/library/rexml/cdata/clone_spec.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::CData#clone" do
- it "makes a copy of itself" do
- c = REXML::CData.new("some text")
- c.clone.to_s.should == c.to_s
- c.clone.should == c
- end
- end
-end
diff --git a/spec/ruby/library/rexml/cdata/initialize_spec.rb b/spec/ruby/library/rexml/cdata/initialize_spec.rb
deleted file mode 100644
index 1393d97f4a..0000000000
--- a/spec/ruby/library/rexml/cdata/initialize_spec.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::CData#initialize" do
- it "creates a new CData object" do
- c = REXML::CData.new("some text")
- c.should be_kind_of(REXML::CData)
- c.should be_kind_of(REXML::Text)
- end
-
- it "respects whitespace if whitespace is true" do
- c = REXML::CData.new("whitespace test", true)
- c1 = REXML::CData.new("whitespace test", false)
-
- c.to_s.should == "whitespace test"
- c1.to_s.should == "whitespace test"
- end
-
- it "receives parent as third argument" do
- e = REXML::Element.new("root")
- REXML::CData.new("test", true, e)
- e.to_s.should == "<root><![CDATA[test]]></root>"
- end
- end
-end
diff --git a/spec/ruby/library/rexml/cdata/shared/to_s.rb b/spec/ruby/library/rexml/cdata/shared/to_s.rb
deleted file mode 100644
index f8c4951c95..0000000000
--- a/spec/ruby/library/rexml/cdata/shared/to_s.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-describe :rexml_cdata_to_s, shared: true do
- it "returns the contents of the CData" do
- c = REXML::CData.new("some text")
- c.send(@method).should == "some text"
- end
-
- it "does not escape text" do
- c1 = REXML::CData.new("some& text\n")
- c1.send(@method).should == "some& text\n"
- end
-end
diff --git a/spec/ruby/library/rexml/cdata/to_s_spec.rb b/spec/ruby/library/rexml/cdata/to_s_spec.rb
deleted file mode 100644
index a5c061f116..0000000000
--- a/spec/ruby/library/rexml/cdata/to_s_spec.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require_relative 'shared/to_s'
- require 'rexml/document'
-
- describe "REXML::CData#to_s" do
- it_behaves_like :rexml_cdata_to_s, :to_s
- end
-end
diff --git a/spec/ruby/library/rexml/cdata/value_spec.rb b/spec/ruby/library/rexml/cdata/value_spec.rb
deleted file mode 100644
index 9f36226976..0000000000
--- a/spec/ruby/library/rexml/cdata/value_spec.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require_relative 'shared/to_s'
- require 'rexml/document'
-
- describe "REXML::CData#value" do
- it_behaves_like :rexml_cdata_to_s, :value
- end
-end
diff --git a/spec/ruby/library/rexml/document/add_element_spec.rb b/spec/ruby/library/rexml/document/add_element_spec.rb
deleted file mode 100644
index 29dec0b24e..0000000000
--- a/spec/ruby/library/rexml/document/add_element_spec.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Document#add_element" do
- it "adds arg1 with attributes arg2 as root node" do
- d = REXML::Document.new
- e = REXML::Element.new("root")
- d.add_element e
- d.root.should == e
- end
-
- it "sets arg2 as arg1's attributes" do
- d = REXML::Document.new
- e = REXML::Element.new("root")
- attr = {"foo" => "bar"}
- d.add_element(e,attr)
- d.root.attributes["foo"].should == attr["foo"]
- end
-
- it "accepts a node name as arg1 and adds it as root" do
- d = REXML::Document.new
- d.add_element "foo"
- d.root.name.should == "foo"
- end
-
- it "sets arg1's context to the root's context" do
- d = REXML::Document.new("", {"foo" => "bar"})
- d.add_element "foo"
- d.root.context.should == d.context
- end
- end
-end
diff --git a/spec/ruby/library/rexml/document/add_spec.rb b/spec/ruby/library/rexml/document/add_spec.rb
deleted file mode 100644
index 8666d3dbf9..0000000000
--- a/spec/ruby/library/rexml/document/add_spec.rb
+++ /dev/null
@@ -1,60 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- # This spec defines Document#add and Document#<<
-
- describe :rexml_document_add, shared: true do
- before :each do
- @doc = REXML::Document.new("<root/>")
- @decl = REXML::XMLDecl.new("1.0")
- end
-
- it "sets document's XML declaration" do
- @doc.send(@method, @decl)
- @doc.xml_decl.should == @decl
- end
-
- it "inserts XML declaration as first node" do
- @doc.send(@method, @decl)
- @doc.children[0].version.should == "1.0"
- end
-
- it "overwrites existing XML declaration" do
- @doc.send(@method, @decl)
- @doc.send(@method, REXML::XMLDecl.new("2.0"))
- @doc.xml_decl.version.should == "2.0"
- end
-
- it "sets document DocType" do
- @doc.send(@method, REXML::DocType.new("transitional"))
- @doc.doctype.name.should == "transitional"
- end
-
- it "overwrites existing DocType" do
- @doc.send(@method, REXML::DocType.new("transitional"))
- @doc.send(@method, REXML::DocType.new("strict"))
- @doc.doctype.name.should == "strict"
- end
-
- it "adds root node unless it exists" do
- d = REXML::Document.new("")
- elem = REXML::Element.new "root"
- d.send(@method, elem)
- d.root.should == elem
- end
-
- it "refuses to add second root" do
- -> { @doc.send(@method, REXML::Element.new("foo")) }.should raise_error(RuntimeError)
- end
- end
-
- describe "REXML::Document#add" do
- it_behaves_like :rexml_document_add, :add
- end
-
- describe "REXML::Document#<<" do
- it_behaves_like :rexml_document_add, :<<
- end
-end
diff --git a/spec/ruby/library/rexml/document/clone_spec.rb b/spec/ruby/library/rexml/document/clone_spec.rb
deleted file mode 100644
index 137fe8a073..0000000000
--- a/spec/ruby/library/rexml/document/clone_spec.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- # According to the MRI documentation (http://www.ruby-doc.org/stdlib/libdoc/rexml/rdoc/index.html),
- # clone's behavior "should be obvious". Apparently "obvious" means cloning
- # only the attributes and the context of the document, not its children.
- describe "REXML::Document#clone" do
- it "clones document attributes" do
- d = REXML::Document.new("foo")
- d.attributes["foo"] = "bar"
- e = d.clone
- e.attributes.should == d.attributes
- end
-
- it "clones document context" do
- d = REXML::Document.new("foo", {"foo" => "bar"})
- e = d.clone
- e.context.should == d.context
- end
- end
-end
diff --git a/spec/ruby/library/rexml/document/doctype_spec.rb b/spec/ruby/library/rexml/document/doctype_spec.rb
deleted file mode 100644
index e1b7ba4916..0000000000
--- a/spec/ruby/library/rexml/document/doctype_spec.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Document#doctype" do
- it "returns the doctype" do
- d = REXML::Document.new
- dt = REXML::DocType.new("foo")
- d.add dt
- d.doctype.should == dt
- end
-
- it "returns nil if there's no doctype" do
- REXML::Document.new.doctype.should == nil
- end
- end
-end
diff --git a/spec/ruby/library/rexml/document/encoding_spec.rb b/spec/ruby/library/rexml/document/encoding_spec.rb
deleted file mode 100644
index 2cc947f06a..0000000000
--- a/spec/ruby/library/rexml/document/encoding_spec.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Document#encoding" do
- before :each do
- @doc = REXML::Document.new
- end
-
- it "returns encoding from XML declaration" do
- @doc.add REXML::XMLDecl.new(nil, "UTF-16", nil)
- @doc.encoding.should == "UTF-16"
- end
-
- it "returns encoding from XML declaration (for UTF-16 as well)" do
- @doc.add REXML::XMLDecl.new("1.0", "UTF-8", nil)
- @doc.encoding.should == "UTF-8"
- end
-
- it "uses UTF-8 as default encoding" do
- @doc.encoding.should == "UTF-8"
- end
- end
-end
diff --git a/spec/ruby/library/rexml/document/expanded_name_spec.rb b/spec/ruby/library/rexml/document/expanded_name_spec.rb
deleted file mode 100644
index 9d1025b5e0..0000000000
--- a/spec/ruby/library/rexml/document/expanded_name_spec.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe :document_expanded_name, shared: true do
- it "returns an empty string for root" do # root nodes have no expanded name
- REXML::Document.new.send(@method).should == ""
- end
- end
-
- describe "REXML::Document#expanded_name" do
- it_behaves_like :document_expanded_name, :expanded_name
- end
-
- describe "REXML::Document#name" do
- it_behaves_like :document_expanded_name, :name
- end
-end
diff --git a/spec/ruby/library/rexml/document/new_spec.rb b/spec/ruby/library/rexml/document/new_spec.rb
deleted file mode 100644
index 4e24b6f5a1..0000000000
--- a/spec/ruby/library/rexml/document/new_spec.rb
+++ /dev/null
@@ -1,39 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Document#new" do
-
- it "initializes context of {} unless specified" do
- d = REXML::Document.new("<foo />")
- d.context.should == {}
- end
-
- it "has empty attributes if source is nil" do
- d = REXML::Document.new(nil)
- d.elements.should be_empty
- end
-
- it "can use other document context" do
- s = REXML::Document.new("")
- d = REXML::Document.new(s)
- d.context.should == s.context
- end
-
- it "clones source attributes" do
- s = REXML::Document.new("<root />")
- s.attributes["some_attr"] = "some_val"
- d = REXML::Document.new(s)
- d.attributes.should == s.attributes
- end
-
- it "raises an error if source is not a Document, String or IO" do
- -> {REXML::Document.new(3)}.should raise_error(RuntimeError)
- end
-
- it "does not perform XML validation" do
- REXML::Document.new("Invalid document").should be_kind_of(REXML::Document)
- end
- end
-end
diff --git a/spec/ruby/library/rexml/document/node_type_spec.rb b/spec/ruby/library/rexml/document/node_type_spec.rb
deleted file mode 100644
index b6d7e7a7da..0000000000
--- a/spec/ruby/library/rexml/document/node_type_spec.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Document#node_type" do
- it "returns :document" do
- REXML::Document.new.node_type.should == :document
- end
- end
-end
diff --git a/spec/ruby/library/rexml/document/root_spec.rb b/spec/ruby/library/rexml/document/root_spec.rb
deleted file mode 100644
index 1a584a720b..0000000000
--- a/spec/ruby/library/rexml/document/root_spec.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Document#root" do
- it "returns document root tag name" do
- REXML::Document.new("<foo/>").root.name.should == "foo"
- end
-
- it "returns nil if there is not root" do
- REXML::Document.new.root.should == nil
- end
- end
-end
diff --git a/spec/ruby/library/rexml/document/stand_alone_spec.rb b/spec/ruby/library/rexml/document/stand_alone_spec.rb
deleted file mode 100644
index e1c721e782..0000000000
--- a/spec/ruby/library/rexml/document/stand_alone_spec.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Document#stand_alone?" do
- it "returns the XMLDecl standalone value" do
- d = REXML::Document.new
- decl = REXML::XMLDecl.new("1.0", "UTF-8", "yes")
- d.add decl
- d.stand_alone?.should == "yes"
- end
-
- # According to the docs this should return the default XMLDecl but that
- # will carry some more problems when printing the document. Currently, it
- # returns nil. See http://www.ruby-forum.com/topic/146812#650061
- it "returns the default value when no XML declaration present" do
- REXML::Document.new.stand_alone?.should == nil
- end
-
- end
-end
diff --git a/spec/ruby/library/rexml/document/version_spec.rb b/spec/ruby/library/rexml/document/version_spec.rb
deleted file mode 100644
index 4f6b40551b..0000000000
--- a/spec/ruby/library/rexml/document/version_spec.rb
+++ /dev/null
@@ -1,17 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Document#version" do
- it "returns XML version from declaration" do
- d = REXML::Document.new
- d.add REXML::XMLDecl.new("1.1")
- d.version.should == "1.1"
- end
-
- it "returns the default version when declaration is not present" do
- REXML::Document.new.version.should == REXML::XMLDecl::DEFAULT_VERSION
- end
- end
-end
diff --git a/spec/ruby/library/rexml/document/write_spec.rb b/spec/ruby/library/rexml/document/write_spec.rb
deleted file mode 100644
index 00c22141b3..0000000000
--- a/spec/ruby/library/rexml/document/write_spec.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
- require 'rexml/formatters/transitive'
-
- # Maybe this can be cleaned
- describe "REXML::Document#write" do
- before :each do
- @d = REXML::Document.new
- city = REXML::Element.new "Springfield"
- street = REXML::Element.new "EvergreenTerrace"
- address = REXML::Element.new "House742"
- @d << city << street << address
- @str = ""
- end
-
- it "returns document source as string" do
- @d.write(@str)
- @str.should == "<Springfield><EvergreenTerrace><House742/></EvergreenTerrace></Springfield>"
- end
-
- it "returns document indented" do
- @d.write(@str, 2)
- @str.should =~ /\s*<Springfield>\s*<EvergreenTerrace>\s*<House742\/>\s*<\/EvergreenTerrace>\s*<\/Springfield>/
- end
-
- it "returns document with transitive support" do
- @d.write(@str, 2, true)
- @str.should =~ /\s*<Springfield\s*><EvergreenTerrace\s*><House742\s*\/><\/EvergreenTerrace\s*><\/Springfield\s*>/
- end
-
- it "returns document with support for IE" do
- @d.write(@str, -1, false, true)
- @str.should == "<Springfield><EvergreenTerrace><House742 /></EvergreenTerrace></Springfield>"
- end
- end
-end
diff --git a/spec/ruby/library/rexml/document/xml_decl_spec.rb b/spec/ruby/library/rexml/document/xml_decl_spec.rb
deleted file mode 100644
index 8ac47510b0..0000000000
--- a/spec/ruby/library/rexml/document/xml_decl_spec.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Document#xml_decl" do
- it "returns XML declaration of the document" do
- d = REXML::Document.new
- decl = REXML::XMLDecl.new("1.0", "UTF-16", "yes")
- d.add decl
- d.xml_decl.should == decl
- end
-
- it "returns default XML declaration unless present" do
- REXML::Document.new.xml_decl.should == REXML::XMLDecl.new
- end
- end
-end
diff --git a/spec/ruby/library/rexml/element/add_attribute_spec.rb b/spec/ruby/library/rexml/element/add_attribute_spec.rb
deleted file mode 100644
index 64f2ec84a3..0000000000
--- a/spec/ruby/library/rexml/element/add_attribute_spec.rb
+++ /dev/null
@@ -1,44 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Element#add_attribute" do
- before :each do
- @person = REXML::Element.new "person"
- @person.attributes["name"] = "Bill"
- end
-
- it "adds a new attribute" do
- @person.add_attribute("age", "17")
- @person.attributes["age"].should == "17"
- end
-
- it "overwrites an existing attribute" do
- @person.add_attribute("name", "Bill")
- @person.attributes["name"].should == "Bill"
- end
-
- it "accepts a pair of strings" do
- @person.add_attribute("male", "true")
- @person.attributes["male"].should == "true"
- end
-
- it "accepts an Attribute for key" do
- attr = REXML::Attribute.new("male", "true")
- @person.add_attribute attr
- @person.attributes["male"].should == "true"
- end
-
- it "ignores value if key is an Attribute" do
- attr = REXML::Attribute.new("male", "true")
- @person.add_attribute(attr, "false")
- @person.attributes["male"].should == "true"
- end
-
- it "returns the attribute added" do
- attr = REXML::Attribute.new("name", "Tony")
- @person.add_attribute(attr).should == attr
- end
- end
-end
diff --git a/spec/ruby/library/rexml/element/add_attributes_spec.rb b/spec/ruby/library/rexml/element/add_attributes_spec.rb
deleted file mode 100644
index f331803dd8..0000000000
--- a/spec/ruby/library/rexml/element/add_attributes_spec.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Element#add_attributes" do
- before :each do
- @person = REXML::Element.new "person"
- @person.attributes["name"] = "Bill"
- end
-
- it "adds multiple attributes from a hash" do
- @person.add_attributes({"name" => "Joe", "age" => "27"})
- @person.attributes["name"].should == "Joe"
- @person.attributes["age"].should == "27"
- end
-
- it "adds multiple attributes from an array" do
- attrs = { "name" => "Joe", "age" => "27"}
- @person.add_attributes attrs.to_a
- @person.attributes["name"].should == "Joe"
- @person.attributes["age"].should == "27"
- end
- end
-end
diff --git a/spec/ruby/library/rexml/element/add_element_spec.rb b/spec/ruby/library/rexml/element/add_element_spec.rb
deleted file mode 100644
index 8ba023f2c7..0000000000
--- a/spec/ruby/library/rexml/element/add_element_spec.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Element#add_element" do
- before :each do
- @root = REXML::Element.new("root")
- end
-
- it "adds a child without attributes" do
- name = REXML::Element.new("name")
- @root.add_element name
- @root.elements["name"].name.should == name.name
- @root.elements["name"].attributes.should == name.attributes
- @root.elements["name"].context.should == name.context
- end
-
- it "adds a child with attributes" do
- person = REXML::Element.new("person")
- @root.add_element(person, {"name" => "Madonna"})
- @root.elements["person"].name.should == person.name
- @root.elements["person"].attributes.should == person.attributes
- @root.elements["person"].context.should == person.context
- end
-
- it "adds a child with name" do
- @root.add_element "name"
- @root.elements["name"].name.should == "name"
- @root.elements["name"].attributes.should == {}
- @root.elements["name"].context.should == nil
- end
-
- it "returns the added child" do
- name = @root.add_element "name"
- @root.elements["name"].name.should == name.name
- @root.elements["name"].attributes.should == name.attributes
- @root.elements["name"].context.should == name.context
- end
- end
-end
diff --git a/spec/ruby/library/rexml/element/add_namespace_spec.rb b/spec/ruby/library/rexml/element/add_namespace_spec.rb
deleted file mode 100644
index 44b074bac7..0000000000
--- a/spec/ruby/library/rexml/element/add_namespace_spec.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Element#add_namespace" do
- before :each do
- @elem = REXML::Element.new("person")
- end
-
- it "adds a namespace to element" do
- @elem.add_namespace("foo", "bar")
- @elem.namespace("foo").should == "bar"
- end
-
- it "accepts a prefix string as prefix" do
- @elem.add_namespace("xmlns:foo", "bar")
- @elem.namespace("foo").should == "bar"
- end
-
- it "uses prefix as URI if uri is nil" do
- @elem.add_namespace("some_uri", nil)
- @elem.namespace.should == "some_uri"
- end
- end
-end
diff --git a/spec/ruby/library/rexml/element/add_text_spec.rb b/spec/ruby/library/rexml/element/add_text_spec.rb
deleted file mode 100644
index 3a0531ad42..0000000000
--- a/spec/ruby/library/rexml/element/add_text_spec.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Element#add_text" do
- before :each do
- @name = REXML::Element.new "Name"
- end
-
- it "adds text to an element" do
- @name.add_text "Ringo"
- @name.to_s.should == "<Name>Ringo</Name>"
- end
-
- it "accepts a Text" do
- @name.add_text(REXML::Text.new("Ringo"))
- @name.to_s.should == "<Name>Ringo</Name>"
- end
-
- it "joins the new text with the old one" do
- @name.add_text "Ringo"
- @name.add_text " Starr"
- @name.to_s.should == "<Name>Ringo Starr</Name>"
- end
- end
-end
diff --git a/spec/ruby/library/rexml/element/attribute_spec.rb b/spec/ruby/library/rexml/element/attribute_spec.rb
deleted file mode 100644
index b223d3440c..0000000000
--- a/spec/ruby/library/rexml/element/attribute_spec.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Element#attribute" do
- it "returns an attribute by name" do
- person = REXML::Element.new "Person"
- attribute = REXML::Attribute.new("drink", "coffee")
- person.add_attribute(attribute)
- person.attribute("drink").should == attribute
- end
-
- it "supports attributes inside namespaces" do
- e = REXML::Element.new("element")
- e.add_attributes({"xmlns:ns" => "http://some_uri"})
- e.attribute("ns", "ns").to_s.should == "http://some_uri"
- end
- end
-end
diff --git a/spec/ruby/library/rexml/element/attributes_spec.rb b/spec/ruby/library/rexml/element/attributes_spec.rb
deleted file mode 100644
index 92bcecc40a..0000000000
--- a/spec/ruby/library/rexml/element/attributes_spec.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Element#attributes" do
- it "returns element's Attributes" do
- p = REXML::Element.new "Person"
-
- name = REXML::Attribute.new("name", "John")
- attrs = REXML::Attributes.new(p)
- attrs.add name
-
- p.add_attribute name
- p.attributes.should == attrs
- end
-
- it "returns an empty hash if element has no attributes" do
- REXML::Element.new("Person").attributes.should == {}
- end
- end
-end
diff --git a/spec/ruby/library/rexml/element/cdatas_spec.rb b/spec/ruby/library/rexml/element/cdatas_spec.rb
deleted file mode 100644
index 988b2cb422..0000000000
--- a/spec/ruby/library/rexml/element/cdatas_spec.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Element#cdatas" do
- before :each do
- @e = REXML::Element.new("Root")
- end
-
- it "returns the array of children cdatas" do
- c = REXML::CData.new("Primary")
- d = REXML::CData.new("Secondary")
- @e << c
- @e << d
- @e.cdatas.should == [c, d]
- end
-
- it "freezes the returned array" do
- @e.cdatas.should.frozen?
- end
-
- it "returns an empty array if element has no cdata" do
- @e.cdatas.should == []
- end
- end
-end
diff --git a/spec/ruby/library/rexml/element/clone_spec.rb b/spec/ruby/library/rexml/element/clone_spec.rb
deleted file mode 100644
index 490e43181f..0000000000
--- a/spec/ruby/library/rexml/element/clone_spec.rb
+++ /dev/null
@@ -1,32 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Element#clone" do
- before :each do
- @e = REXML::Element.new "a"
- end
- it "creates a copy of element" do
- @e.clone.to_s.should == @e.to_s
- end
-
- it "copies the attributes" do
- @e.add_attribute("foo", "bar")
- @e.clone.to_s.should == @e.to_s
- end
-
- it "does not copy the text" do
- @e.add_text "some text..."
- @e.clone.to_s.should_not == @e
- @e.clone.to_s.should == "<a/>"
- end
-
- it "does not copy the child elements" do
- b = REXML::Element.new "b"
- @e << b
- @e.clone.should_not == @e
- @e.clone.to_s.should == "<a/>"
- end
- end
-end
diff --git a/spec/ruby/library/rexml/element/comments_spec.rb b/spec/ruby/library/rexml/element/comments_spec.rb
deleted file mode 100644
index 84ab9a7469..0000000000
--- a/spec/ruby/library/rexml/element/comments_spec.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Element#comments" do
- before :each do
- @e = REXML::Element.new "root"
- @c1 = REXML::Comment.new "this is a comment"
- @c2 = REXML::Comment.new "this is another comment"
- @e << @c1
- @e << @c2
- end
-
- it "returns the array of comments" do
- @e.comments.should == [@c1, @c2]
- end
-
- it "returns a frozen object" do
- @e.comments.should.frozen?
- end
- end
-end
diff --git a/spec/ruby/library/rexml/element/delete_attribute_spec.rb b/spec/ruby/library/rexml/element/delete_attribute_spec.rb
deleted file mode 100644
index e2ba81eb0d..0000000000
--- a/spec/ruby/library/rexml/element/delete_attribute_spec.rb
+++ /dev/null
@@ -1,42 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Element#delete_attribute" do
- before :each do
- @e = REXML::Element.new("Person")
- @attr = REXML::Attribute.new("name", "Sean")
- @e.add_attribute(@attr)
- end
-
- it "deletes an attribute from the element" do
- @e.delete_attribute("name")
- @e.attributes["name"].should be_nil
- end
-
- # Bug was filled with a patch in Ruby's tracker #20298
- quarantine! do
- it "receives an Attribute" do
- @e.add_attribute(@attr)
- @e.delete_attribute(@attr)
- @e.attributes["name"].should be_nil
- end
- end
-
- # Docs say that it returns the removed attribute but then examples
- # show it returns the element with the attribute removed.
- # Also fixed in #20298
- it "returns the element with the attribute removed" do
- elem = @e.delete_attribute("name")
- elem.attributes.should be_empty
- elem.to_s.should eql("<Person/>")
- end
-
- it "returns nil if the attribute does not exist" do
- @e.delete_attribute("name")
- at = @e.delete_attribute("name")
- at.should be_nil
- end
- end
-end
diff --git a/spec/ruby/library/rexml/element/delete_element_spec.rb b/spec/ruby/library/rexml/element/delete_element_spec.rb
deleted file mode 100644
index c0b486a6f7..0000000000
--- a/spec/ruby/library/rexml/element/delete_element_spec.rb
+++ /dev/null
@@ -1,52 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Element#delete_element" do
- before :each do
- @root = REXML::Element.new("root")
- end
-
- it "deletes the child element" do
- node = REXML::Element.new("some_node")
- @root.add_element node
- @root.delete_element node
- @root.elements.size.should == 0
- end
-
- it "deletes a child via XPath" do
- @root.add_element "some_node"
- @root.delete_element "some_node"
- @root.elements.size.should == 0
- end
-
- it "deletes the child at index" do
- @root.add_element "some_node"
- @root.delete_element 1
- @root.elements.size.should == 0
- end
-
- # According to the docs this should return the deleted element
- # but it won't if it's an Element.
- it "deletes Element and returns it" do
- node = REXML::Element.new("some_node")
- @root.add_element node
- del_node = @root.delete_element node
- del_node.should == node
- end
-
- # Note how passing the string will return the removed element
- # but passing the Element as above won't.
- it "deletes an element and returns it" do
- node = REXML::Element.new("some_node")
- @root.add_element node
- del_node = @root.delete_element "some_node"
- del_node.should == node
- end
-
- it "returns nil unless element exists" do
- @root.delete_element("something").should == nil
- end
- end
-end
diff --git a/spec/ruby/library/rexml/element/delete_namespace_spec.rb b/spec/ruby/library/rexml/element/delete_namespace_spec.rb
deleted file mode 100644
index a7763d51e8..0000000000
--- a/spec/ruby/library/rexml/element/delete_namespace_spec.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Element#delete_namespace" do
-
- before :each do
- @doc = REXML::Document.new "<a xmlns:foo='bar' xmlns='twiddle'/>"
- end
-
- it "deletes a namespace from the element" do
- @doc.root.delete_namespace 'foo'
- @doc.root.namespace("foo").should be_nil
- @doc.root.to_s.should == "<a xmlns='twiddle'/>"
- end
-
- it "deletes default namespace when called with no args" do
- @doc.root.delete_namespace
- @doc.root.namespace.should be_empty
- @doc.root.to_s.should == "<a xmlns:foo='bar'/>"
- end
-
- it "returns the element" do
- @doc.root.delete_namespace.should == @doc.root
- end
- end
-end
diff --git a/spec/ruby/library/rexml/element/document_spec.rb b/spec/ruby/library/rexml/element/document_spec.rb
deleted file mode 100644
index 754f27d8a0..0000000000
--- a/spec/ruby/library/rexml/element/document_spec.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Element#document" do
-
- it "returns the element's document" do
- d = REXML::Document.new("<root><elem/></root>")
- d << REXML::XMLDecl.new
- d.root.document.should == d
- d.root.document.to_s.should == d.to_s
- end
-
- it "returns nil if it belongs to no document" do
- REXML::Element.new("standalone").document.should be_nil
- end
- end
-end
diff --git a/spec/ruby/library/rexml/element/each_element_with_attribute_spec.rb b/spec/ruby/library/rexml/element/each_element_with_attribute_spec.rb
deleted file mode 100644
index dcc6dbbf17..0000000000
--- a/spec/ruby/library/rexml/element/each_element_with_attribute_spec.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Element#each_element_with_attributes" do
- before :each do
- @document = REXML::Element.new("people")
- @father = REXML::Element.new("Person")
- @father.attributes["name"] = "Joe"
- @son = REXML::Element.new("Child")
- @son.attributes["name"] = "Fred"
- @document.root << @father
- @document.root << @son
- @children = []
- end
-
- it "returns children with attribute" do
- @document.each_element_with_attribute("name") { |elem| @children << elem }
- @children[0].should == @father
- @children[1].should == @son
- end
-
- it "takes attribute value as second argument" do
- @document.each_element_with_attribute("name", "Fred"){ |elem| elem.should == @son }
- end
-
- it "takes max number of children as third argument" do
- @document.each_element_with_attribute("name", nil, 1) { |elem| @children << elem }
- @children.size.should == 1
- @children[0].should == @father
- end
-
- it "takes XPath filter as fourth argument" do
- @document.each_element_with_attribute("name", nil, 0, "Child"){ |elem| elem.should == @son}
- end
- end
-end
diff --git a/spec/ruby/library/rexml/element/each_element_with_text_spec.rb b/spec/ruby/library/rexml/element/each_element_with_text_spec.rb
deleted file mode 100644
index a4a200d237..0000000000
--- a/spec/ruby/library/rexml/element/each_element_with_text_spec.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Element#each_element_with_text" do
- before :each do
- @document = REXML::Element.new("people")
-
- @joe = REXML::Element.new("Person")
- @joe.text = "Joe"
- @fred = REXML::Element.new("Person")
- @fred.text = "Fred"
- @another = REXML::Element.new("AnotherPerson")
- @another.text = "Fred"
- @document.root << @joe
- @document.root << @fred
- @document.root << @another
- @children = []
- end
-
- it "returns children with text" do
- @document.each_element_with_text("Joe"){|c| c.should == @joe}
- end
-
- it "takes max as second argument" do
- @document.each_element_with_text("Fred", 1){ |c| c.should == @fred}
- end
-
- it "takes XPath filter as third argument" do
- @document.each_element_with_text("Fred", 0, "Person"){ |c| c.should == @fred}
- end
- end
-end
diff --git a/spec/ruby/library/rexml/element/element_reference_spec.rb b/spec/ruby/library/rexml/element/element_reference_spec.rb
deleted file mode 100644
index 9e5d371ce4..0000000000
--- a/spec/ruby/library/rexml/element/element_reference_spec.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Element#[]" do
-
- before :each do
- @doc = REXML::Document.new("<root foo='bar'></root>")
- @child = REXML::Element.new("child")
- @doc.root.add_element @child
- end
-
- it "return attribute value if argument is string or symbol" do
- @doc.root[:foo].should == 'bar'
- @doc.root['foo'].should == 'bar'
- end
-
- it "return nth element if argument is int" do
- @doc.root[0].should == @child
- end
- end
-end
diff --git a/spec/ruby/library/rexml/element/get_text_spec.rb b/spec/ruby/library/rexml/element/get_text_spec.rb
deleted file mode 100644
index 0fa8d7cb3f..0000000000
--- a/spec/ruby/library/rexml/element/get_text_spec.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Element#get_text" do
- before :each do
- @doc = REXML::Document.new "<p>some text<b>this is bold!</b> more text</p>"
- end
-
- it "returns the first text child node" do
- @doc.root.get_text.value.should == "some text"
- @doc.root.get_text.should be_kind_of(REXML::Text)
- end
-
- it "returns text from an element matching path" do
- @doc.root.get_text("b").value.should == "this is bold!"
- @doc.root.get_text("b").should be_kind_of(REXML::Text)
- end
- end
-end
diff --git a/spec/ruby/library/rexml/element/has_attributes_spec.rb b/spec/ruby/library/rexml/element/has_attributes_spec.rb
deleted file mode 100644
index af3ce8ce1b..0000000000
--- a/spec/ruby/library/rexml/element/has_attributes_spec.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Element#has_attributes?" do
- before :each do
- @e = REXML::Element.new("test_elem")
- end
-
- it "returns true when element has any attributes" do
- @e.add_attribute("name", "Joe")
- @e.has_attributes?.should be_true
- end
-
- it "returns false if element has no attributes" do
- @e.has_attributes?.should be_false
- end
- end
-end
diff --git a/spec/ruby/library/rexml/element/has_elements_spec.rb b/spec/ruby/library/rexml/element/has_elements_spec.rb
deleted file mode 100644
index 04c7fe01a5..0000000000
--- a/spec/ruby/library/rexml/element/has_elements_spec.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Element#has_elements?" do
- before :each do
- @e = REXML::Element.new("root")
- end
-
- it "returns true if element has child elements" do
- child = REXML::Element.new("child")
- @e << child
- @e.has_elements?.should be_true
- end
-
- it "returns false if element doesn't have child elements" do
- @e.has_elements?.should be_false
- end
- end
-end
diff --git a/spec/ruby/library/rexml/element/has_text_spec.rb b/spec/ruby/library/rexml/element/has_text_spec.rb
deleted file mode 100644
index 206c167ae6..0000000000
--- a/spec/ruby/library/rexml/element/has_text_spec.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Element#has_text?" do
-
- it "returns true if element has a Text child" do
- e = REXML::Element.new("Person")
- e.text = "My text"
- e.has_text?.should be_true
- end
-
- it "returns false if it has no Text children" do
- e = REXML::Element.new("Person")
- e.has_text?.should be_false
- end
- end
-end
diff --git a/spec/ruby/library/rexml/element/inspect_spec.rb b/spec/ruby/library/rexml/element/inspect_spec.rb
deleted file mode 100644
index ec16c136ee..0000000000
--- a/spec/ruby/library/rexml/element/inspect_spec.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Element#inspect" do
-
- before :each do
- @name = REXML::Element.new "name"
- end
-
- it "returns the node as a string" do
- @name.inspect.should == "<name/>"
- end
-
- it "inserts '...' if the node has children" do
- e = REXML::Element.new "last_name"
- @name << e
- @name.inspect.should == "<name> ... </>"
- # This might make more sense but differs from MRI's default behavior
- # @name.inspect.should == "<name> ... </name>"
- end
-
- it "inserts the attributes in the string" do
- @name.add_attribute "language"
- @name.attributes["language"] = "english"
- @name.inspect.should == "<name language='english'/>"
- end
- end
-end
diff --git a/spec/ruby/library/rexml/element/instructions_spec.rb b/spec/ruby/library/rexml/element/instructions_spec.rb
deleted file mode 100644
index 11f1396df0..0000000000
--- a/spec/ruby/library/rexml/element/instructions_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Element#instructions" do
- before :each do
- @elem = REXML::Element.new("root")
- end
- it "returns the Instruction children nodes" do
- inst = REXML::Instruction.new("xml-stylesheet", "href='headlines.css'")
- @elem << inst
- @elem.instructions.first.should == inst
- end
-
- it "returns an empty array if it has no Instruction children" do
- @elem.instructions.should be_empty
- end
-
- it "freezes the returned array" do
- @elem.instructions.frozen?.should be_true
- end
- end
-end
diff --git a/spec/ruby/library/rexml/element/namespace_spec.rb b/spec/ruby/library/rexml/element/namespace_spec.rb
deleted file mode 100644
index 28966289c5..0000000000
--- a/spec/ruby/library/rexml/element/namespace_spec.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Element#namespace" do
- before :each do
- @doc = REXML::Document.new("<a xmlns='1' xmlns:y='2'><b/><c xmlns:z='3'/></a>")
- @elem = @doc.elements["//b"]
- end
-
- it "returns the default namespace" do
- @elem.namespace.should == "1"
- end
-
- it "accepts a namespace prefix" do
- @elem.namespace("y").should == "2"
- @doc.elements["//c"].namespace("z").should == "3"
- end
-
- it "returns an empty String if default namespace is not defined" do
- e = REXML::Document.new("<a/>")
- e.root.namespace.should be_empty
- end
-
- it "returns nil if namespace is not defined" do
- @elem.namespace("z").should be_nil
- end
- end
-end
diff --git a/spec/ruby/library/rexml/element/namespaces_spec.rb b/spec/ruby/library/rexml/element/namespaces_spec.rb
deleted file mode 100644
index 4544540173..0000000000
--- a/spec/ruby/library/rexml/element/namespaces_spec.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Element#namespaces" do
- before :each do
- doc = REXML::Document.new("<a xmlns='1' xmlns:y='2'><b/><c xmlns:z='3'/></a>")
- @elem = doc.elements["//c"]
- end
-
- it "returns a hash of the namespaces" do
- ns = {"y"=>"2", "z"=>"3", "xmlns"=>"1"}
- @elem.namespaces.keys.sort.should == ns.keys.sort
- @elem.namespaces.values.sort.should == ns.values.sort
- end
-
- it "returns an empty hash if no namespaces exist" do
- e = REXML::Element.new "element"
- e.namespaces.kind_of?(Hash).should == true
- e.namespaces.should be_empty
- end
-
- it "uses namespace prefixes as keys" do
- prefixes = ["y", "z", "xmlns"]
- @elem.namespaces.keys.sort.should == prefixes.sort
- end
-
- it "uses namespace values as the hash values" do
- values = ["2", "3", "1"]
- @elem.namespaces.values.sort.should == values.sort
- end
-
- end
-end
diff --git a/spec/ruby/library/rexml/element/new_spec.rb b/spec/ruby/library/rexml/element/new_spec.rb
deleted file mode 100644
index c6ab289476..0000000000
--- a/spec/ruby/library/rexml/element/new_spec.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Element#new" do
-
- it "creates element from tag name" do
- REXML::Element.new("foo").name.should == "foo"
- end
-
- it "creates element with default attributes" do
- e = REXML::Element.new
- e.name.should == REXML::Element::UNDEFINED
- e.context.should == nil
- e.parent.should == nil
- end
-
- it "creates element from another element" do
- e = REXML::Element.new "foo"
- f = REXML::Element.new e
- e.name.should == f.name
- e.context.should == f.context
- e.parent.should == f.parent
- end
-
- it "takes parent as second argument" do
- parent = REXML::Element.new "foo"
- child = REXML::Element.new "bar", parent
- child.parent.should == parent
- end
-
- it "takes context as third argument" do
- context = {"some_key" => "some_value"}
- REXML::Element.new("foo", nil, context).context.should == context
- end
- end
-end
diff --git a/spec/ruby/library/rexml/element/next_element_spec.rb b/spec/ruby/library/rexml/element/next_element_spec.rb
deleted file mode 100644
index 46d8f74760..0000000000
--- a/spec/ruby/library/rexml/element/next_element_spec.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Element#next_element" do
- before :each do
- @a = REXML::Element.new "a"
- @b = REXML::Element.new "b"
- @c = REXML::Element.new "c"
- @a.root << @b
- @a.root << @c
- end
- it "returns next existing element" do
- @a.elements["b"].next_element.should == @c
- end
-
- it "returns nil on last element" do
- @a.elements["c"].next_element.should == nil
- end
- end
-end
diff --git a/spec/ruby/library/rexml/element/node_type_spec.rb b/spec/ruby/library/rexml/element/node_type_spec.rb
deleted file mode 100644
index a39c2deca5..0000000000
--- a/spec/ruby/library/rexml/element/node_type_spec.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Element#node_type" do
- it "returns :element" do
- REXML::Element.new("MyElem").node_type.should == :element
- end
- end
-end
diff --git a/spec/ruby/library/rexml/element/prefixes_spec.rb b/spec/ruby/library/rexml/element/prefixes_spec.rb
deleted file mode 100644
index ea4caab4bc..0000000000
--- a/spec/ruby/library/rexml/element/prefixes_spec.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Element#prefixes" do
- before :each do
- doc = REXML::Document.new("<a xmlns='1' xmlns:y='2'><b/><c xmlns:z='3'/></a>")
- @elem = doc.elements["//c"]
- end
-
- it "returns an array of the prefixes of the namespaces" do
- @elem.prefixes.should == ["y", "z"]
- end
-
- it "does not include the default namespace" do
- @elem.prefixes.include?("xmlns").should == false
- end
-
- it "returns an empty array if no namespace was defined" do
- doc = REXML::Document.new "<root><something/></root>"
- root = doc.elements["//root"]
- root.prefixes.should == []
- end
- end
-end
diff --git a/spec/ruby/library/rexml/element/previous_element_spec.rb b/spec/ruby/library/rexml/element/previous_element_spec.rb
deleted file mode 100644
index a43b1ddd10..0000000000
--- a/spec/ruby/library/rexml/element/previous_element_spec.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Element#previous_element" do
- before :each do
- @a = REXML::Element.new "a"
- @b = REXML::Element.new "b"
- @c = REXML::Element.new "c"
- @a.root << @b
- @a.root << @c
- end
-
- it "returns previous element" do
- @a.elements["c"].previous_element.should == @b
- end
-
- it "returns nil on first element" do
- @a.elements["b"].previous_element.should == nil
- end
- end
-end
diff --git a/spec/ruby/library/rexml/element/raw_spec.rb b/spec/ruby/library/rexml/element/raw_spec.rb
deleted file mode 100644
index 200a99d194..0000000000
--- a/spec/ruby/library/rexml/element/raw_spec.rb
+++ /dev/null
@@ -1,27 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Element#raw" do
- it "returns true if raw mode is set to all" do
- REXML::Element.new("MyElem", nil, {raw: :all}).raw.should == true
- end
-
- it "returns true if raw mode is set to expanded_name" do
- REXML::Element.new("MyElem", nil, {raw: "MyElem"}).raw.should == true
- end
-
- it "returns false if raw mode is not set" do
- REXML::Element.new("MyElem", nil, {raw: ""}).raw.should == false
- end
-
- it "returns false if raw is not :all or expanded_name" do
- REXML::Element.new("MyElem", nil, {raw: "Something"}).raw.should == false
- end
-
- it "returns nil if context is not set" do
- REXML::Element.new("MyElem").raw.should == nil
- end
- end
-end
diff --git a/spec/ruby/library/rexml/element/root_spec.rb b/spec/ruby/library/rexml/element/root_spec.rb
deleted file mode 100644
index 52aa4571b9..0000000000
--- a/spec/ruby/library/rexml/element/root_spec.rb
+++ /dev/null
@@ -1,31 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Element#root" do
- before :each do
- @doc = REXML::Document.new
- @root = REXML::Element.new "root"
- @node = REXML::Element.new "node"
- @doc << @root << @node
- end
-
- it "returns first child on documents" do
- @doc.root.should == @root
- end
-
- it "returns self on root nodes" do
- @root.root.should == @root
- end
-
- it "returns parent's root on child nodes" do
- @node.root.should == @root
- end
-
- it "returns self on standalone nodes" do
- e = REXML::Element.new "Elem" # Note that it doesn't have a parent node
- e.root.should == e
- end
- end
-end
diff --git a/spec/ruby/library/rexml/element/text_spec.rb b/spec/ruby/library/rexml/element/text_spec.rb
deleted file mode 100644
index 3234bba153..0000000000
--- a/spec/ruby/library/rexml/element/text_spec.rb
+++ /dev/null
@@ -1,49 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Element#text" do
- before :each do
- @e = REXML::Element.new "name"
- @e.text = "John"
- end
-
- it "returns the text node of element" do
- @e.text.should == "John"
- end
-
- it "returns the text node value" do
- t = REXML::Text.new "Joe"
- @e.text = t
- @e.text.should == "Joe"
- @e.text.should_not == t
- end
-
- it "returns nil if no text is attached" do
- elem = REXML::Element.new "name"
- elem.text.should == nil
- end
- end
-
- describe "REXML::Element#text=" do
- before :each do
- @e = REXML::Element.new "name"
- @e.text = "John"
- end
-
- it "sets the text node" do
- @e.to_s.should == "<name>John</name>"
- end
-
- it "replaces existing text" do
- @e.text = "Joe"
- @e.to_s.should == "<name>Joe</name>"
- end
-
- it "receives nil as an argument" do
- @e.text = nil
- @e.to_s.should == "<name/>"
- end
- end
-end
diff --git a/spec/ruby/library/rexml/element/texts_spec.rb b/spec/ruby/library/rexml/element/texts_spec.rb
deleted file mode 100644
index 2d374d5e66..0000000000
--- a/spec/ruby/library/rexml/element/texts_spec.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Element#texts" do
-
- it "returns an array of the Text children" do
- e = REXML::Element.new("root")
- e.add_text "First"
- e.add_text "Second"
- e.texts.should == ["FirstSecond"]
- end
-
- it "returns an empty array if it has no Text children" do
- REXML::Element.new("root").texts.should == []
- end
- end
-end
diff --git a/spec/ruby/library/rexml/element/whitespace_spec.rb b/spec/ruby/library/rexml/element/whitespace_spec.rb
deleted file mode 100644
index f455067922..0000000000
--- a/spec/ruby/library/rexml/element/whitespace_spec.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Element#whitespace" do
- it "returns true if whitespace is respected in the element" do
- e = REXML::Element.new("root")
- e.whitespace.should be_true
-
- e = REXML::Element.new("root", nil, respect_whitespace: :all)
- e.whitespace.should be_true
-
- e = REXML::Element.new("root", nil, respect_whitespace: ["root"])
- e.whitespace.should be_true
- end
-
- it "returns false if whitespace is ignored inside element" do
- e = REXML::Element.new("root", nil, compress_whitespace: :all)
- e.whitespace.should be_false
-
- e = REXML::Element.new("root", nil, compress_whitespace: ["root"])
- e.whitespace.should be_false
- end
- end
-end
diff --git a/spec/ruby/library/rexml/node/each_recursive_spec.rb b/spec/ruby/library/rexml/node/each_recursive_spec.rb
deleted file mode 100644
index da347b1389..0000000000
--- a/spec/ruby/library/rexml/node/each_recursive_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Node#each_recursive" do
- before :each do
- @doc = REXML::Document.new
- @doc << REXML::XMLDecl.new
- @root = REXML::Element.new "root"
- @child1 = REXML::Element.new "child1"
- @child2 = REXML::Element.new "child2"
- @root << @child1
- @root << @child2
- @doc << @root
- end
-
- it "visits all subnodes of self" do
- nodes = []
- @doc.each_recursive { |node| nodes << node}
- nodes.should == [@root, @child1, @child2]
- end
- end
-end
diff --git a/spec/ruby/library/rexml/node/find_first_recursive_spec.rb b/spec/ruby/library/rexml/node/find_first_recursive_spec.rb
deleted file mode 100644
index 2a4f1097ae..0000000000
--- a/spec/ruby/library/rexml/node/find_first_recursive_spec.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Node#find_first_recursive" do
- before :each do
- @e = REXML::Element.new("root")
- @node1 = REXML::Element.new("node")
- @node2 = REXML::Element.new("another node")
- @subnode = REXML::Element.new("another node")
- @node1 << @subnode
- @e << @node1
- @e << @node2
- end
-
- it "finds the first element that matches block" do
- found = @e.find_first_recursive { |n| n.to_s == "<node><another node/></node>"}
- found.should == @node1
- end
-
- it "visits the nodes in preorder" do
- found = @e.find_first_recursive { |n| n.to_s == "<another node/>"}
- found.should == @subnode
- found.should_not == @node2
- end
- end
-end
diff --git a/spec/ruby/library/rexml/node/index_in_parent_spec.rb b/spec/ruby/library/rexml/node/index_in_parent_spec.rb
deleted file mode 100644
index 55909f86d6..0000000000
--- a/spec/ruby/library/rexml/node/index_in_parent_spec.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Node#index_in_parent" do
- it "returns the index (starting from 1) of self in parent" do
- e = REXML::Element.new("root")
- node1 = REXML::Element.new("node")
- node2 = REXML::Element.new("another node")
- e << node1
- e << node2
-
- node1.index_in_parent.should == 1
- node2.index_in_parent.should == 2
- end
- end
-end
diff --git a/spec/ruby/library/rexml/node/next_sibling_node_spec.rb b/spec/ruby/library/rexml/node/next_sibling_node_spec.rb
deleted file mode 100644
index 7aae861d75..0000000000
--- a/spec/ruby/library/rexml/node/next_sibling_node_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Node#next_sibling_node" do
- before :each do
- @e = REXML::Element.new("root")
- @node1 = REXML::Element.new("node")
- @node2 = REXML::Element.new("another node")
- @e << @node1
- @e << @node2
- end
-
- it "returns the next child node in parent" do
- @node1.next_sibling_node.should == @node2
- end
-
- it "returns nil if there are no more child nodes next" do
- @node2.next_sibling_node.should == nil
- @e.next_sibling_node.should == nil
- end
- end
-end
diff --git a/spec/ruby/library/rexml/node/parent_spec.rb b/spec/ruby/library/rexml/node/parent_spec.rb
deleted file mode 100644
index 43c3a747e0..0000000000
--- a/spec/ruby/library/rexml/node/parent_spec.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Node#parent?" do
- it "returns true for Elements" do
- e = REXML::Element.new("foo")
- e.should.parent?
- end
-
- it "returns true for Documents" do
- e = REXML::Document.new
- e.should.parent?
- end
-
- # This includes attributes, CData and declarations.
- it "returns false for Texts" do
- e = REXML::Text.new("foo")
- e.should_not.parent?
- end
- end
-end
diff --git a/spec/ruby/library/rexml/node/previous_sibling_node_spec.rb b/spec/ruby/library/rexml/node/previous_sibling_node_spec.rb
deleted file mode 100644
index 11263968a7..0000000000
--- a/spec/ruby/library/rexml/node/previous_sibling_node_spec.rb
+++ /dev/null
@@ -1,24 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Node#previous_sibling_node" do
- before :each do
- @e = REXML::Element.new("root")
- @node1 = REXML::Element.new("node")
- @node2 = REXML::Element.new("another node")
- @e << @node1
- @e << @node2
- end
-
- it "returns the previous child node in parent" do
- @node2.previous_sibling_node.should == @node1
- end
-
- it "returns nil if there are no more child nodes before" do
- @node1.previous_sibling_node.should == nil
- @e.previous_sibling_node.should == nil
- end
- end
-end
diff --git a/spec/ruby/library/rexml/shared/each_element.rb b/spec/ruby/library/rexml/shared/each_element.rb
deleted file mode 100644
index 2e0871161d..0000000000
--- a/spec/ruby/library/rexml/shared/each_element.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-require 'rexml/document'
-require_relative '../../../spec_helper'
-
-describe :rexml_each_element, shared: true do
- before :each do
- @e = REXML::Element.new "root"
- s1 = REXML::Element.new "node1"
- s2 = REXML::Element.new "node2"
- s3 = REXML::Element.new "node3"
- s4 = REXML::Element.new "sub_node"
- @e << s1
- @e << s2
- @e << s3
- @e << s4
- end
-
- it "iterates through element" do
- str = ""
- @e.send(@method) { |elem| str << elem.name << " " }
- str.should == "node1 node2 node3 sub_node "
- end
-
- it "iterates through element filtering with XPath" do
- str = ""
- @e.send(@method, "/*"){ |e| str << e.name << " "}
- str.should == "node1 node2 node3 sub_node "
- end
-end
-
-describe "REXML::Element#each_element" do
- it_behaves_like :rexml_each_element, :each_element
-end
-
-describe "REXML::Elements#each" do
- it_behaves_like :rexml_each_element, :each
-end
diff --git a/spec/ruby/library/rexml/shared/elements_to_a.rb b/spec/ruby/library/rexml/shared/elements_to_a.rb
deleted file mode 100644
index b7169f0b2e..0000000000
--- a/spec/ruby/library/rexml/shared/elements_to_a.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-require 'rexml/document'
-require_relative '../../../spec_helper'
-
-describe :rexml_elements_to_a, shared: true do
- before :each do
- @e = REXML::Element.new "root"
- @first = REXML::Element.new("FirstChild")
- @second = REXML::Element.new("SecondChild")
- @e << @first
- @e << @second
- end
-
- it "returns elements that match xpath" do
- @e.elements.send(@method, "FirstChild").first.should == @first
- end
-
- # According to the docs REXML::Element#get_elements is an alias for
- # REXML::Elements.to_a. Implementation wise there's a difference, get_elements
- # always needs the first param (even if it's nil).
- # A patch was submitted:
- # http://rubyforge.org/tracker/index.php?func=detail&aid=19354&group_id=426&atid=1698
- it "returns all children if xpath is nil" do
- @e.elements.send(@method).should == [@first, @second]
- end
-
-end
-
-describe "REXML::REXML::Elements#to_a" do
- it_behaves_like :rexml_elements_to_a, :to_a
-end
-
-describe "REXML::REXML::Element#get_elements" do
- it_behaves_like :rexml_elements_to_a, :get_elements
-end
diff --git a/spec/ruby/library/rexml/text/append_spec.rb b/spec/ruby/library/rexml/text/append_spec.rb
deleted file mode 100644
index 5e7a5bae7c..0000000000
--- a/spec/ruby/library/rexml/text/append_spec.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Text#<<" do
- it "appends a string to this text node" do
- text = REXML::Text.new("foo")
- text << "bar"
- text.should == "foobar"
- end
- end
-end
diff --git a/spec/ruby/library/rexml/text/clone_spec.rb b/spec/ruby/library/rexml/text/clone_spec.rb
deleted file mode 100644
index 7801782ff5..0000000000
--- a/spec/ruby/library/rexml/text/clone_spec.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Text#clone" do
- it "creates a copy of this node" do
- text = REXML::Text.new("foo")
- text.clone.should == "foo"
- text.clone.should == text
- end
- end
-end
diff --git a/spec/ruby/library/rexml/text/comparison_spec.rb b/spec/ruby/library/rexml/text/comparison_spec.rb
deleted file mode 100644
index 119dd050a6..0000000000
--- a/spec/ruby/library/rexml/text/comparison_spec.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Text#<=>" do
- before :each do
- @first = REXML::Text.new("abc")
- @last = REXML::Text.new("def")
- end
-
- it "returns -1 if lvalue is less than rvalue" do
- val = @first <=> @last
- val.should == -1
- end
-
- it "returns -1 if lvalue is greater than rvalue" do
- val = @last <=> @first
- val.should == 1
- end
-
- it "returns 0 if both values are equal" do
- tmp = REXML::Text.new("tmp")
- val = tmp <=> tmp
- val.should == 0
- end
- end
-end
diff --git a/spec/ruby/library/rexml/text/empty_spec.rb b/spec/ruby/library/rexml/text/empty_spec.rb
deleted file mode 100644
index 4c9c899bcb..0000000000
--- a/spec/ruby/library/rexml/text/empty_spec.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Text#empty?" do
- it "returns true if the text is empty" do
- REXML::Text.new("").should.empty?
- end
-
- it "returns false if the text is not empty" do
- REXML::Text.new("some_text").should_not.empty?
- end
- end
-end
diff --git a/spec/ruby/library/rexml/text/indent_text_spec.rb b/spec/ruby/library/rexml/text/indent_text_spec.rb
deleted file mode 100644
index 73065c37da..0000000000
--- a/spec/ruby/library/rexml/text/indent_text_spec.rb
+++ /dev/null
@@ -1,26 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Text#indent_text" do
- before :each do
- @t = REXML::Text.new("")
- end
- it "indents a string with default parameters" do
- @t.indent_text("foo").should == "\tfoo"
- end
-
- it "accepts a custom indentation level as second argument" do
- @t.indent_text("foo", 2, "\t", true).should == "\t\tfoo"
- end
-
- it "accepts a custom separator as third argument" do
- @t.indent_text("foo", 1, "\n", true).should == "\nfoo"
- end
-
- it "accepts a fourth parameter to skip the first line" do
- @t.indent_text("foo", 1, "\t", false).should == "foo"
- end
- end
-end
diff --git a/spec/ruby/library/rexml/text/inspect_spec.rb b/spec/ruby/library/rexml/text/inspect_spec.rb
deleted file mode 100644
index af389890ee..0000000000
--- a/spec/ruby/library/rexml/text/inspect_spec.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Text#inspect" do
- it "inspects the string attribute as a string" do
- REXML::Text.new("a text").inspect.should == "a text".inspect
- end
- end
-end
diff --git a/spec/ruby/library/rexml/text/new_spec.rb b/spec/ruby/library/rexml/text/new_spec.rb
deleted file mode 100644
index 8b33da9294..0000000000
--- a/spec/ruby/library/rexml/text/new_spec.rb
+++ /dev/null
@@ -1,51 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Text.new" do
-
- it "creates a Text child node with no parent" do
- t = REXML::Text.new("test")
- t.should be_kind_of(REXML::Child)
- t.should == "test"
- t.parent.should == nil
- end
-
- it "respects whitespace if second argument is true" do
- t = REXML::Text.new("testing whitespace", true)
- t.should == "testing whitespace"
- t = REXML::Text.new(" ", true)
- t.should == " "
- end
-
- it "receives a parent as third argument" do
- e = REXML::Element.new("root")
- t = REXML::Text.new("test", false, e)
- t.parent.should == e
- e.to_s.should == "<root>test</root>"
- end
-
- it "expects escaped text if raw is true" do
- t = REXML::Text.new("&lt;&amp;&gt;", false, nil, true)
- t.should == "&lt;&amp;&gt;"
-
- ->{ REXML::Text.new("<&>", false, nil, true)}.should raise_error(Exception)
- end
-
- it "uses raw value of the parent if raw is nil" do
- e1 = REXML::Element.new("root", nil, { raw: :all})
- -> {REXML::Text.new("<&>", false, e1)}.should raise_error(Exception)
-
- e2 = REXML::Element.new("root", nil, { raw: []})
- e2.raw.should be_false
- t1 = REXML::Text.new("<&>", false, e2)
- t1.should == "&lt;&amp;&gt;"
- end
-
- it "escapes the values if raw is false" do
- t = REXML::Text.new("<&>", false, nil, false)
- t.should == "&lt;&amp;&gt;"
- end
- end
-end
diff --git a/spec/ruby/library/rexml/text/node_type_spec.rb b/spec/ruby/library/rexml/text/node_type_spec.rb
deleted file mode 100644
index f44a1ede3e..0000000000
--- a/spec/ruby/library/rexml/text/node_type_spec.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Text#node_type" do
- it "returns :text" do
- REXML::Text.new("test").node_type.should == :text
- end
- end
-end
diff --git a/spec/ruby/library/rexml/text/normalize_spec.rb b/spec/ruby/library/rexml/text/normalize_spec.rb
deleted file mode 100644
index cde11ec3c9..0000000000
--- a/spec/ruby/library/rexml/text/normalize_spec.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Text.normalize" do
- it "escapes a string with <, >, &, ' and \" " do
- REXML::Text.normalize("< > & \" '").should == "&lt; &gt; &amp; &quot; &apos;"
- end
- end
-end
diff --git a/spec/ruby/library/rexml/text/read_with_substitution_spec.rb b/spec/ruby/library/rexml/text/read_with_substitution_spec.rb
deleted file mode 100644
index 7ff26f4d53..0000000000
--- a/spec/ruby/library/rexml/text/read_with_substitution_spec.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Text.read_with_substitution" do
- it "reads a text and escapes entities" do
- REXML::Text.read_with_substitution("&lt; &gt; &amp; &quot; &apos;").should == "< > & \" '"
- end
-
- it "accepts an regex for invalid expressions and raises an error if text matches" do
- -> {REXML::Text.read_with_substitution("this is illegal", /illegal/)}.should raise_error(Exception)
- end
- end
-end
diff --git a/spec/ruby/library/rexml/text/to_s_spec.rb b/spec/ruby/library/rexml/text/to_s_spec.rb
deleted file mode 100644
index e67632c9a1..0000000000
--- a/spec/ruby/library/rexml/text/to_s_spec.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Text#to_s" do
- it "returns the string of this Text node" do
- u = REXML::Text.new("sean russell", false, nil, true)
- u.to_s.should == "sean russell"
-
- t = REXML::Text.new("some test text")
- t.to_s.should == "some test text"
- end
-
- it "escapes the text" do
- t = REXML::Text.new("& < >")
- t.to_s.should == "&amp; &lt; &gt;"
- end
- end
-end
diff --git a/spec/ruby/library/rexml/text/unnormalize_spec.rb b/spec/ruby/library/rexml/text/unnormalize_spec.rb
deleted file mode 100644
index 7b507194d0..0000000000
--- a/spec/ruby/library/rexml/text/unnormalize_spec.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Text.unnormalize" do
- it "unescapes a string with the values defined in SETUTITSBUS" do
- REXML::Text.unnormalize("&lt; &gt; &amp; &quot; &apos;").should == "< > & \" '"
- end
- end
-end
diff --git a/spec/ruby/library/rexml/text/value_spec.rb b/spec/ruby/library/rexml/text/value_spec.rb
deleted file mode 100644
index 53d40c765f..0000000000
--- a/spec/ruby/library/rexml/text/value_spec.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Text#value" do
- it "returns the text value of this node" do
- REXML::Text.new("test").value.should == "test"
- end
-
- it "does not escape entities" do
- REXML::Text.new("& \"").value.should == "& \""
- end
-
- it "follows the respect_whitespace attribute" do
- REXML::Text.new("test bar", false).value.should == "test bar"
- REXML::Text.new("test bar", true).value.should == "test bar"
- end
-
- it "ignores the raw attribute" do
- REXML::Text.new("sean russell", false, nil, true).value.should == "sean russell"
- end
- end
-
- describe "REXML::Text#value=" do
- before :each do
- @t = REXML::Text.new("new")
- end
-
- it "sets the text of the node" do
- @t.value = "another text"
- @t.to_s.should == "another text"
- end
-
- it "escapes entities" do
- @t.value = "<a>"
- @t.to_s.should == "&lt;a&gt;"
- end
- end
-end
diff --git a/spec/ruby/library/rexml/text/wrap_spec.rb b/spec/ruby/library/rexml/text/wrap_spec.rb
deleted file mode 100644
index 331a8439e2..0000000000
--- a/spec/ruby/library/rexml/text/wrap_spec.rb
+++ /dev/null
@@ -1,23 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Text#wrap" do
- before :each do
- @t = REXML::Text.new("abc def")
- end
-
- it "wraps the text at width" do
- @t.wrap("abc def", 3, false).should == "abc\ndef"
- end
-
- it "returns the string if width is greater than the size of the string" do
- @t.wrap("abc def", 10, false).should == "abc def"
- end
-
- it "takes a newline at the beginning option as the third parameter" do
- @t.wrap("abc def", 3, true).should == "\nabc\ndef"
- end
- end
-end
diff --git a/spec/ruby/library/rexml/text/write_with_substitution_spec.rb b/spec/ruby/library/rexml/text/write_with_substitution_spec.rb
deleted file mode 100644
index 840f141e3d..0000000000
--- a/spec/ruby/library/rexml/text/write_with_substitution_spec.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Text#write_with_substitution" do
- before :each do
- @t = REXML::Text.new("test")
- @f = tmp("rexml_spec")
- @file = File.open(@f, "w+")
- end
-
- after :each do
- @file.close
- rm_r @f
- end
-
- it "writes out the input to a String" do
- s = ""
- @t.write_with_substitution(s, "some text")
- s.should == "some text"
- end
-
- it "writes out the input to an IO" do
- @t.write_with_substitution(@file, "some text")
- @file.rewind
- @file.gets.should == "some text"
- end
-
- it "escapes characters" do
- @t.write_with_substitution(@file, "& < >")
- @file.rewind
- @file.gets.should == "&amp; &lt; &gt;"
- end
- end
-end
diff --git a/spec/ruby/library/rubygems/gem/load_path_insert_index_spec.rb b/spec/ruby/library/rubygems/gem/load_path_insert_index_spec.rb
index 58913cddab..9b37eaa43c 100644
--- a/spec/ruby/library/rubygems/gem/load_path_insert_index_spec.rb
+++ b/spec/ruby/library/rubygems/gem/load_path_insert_index_spec.rb
@@ -3,7 +3,7 @@ require 'rubygems'
describe "Gem.load_path_insert_index" do
guard -> { RbConfig::TOPDIR } do
- it "is set for an installed an installed Ruby" do
+ it "is set for an installed Ruby" do
Gem.load_path_insert_index.should be_kind_of Integer
end
end
diff --git a/spec/ruby/library/scanf/io/block_scanf_spec.rb b/spec/ruby/library/scanf/io/block_scanf_spec.rb
deleted file mode 100644
index b9cc1b507e..0000000000
--- a/spec/ruby/library/scanf/io/block_scanf_spec.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'2.7' do
- require_relative 'shared/block_scanf'
- require 'scanf'
-
- describe "IO#block_scanf" do
- it_behaves_like :scanf_io_block_scanf, :block_scanf
- end
-end
diff --git a/spec/ruby/library/scanf/io/fixtures/date.txt b/spec/ruby/library/scanf/io/fixtures/date.txt
deleted file mode 100644
index a1bd635c0c..0000000000
--- a/spec/ruby/library/scanf/io/fixtures/date.txt
+++ /dev/null
@@ -1,4 +0,0 @@
-Beethoven 1770
-Bach 1685
-Handel 1685
-
diff --git a/spec/ruby/library/scanf/io/fixtures/helloworld.txt b/spec/ruby/library/scanf/io/fixtures/helloworld.txt
deleted file mode 100644
index 3b18e512db..0000000000
--- a/spec/ruby/library/scanf/io/fixtures/helloworld.txt
+++ /dev/null
@@ -1 +0,0 @@
-hello world
diff --git a/spec/ruby/library/scanf/io/scanf_spec.rb b/spec/ruby/library/scanf/io/scanf_spec.rb
deleted file mode 100644
index 6a3e6d0d1a..0000000000
--- a/spec/ruby/library/scanf/io/scanf_spec.rb
+++ /dev/null
@@ -1,38 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'2.7' do
- require_relative 'shared/block_scanf'
- require 'scanf'
-
- describe "IO#scanf" do
- before :each do
- @hw = File.open(fixture(__FILE__, 'helloworld.txt'), 'rb')
- @data = File.open(fixture(__FILE__, 'date.txt'), 'rb')
- end
-
- after :each do
- @hw.close unless @hw.closed?
- @data.close unless @data.closed?
- end
-
- it "returns an array containing the input converted in the specified type" do
- @hw.scanf("%s%s").should == ["hello", "world"]
- @data.scanf("%s%d").should == ["Beethoven", 1770]
- end
-
- it "returns an array containing the input converted in the specified type with given maximum field width" do
- @hw.scanf("%2s").should == ["he"]
- @data.scanf("%2c").should == ["Be"]
- end
-
- it "returns an empty array when a wrong specifier is passed" do
- @hw.scanf("%a").should == []
- @hw.scanf("%1").should == []
- @data.scanf("abc").should == []
- end
- end
-
- describe "IO#scanf with block" do
- it_behaves_like :scanf_io_block_scanf, :scanf
- end
-end
diff --git a/spec/ruby/library/scanf/io/shared/block_scanf.rb b/spec/ruby/library/scanf/io/shared/block_scanf.rb
deleted file mode 100644
index d938f43734..0000000000
--- a/spec/ruby/library/scanf/io/shared/block_scanf.rb
+++ /dev/null
@@ -1,28 +0,0 @@
-require 'scanf'
-
-describe :scanf_io_block_scanf, shared: true do
- before :each do
- @data = File.open(fixture(__FILE__, 'date.txt'), 'rb')
- end
-
- after :each do
- @data.close unless @data.closed?
- end
-
- it "passes each match to the block as an array" do
- res = @data.send(@method, "%s%d") { |name, year| "#{name} was born in #{year}." }
- res.should == ["Beethoven was born in 1770.", "Bach was born in 1685.", "Handel was born in 1685."]
- end
-
- it "keeps scanning the input and cycling back to the beginning of the input string" do
- a = []
- @data.send(@method, "%s"){|w| a << w}
- a.should == [["Beethoven"], ["1770"], ["Bach"], ["1685"], ["Handel"], ["1685"]]
- end
-
- it "returns an empty array when a wrong specifier is passed" do
- a = []
- @data.send(@method, "%z"){|w| a << w}
- a.empty?.should be_true
- end
-end
diff --git a/spec/ruby/library/scanf/string/block_scanf_spec.rb b/spec/ruby/library/scanf/string/block_scanf_spec.rb
deleted file mode 100644
index 277e1fa1d7..0000000000
--- a/spec/ruby/library/scanf/string/block_scanf_spec.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'2.7' do
- require_relative 'shared/block_scanf'
- require 'scanf'
-
- describe "String#block_scanf" do
- it_behaves_like :scanf_string_block_scanf, :block_scanf
- end
-end
diff --git a/spec/ruby/library/scanf/string/scanf_spec.rb b/spec/ruby/library/scanf/string/scanf_spec.rb
deleted file mode 100644
index c8897db675..0000000000
--- a/spec/ruby/library/scanf/string/scanf_spec.rb
+++ /dev/null
@@ -1,56 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ''...'2.7' do
- require_relative 'shared/block_scanf'
- require 'scanf'
-
- describe "String#scanf" do
- it "returns an array containing the input converted in the specified type" do
- "hello world".scanf("%s").should == ["hello"]
- "hello world".scanf("%s%d").should == ["hello"]
- "hello world".scanf("%s%c").should == ["hello", " "]
- "hello world".scanf("%c%s").should == ["h", "ello"]
- "hello world".scanf("%s%s").should == ["hello", "world"]
- "hello world".scanf("%c").should == ["h"]
- "123".scanf("%s").should == ["123"]
- "123".scanf("%c").should == ["1"]
- "123".scanf("%d").should == [123]
- "123".scanf("%u").should == [123]
- "123".scanf("%o").should == [83]
- "123".scanf("%x").should == [291]
- "123".scanf("%i").should == [123]
- "0123".scanf("%i").should == [83]
- "123".scanf("%f").should == [123.0]
- "0X123".scanf("%i").should == [291]
- "0x123".scanf("%i").should == [291]
- end
-
- it "returns an array containing the input converted in the specified type with given maximum field width" do
- "hello world".scanf("%2s").should == ["he"]
- "hello world".scanf("%2c").should == ["he"]
- "123".scanf("%2s").should == ["12"]
- "123".scanf("%2c").should == ["12"]
- "123".scanf("%2d").should == [12]
- "123".scanf("%2u").should == [12]
- "123".scanf("%2o").should == [10]
- "123".scanf("%2x").should == [18]
- "123".scanf("%2i").should == [12]
- "0123".scanf("%2i").should == [1]
- "123".scanf("%2f").should == [12.0]
- "0X123".scanf("%2i").should == [0]
- "0X123".scanf("%3i").should == [1]
- "0X123".scanf("%4i").should == [18]
- end
-
- it "returns an empty array when a wrong specifier is passed" do
- "hello world".scanf("%a").should == []
- "123".scanf("%1").should == []
- "123".scanf("abc").should == []
- "123".scanf(:d).should == []
- end
- end
-
- describe "String#scanf with block" do
- it_behaves_like :scanf_string_block_scanf, :scanf
- end
-end
diff --git a/spec/ruby/library/scanf/string/shared/block_scanf.rb b/spec/ruby/library/scanf/string/shared/block_scanf.rb
deleted file mode 100644
index 25ab3f442a..0000000000
--- a/spec/ruby/library/scanf/string/shared/block_scanf.rb
+++ /dev/null
@@ -1,25 +0,0 @@
-require 'scanf'
-
-describe :scanf_string_block_scanf, shared: true do
- it "passes each match to the block as an array" do
- a = []
- "hello world".send(@method, "%s%s"){|w| a << w}
- a.should == [["hello", "world"]]
- end
-
- it "keeps scanning the input and cycling back to the beginning of the input string" do
- a = []
- "hello world".send(@method, "%s"){|w| a << w}
- a.should == [["hello"], ["world"]]
-
- string = "123 abc 456 def 789 ghi"
- s = string.send(@method, "%d%s"){|num,str| [num * 2, str.upcase]}
- s.should == [[246, "ABC"], [912, "DEF"], [1578, "GHI"]]
- end
-
- it "returns an empty array when a wrong specifier is passed" do
- a = []
- "hello world".send(@method, "%z"){|w| a << w}
- a.empty?.should be_true
- end
-end
diff --git a/spec/ruby/library/set/compare_by_identity_spec.rb b/spec/ruby/library/set/compare_by_identity_spec.rb
index 9ed1602189..602d1e758e 100644
--- a/spec/ruby/library/set/compare_by_identity_spec.rb
+++ b/spec/ruby/library/set/compare_by_identity_spec.rb
@@ -5,7 +5,7 @@ describe "Set#compare_by_identity" do
it "compares its members by identity" do
a = "a"
b1 = "b"
- b2 = "b"
+ b2 = b1.dup
set = Set.new
set.compare_by_identity
diff --git a/spec/ruby/library/set/comparison_spec.rb b/spec/ruby/library/set/comparison_spec.rb
index b851ea3d57..ddcfbae0af 100644
--- a/spec/ruby/library/set/comparison_spec.rb
+++ b/spec/ruby/library/set/comparison_spec.rb
@@ -1,29 +1,27 @@
-require_relative '../../spec_helper'
-require 'set'
-
-ruby_version_is "3.0" do
- describe "Set#<=>" do
- it "returns 0 if the sets are equal" do
- (Set[] <=> Set[]).should == 0
- (Set[:a, :b, :c] <=> Set[:a, :b, :c]).should == 0
- end
-
- it "returns -1 if the set is a proper subset of the other set" do
- (Set[] <=> Set[1]).should == -1
- (Set[1, 2] <=> Set[1, 2, 3]).should == -1
- end
-
- it "returns +1 if the set is a proper superset of other set" do
- (Set[1] <=> Set[]).should == +1
- (Set[1, 2, 3] <=> Set[1, 2]).should == +1
- end
-
- it "returns nil if the set has unique elements" do
- (Set[1, 2, 3] <=> Set[:a, :b, :c]).should be_nil
- end
-
- it "returns nil when the argument is not set-like" do
- (Set[] <=> false).should be_nil
- end
- end
-end
+require_relative '../../spec_helper'
+require 'set'
+
+describe "Set#<=>" do
+ it "returns 0 if the sets are equal" do
+ (Set[] <=> Set[]).should == 0
+ (Set[:a, :b, :c] <=> Set[:a, :b, :c]).should == 0
+ end
+
+ it "returns -1 if the set is a proper subset of the other set" do
+ (Set[] <=> Set[1]).should == -1
+ (Set[1, 2] <=> Set[1, 2, 3]).should == -1
+ end
+
+ it "returns +1 if the set is a proper superset of other set" do
+ (Set[1] <=> Set[]).should == +1
+ (Set[1, 2, 3] <=> Set[1, 2]).should == +1
+ end
+
+ it "returns nil if the set has unique elements" do
+ (Set[1, 2, 3] <=> Set[:a, :b, :c]).should be_nil
+ end
+
+ it "returns nil when the argument is not set-like" do
+ (Set[] <=> false).should be_nil
+ end
+end
diff --git a/spec/ruby/library/set/divide_spec.rb b/spec/ruby/library/set/divide_spec.rb
index fdd8cd9622..998a1b292c 100644
--- a/spec/ruby/library/set/divide_spec.rb
+++ b/spec/ruby/library/set/divide_spec.rb
@@ -13,11 +13,11 @@ describe "Set#divide" do
ret.sort.should == ["five", "four", "one", "three", "two"]
end
- # BUG: Does not raise a LocalJumpError, but a NoMethodError
- #
- # it "raises a LocalJumpError when not passed a block" do
- # lambda { Set[1].divide }.should raise_error(LocalJumpError)
- # end
+ 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
@@ -31,4 +31,29 @@ describe "Set#divide when passed a block with an arity of 2" do
Set[1, 2].divide { |x, y| ret << [x, y] }
ret.sort.should == [[1, 1], [1, 2], [2, 1], [2, 2]]
end
+
+ it "returns an enumerator when not passed a block" do
+ ret = Set[1, 2, 3, 4].divide
+ ret.should be_kind_of(Enumerator)
+ ret.each { |a, b| (a + b).even? }.should == Set[Set[1, 3], Set[2, 4]]
+ end
+end
+
+describe "Set#divide when passed a block with an arity of > 2" do
+ it "only uses the first element if the arity > 2" do
+ set = Set["one", "two", "three", "four", "five"].divide do |x, y, z|
+ y.should be_nil
+ z.should be_nil
+ x.length
+ end
+ set.map { |x| x.to_a.sort }.sort.should == [["five", "four"], ["one", "two"], ["three"]]
+ end
+
+ it "only uses the first element if the arity = -1" do
+ set = Set["one", "two", "three", "four", "five"].divide do |*xs|
+ xs.size.should == 1
+ xs.first.length
+ end
+ set.map { |x| x.to_a.sort }.sort.should == [["five", "four"], ["one", "two"], ["three"]]
+ end
end
diff --git a/spec/ruby/library/set/each_spec.rb b/spec/ruby/library/set/each_spec.rb
index 9bb5ead03a..44e185a4da 100644
--- a/spec/ruby/library/set/each_spec.rb
+++ b/spec/ruby/library/set/each_spec.rb
@@ -18,6 +18,7 @@ describe "Set#each" do
it "returns an Enumerator when not passed a block" do
enum = @set.each
+ enum.should be_an_instance_of(Enumerator)
ret = []
enum.each { |x| ret << x }
diff --git a/spec/ruby/library/set/enumerable/to_set_spec.rb b/spec/ruby/library/set/enumerable/to_set_spec.rb
index 3790d8deee..b2d850515b 100644
--- a/spec/ruby/library/set/enumerable/to_set_spec.rb
+++ b/spec/ruby/library/set/enumerable/to_set_spec.rb
@@ -7,14 +7,6 @@ describe "Enumerable#to_set" do
{a: 1, b: 2}.to_set.should == Set[[:b, 2], [:a, 1]]
end
- ruby_version_is ''...'3.0' do
- it "allows passing an alternate class for Set" do
- sorted_set = [1, 2, 3].to_set(SortedSet)
- sorted_set.should == SortedSet[1, 2, 3]
- sorted_set.instance_of?(SortedSet).should == true
- end
- end
-
it "passes down passed blocks" do
[1, 2, 3].to_set { |x| x * x }.should == Set[1, 4, 9]
end
diff --git a/spec/ruby/library/set/flatten_spec.rb b/spec/ruby/library/set/flatten_spec.rb
index 4ac83ea825..51b58d6439 100644
--- a/spec/ruby/library/set/flatten_spec.rb
+++ b/spec/ruby/library/set/flatten_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
require_relative 'fixtures/set_like'
require 'set'
+set_version = defined?(Set::VERSION) ? Set::VERSION : '1.0.0'
describe "Set#flatten" do
it "returns a copy of self with each included Set flattened" do
@@ -45,9 +46,11 @@ describe "Set#flatten!" do
-> { set.flatten! }.should raise_error(ArgumentError)
end
- context "when Set contains a Set-like object" do
- it "flattens self, including Set-like objects" do
- Set[SetSpecs::SetLike.new([1])].flatten!.should == Set[1]
+ version_is(set_version, ""..."1.1.0") do #ruby_version_is ""..."3.3" do
+ context "when Set contains a Set-like object" do
+ it "flattens self, including Set-like objects" do
+ Set[SetSpecs::SetLike.new([1])].flatten!.should == Set[1]
+ end
end
end
end
diff --git a/spec/ruby/library/set/initialize_clone_spec.rb b/spec/ruby/library/set/initialize_clone_spec.rb
index 62985987fa..bda42cd6e8 100644
--- a/spec/ruby/library/set/initialize_clone_spec.rb
+++ b/spec/ruby/library/set/initialize_clone_spec.rb
@@ -2,17 +2,15 @@ require_relative '../../spec_helper'
require 'set'
describe "Set#initialize_clone" do
- ruby_version_is "3.0" do
- # See https://bugs.ruby-lang.org/issues/14266
- it "does not freeze the new Set when called from clone(freeze: false)" do
- set1 = Set[1, 2]
- set1.freeze
- set2 = set1.clone(freeze: false)
- set1.frozen?.should == true
- set2.frozen?.should == false
- set2.add 3
- set1.should == Set[1, 2]
- set2.should == Set[1, 2, 3]
- end
+ # 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/library/set/join_spec.rb b/spec/ruby/library/set/join_spec.rb
index 7498a91d98..3f511a84e4 100644
--- a/spec/ruby/library/set/join_spec.rb
+++ b/spec/ruby/library/set/join_spec.rb
@@ -1,31 +1,29 @@
require_relative '../../spec_helper'
require 'set'
-ruby_version_is "3.0" do
- describe "Set#join" do
- it "returns an empty string if the Set is empty" do
- Set[].join.should == ''
- end
+describe "Set#join" do
+ it "returns an empty string if the Set is empty" do
+ Set[].join.should == ''
+ end
- it "returns a new string formed by joining elements after conversion" do
- set = Set[:a, :b, :c]
- set.join.should == "abc"
- end
+ it "returns a new string formed by joining elements after conversion" do
+ set = Set[:a, :b, :c]
+ set.join.should == "abc"
+ end
- it "does not separate elements when the passed separator is nil" do
- set = Set[:a, :b, :c]
- set.join(nil).should == "abc"
- end
+ it "does not separate elements when the passed separator is nil" do
+ set = Set[:a, :b, :c]
+ set.join(nil).should == "abc"
+ end
- it "returns a string formed by concatenating each element separated by the separator" do
- set = Set[:a, :b, :c]
- set.join(' | ').should == "a | b | c"
- end
+ it "returns a string formed by concatenating each element separated by the separator" do
+ set = Set[:a, :b, :c]
+ set.join(' | ').should == "a | b | c"
+ end
- it "calls #to_a to convert the Set in to an Array" do
- set = Set[:a, :b, :c]
- set.should_receive(:to_a).and_return([:a, :b, :c])
- set.join.should == "abc"
- end
+ it "calls #to_a to convert the Set in to an Array" do
+ set = Set[:a, :b, :c]
+ set.should_receive(:to_a).and_return([:a, :b, :c])
+ set.join.should == "abc"
end
end
diff --git a/spec/ruby/library/set/proper_subset_spec.rb b/spec/ruby/library/set/proper_subset_spec.rb
index 1f496a6199..6b51dedc9f 100644
--- a/spec/ruby/library/set/proper_subset_spec.rb
+++ b/spec/ruby/library/set/proper_subset_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
require_relative 'fixtures/set_like'
require 'set'
+set_version = defined?(Set::VERSION) ? Set::VERSION : '1.0.0'
describe "Set#proper_subset?" do
before :each do
@@ -33,9 +34,11 @@ describe "Set#proper_subset?" do
-> { Set[].proper_subset?(Object.new) }.should raise_error(ArgumentError)
end
- context "when comparing to a Set-like object" do
- it "returns true if passed a Set-like object that self is a proper subset of" do
- Set[1, 2, 3].proper_subset?(SetSpecs::SetLike.new([1, 2, 3, 4])).should be_true
+ version_is(set_version, ""..."1.1.0") do #ruby_version_is ""..."3.3" do
+ context "when comparing to a Set-like object" do
+ it "returns true if passed a Set-like object that self is a proper subset of" do
+ Set[1, 2, 3].proper_subset?(SetSpecs::SetLike.new([1, 2, 3, 4])).should be_true
+ end
end
end
end
diff --git a/spec/ruby/library/set/set_spec.rb b/spec/ruby/library/set/set_spec.rb
new file mode 100644
index 0000000000..2a4edc6dfc
--- /dev/null
+++ b/spec/ruby/library/set/set_spec.rb
@@ -0,0 +1,12 @@
+require_relative '../../spec_helper'
+
+describe 'Set' do
+ ruby_version_is '3.2' do
+ it 'is available without explicit requiring' do
+ output = ruby_exe(<<~RUBY, options: '--disable-gems', args: '2>&1')
+ puts Set.new([1, 2, 3])
+ RUBY
+ output.chomp.should == "#<Set: {1, 2, 3}>"
+ end
+ end
+end
diff --git a/spec/ruby/library/set/shared/inspect.rb b/spec/ruby/library/set/shared/inspect.rb
index 69fbdd12f6..adb6ddb4c9 100644
--- a/spec/ruby/library/set/shared/inspect.rb
+++ b/spec/ruby/library/set/shared/inspect.rb
@@ -1,4 +1,4 @@
-describe "set_inspect", shared: true do
+describe :set_inspect, shared: true do
it "returns a String representation of self" do
Set[].send(@method).should be_kind_of(String)
Set[nil, false, true].send(@method).should be_kind_of(String)
@@ -7,9 +7,19 @@ describe "set_inspect", shared: true do
Set[:a, "b", Set[?c]].send(@method).should be_kind_of(String)
end
- it "correctly handles self-references" do
- (set = Set[]) << set
- set.send(@method).should be_kind_of(String)
- set.send(@method).should include("#<Set: {...}>")
+ it "does include the elements of the set" do
+ Set["1"].send(@method).should == '#<Set: {"1"}>'
+ end
+
+ it "puts spaces between the elements" do
+ Set["1", "2"].send(@method).should include('", "')
+ end
+
+ it "correctly handles cyclic-references" do
+ set1 = Set[]
+ set2 = Set[set1]
+ set1 << set2
+ set1.send(@method).should be_kind_of(String)
+ set1.send(@method).should include("#<Set: {...}>")
end
end
diff --git a/spec/ruby/library/set/sortedset/add_spec.rb b/spec/ruby/library/set/sortedset/add_spec.rb
deleted file mode 100644
index 4f3bb252e1..0000000000
--- a/spec/ruby/library/set/sortedset/add_spec.rb
+++ /dev/null
@@ -1,42 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.0" do
- require 'set'
- require_relative 'shared/add'
-
- describe "SortedSet#add" do
- it_behaves_like :sorted_set_add, :add
-
- it "takes only values which responds <=>" do
- obj = mock('no_comparison_operator')
- obj.stub!(:respond_to?).with(:<=>).and_return(false)
- -> { SortedSet["hello"].add(obj) }.should raise_error(ArgumentError)
- end
-
- it "raises on incompatible <=> comparison" do
- # Use #to_a here as elements are sorted only when needed.
- # Therefore the <=> incompatibility is only noticed on sorting.
- -> { SortedSet['1', '2'].add(3).to_a }.should raise_error(ArgumentError)
- end
- end
-
- describe "SortedSet#add?" do
- before :each do
- @set = SortedSet.new
- end
-
- it "adds the passed Object to self" do
- @set.add?("cat")
- @set.should include("cat")
- end
-
- it "returns self when the Object has not yet been added to self" do
- @set.add?("cat").should equal(@set)
- end
-
- it "returns nil when the Object has already been added to self" do
- @set.add?("cat")
- @set.add?("cat").should be_nil
- end
- end
-end
diff --git a/spec/ruby/library/set/sortedset/append_spec.rb b/spec/ruby/library/set/sortedset/append_spec.rb
deleted file mode 100644
index d72d70b21f..0000000000
--- a/spec/ruby/library/set/sortedset/append_spec.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.0" do
- require 'set'
- require_relative 'shared/add'
-
- describe "SortedSet#<<" do
- it_behaves_like :sorted_set_add, :<<
- end
-end
diff --git a/spec/ruby/library/set/sortedset/case_equality_spec.rb b/spec/ruby/library/set/sortedset/case_equality_spec.rb
deleted file mode 100644
index d7c296b626..0000000000
--- a/spec/ruby/library/set/sortedset/case_equality_spec.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.0" do
- require_relative 'shared/include'
- require 'set'
-
- describe "SortedSet#===" do
- it_behaves_like :sorted_set_include, :===
- end
-end
diff --git a/spec/ruby/library/set/sortedset/classify_spec.rb b/spec/ruby/library/set/sortedset/classify_spec.rb
deleted file mode 100644
index 4011e58b82..0000000000
--- a/spec/ruby/library/set/sortedset/classify_spec.rb
+++ /dev/null
@@ -1,30 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.0" do
- require 'set'
-
- describe "SortedSet#classify" do
- before :each do
- @set = SortedSet["one", "two", "three", "four"]
- end
-
- it "yields each Object in self in sorted order" do
- res = []
- @set.classify { |x| res << x }
- res.should == ["one", "two", "three", "four"].sort
- end
-
- it "returns an Enumerator when passed no block" do
- enum = @set.classify
- enum.should be_an_instance_of(Enumerator)
-
- classified = enum.each { |x| x.length }
- classified.should == { 3 => SortedSet["one", "two"], 4 => SortedSet["four"], 5 => SortedSet["three"] }
- end
-
- it "classifies the Objects in self based on the block's return value" do
- classified = @set.classify { |x| x.length }
- classified.should == { 3 => SortedSet["one", "two"], 4 => SortedSet["four"], 5 => SortedSet["three"] }
- end
- end
-end
diff --git a/spec/ruby/library/set/sortedset/clear_spec.rb b/spec/ruby/library/set/sortedset/clear_spec.rb
deleted file mode 100644
index 879aa824d8..0000000000
--- a/spec/ruby/library/set/sortedset/clear_spec.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.0" do
- require 'set'
-
- describe "SortedSet#clear" do
- before :each do
- @set = SortedSet["one", "two", "three", "four"]
- end
-
- it "removes all elements from self" do
- @set.clear
- @set.should be_empty
- end
-
- it "returns self" do
- @set.clear.should equal(@set)
- end
- end
-end
diff --git a/spec/ruby/library/set/sortedset/collect_spec.rb b/spec/ruby/library/set/sortedset/collect_spec.rb
deleted file mode 100644
index 0674f0d130..0000000000
--- a/spec/ruby/library/set/sortedset/collect_spec.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.0" do
- require 'set'
- require_relative 'shared/collect'
-
- describe "SortedSet#collect!" do
- it_behaves_like :sorted_set_collect_bang, :collect!
- end
-end
diff --git a/spec/ruby/library/set/sortedset/constructor_spec.rb b/spec/ruby/library/set/sortedset/constructor_spec.rb
deleted file mode 100644
index 31f30fd892..0000000000
--- a/spec/ruby/library/set/sortedset/constructor_spec.rb
+++ /dev/null
@@ -1,18 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.0" do
- require 'set'
-
- describe "SortedSet[]" do
- it "returns a new SortedSet populated with the passed Objects" do
- set = SortedSet[1, 2, 3]
-
- set.instance_of?(SortedSet).should be_true
- set.size.should eql(3)
-
- set.should include(1)
- set.should include(2)
- set.should include(3)
- end
- end
-end
diff --git a/spec/ruby/library/set/sortedset/delete_if_spec.rb b/spec/ruby/library/set/sortedset/delete_if_spec.rb
deleted file mode 100644
index 787639ae12..0000000000
--- a/spec/ruby/library/set/sortedset/delete_if_spec.rb
+++ /dev/null
@@ -1,41 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.0" do
- require 'set'
-
- describe "SortedSet#delete_if" do
- before :each do
- @set = SortedSet["one", "two", "three"]
- end
-
- it "yields each Object in self in sorted order" do
- ret = []
- @set.delete_if { |x| ret << x }
- ret.should == ["one", "two", "three"].sort
- end
-
- it "deletes every element from self for which the passed block returns true" do
- @set.delete_if { |x| x.size == 3 }
- @set.size.should eql(1)
-
- @set.should_not include("one")
- @set.should_not include("two")
- @set.should include("three")
- end
-
- it "returns self" do
- @set.delete_if { |x| x }.should equal(@set)
- end
-
- it "returns an Enumerator when passed no block" do
- enum = @set.delete_if
- enum.should be_an_instance_of(Enumerator)
-
- enum.each { |x| x.size == 3 }
-
- @set.should_not include("one")
- @set.should_not include("two")
- @set.should include("three")
- end
- end
-end
diff --git a/spec/ruby/library/set/sortedset/delete_spec.rb b/spec/ruby/library/set/sortedset/delete_spec.rb
deleted file mode 100644
index 0e2a6accf3..0000000000
--- a/spec/ruby/library/set/sortedset/delete_spec.rb
+++ /dev/null
@@ -1,40 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.0" do
- require 'set'
-
- describe "SortedSet#delete" do
- before :each do
- @set = SortedSet["a", "b", "c"]
- end
-
- it "deletes the passed Object from self" do
- @set.delete("a")
- @set.should_not include("a")
- end
-
- it "returns self" do
- @set.delete("a").should equal(@set)
- @set.delete("x").should equal(@set)
- end
- end
-
- describe "SortedSet#delete?" do
- before :each do
- @set = SortedSet["a", "b", "c"]
- end
-
- it "deletes the passed Object from self" do
- @set.delete?("a")
- @set.should_not include("a")
- end
-
- it "returns self when the passed Object is in self" do
- @set.delete?("a").should equal(@set)
- end
-
- it "returns nil when the passed Object is not in self" do
- @set.delete?("x").should be_nil
- end
- end
-end
diff --git a/spec/ruby/library/set/sortedset/difference_spec.rb b/spec/ruby/library/set/sortedset/difference_spec.rb
deleted file mode 100644
index fb064bdff9..0000000000
--- a/spec/ruby/library/set/sortedset/difference_spec.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.0" do
- require 'set'
- require_relative 'shared/difference'
-
- describe "SortedSet#difference" do
- it_behaves_like :sorted_set_difference, :difference
- end
-end
diff --git a/spec/ruby/library/set/sortedset/divide_spec.rb b/spec/ruby/library/set/sortedset/divide_spec.rb
deleted file mode 100644
index 31ab6037e4..0000000000
--- a/spec/ruby/library/set/sortedset/divide_spec.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.0" do
- require 'set'
-
- describe "SortedSet#divide" do
- it "divides self into a set of subsets based on the blocks return values" do
- set = SortedSet["one", "two", "three", "four", "five"].divide { |x| x.length }
- set.map { |x| x.to_a }.to_a.sort.should == [["five", "four"], ["one", "two"], ["three"]]
- end
-
- it "yields each Object in self in sorted order" do
- ret = []
- SortedSet["one", "two", "three", "four", "five"].divide { |x| ret << x }
- ret.should == ["one", "two", "three", "four", "five"].sort
- end
-
- # BUG: Does not raise a LocalJumpError, but a NoMethodError
- #
- # it "raises a LocalJumpError when not passed a block" do
- # lambda { SortedSet[1].divide }.should raise_error(LocalJumpError)
- # end
- end
-
- describe "SortedSet#divide when passed a block with an arity of 2" do
- it "divides self into a set of subsets based on the blocks return values" do
- set = SortedSet[1, 3, 4, 6, 9, 10, 11].divide { |x, y| (x - y).abs == 1 }
- set.map { |x| x.to_a }.to_a.sort.should == [[1], [3, 4], [6], [9, 10, 11]]
- end
-
- it "yields each two Objects to the block" do
- ret = []
- SortedSet[1, 2].divide { |x, y| ret << [x, y] }
- ret.should == [[1, 1], [1, 2], [2, 1], [2, 2]]
- end
- end
-end
diff --git a/spec/ruby/library/set/sortedset/each_spec.rb b/spec/ruby/library/set/sortedset/each_spec.rb
deleted file mode 100644
index 79d8aee223..0000000000
--- a/spec/ruby/library/set/sortedset/each_spec.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.0" do
- require 'set'
-
- describe "SortedSet#each" do
- before :each do
- @set = SortedSet[1, 2, 3]
- end
-
- it "yields each Object in self in sorted order" do
- ret = []
- SortedSet["one", "two", "three"].each { |x| ret << x }
- ret.should == ["one", "two", "three"].sort
- end
-
- it "returns self" do
- @set.each { |x| x }.should equal(@set)
- end
-
- it "returns an Enumerator when not passed a block" do
- enum = @set.each
-
- ret = []
- enum.each { |x| ret << x }
- ret.sort.should == [1, 2, 3]
- end
- end
-end
diff --git a/spec/ruby/library/set/sortedset/empty_spec.rb b/spec/ruby/library/set/sortedset/empty_spec.rb
deleted file mode 100644
index 2e52c3e81a..0000000000
--- a/spec/ruby/library/set/sortedset/empty_spec.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.0" do
- require 'set'
-
- describe "SortedSet#empty?" do
- it "returns true if self is empty" do
- SortedSet[].empty?.should be_true
- SortedSet[1].empty?.should be_false
- SortedSet[1,2,3].empty?.should be_false
- end
- end
-end
diff --git a/spec/ruby/library/set/sortedset/eql_spec.rb b/spec/ruby/library/set/sortedset/eql_spec.rb
deleted file mode 100644
index 050464994b..0000000000
--- a/spec/ruby/library/set/sortedset/eql_spec.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.0" do
- require 'set'
-
- describe "SortedSet#eql?" do
- it "returns true when the passed argument is a SortedSet and contains the same elements" do
- SortedSet[].should eql(SortedSet[])
- SortedSet[1, 2, 3].should eql(SortedSet[1, 2, 3])
- SortedSet[1, 2, 3].should eql(SortedSet[3, 2, 1])
-
- # SortedSet["a", :b, ?c].should eql(SortedSet[?c, :b, "a"])
-
- SortedSet[1, 2, 3].should_not eql(SortedSet[1.0, 2, 3])
- SortedSet[1, 2, 3].should_not eql(SortedSet[2, 3])
- SortedSet[1, 2, 3].should_not eql(SortedSet[])
- end
- end
-end
diff --git a/spec/ruby/library/set/sortedset/equal_value_spec.rb b/spec/ruby/library/set/sortedset/equal_value_spec.rb
deleted file mode 100644
index 30422f5b95..0000000000
--- a/spec/ruby/library/set/sortedset/equal_value_spec.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.0" do
- require 'set'
-
- describe "SortedSet#==" do
- it "returns true when the passed Object is a SortedSet and self and the Object contain the same elements" do
- SortedSet[].should == SortedSet[]
- SortedSet[1, 2, 3].should == SortedSet[1, 2, 3]
- SortedSet["1", "2", "3"].should == SortedSet["1", "2", "3"]
-
- SortedSet[1, 2, 3].should_not == SortedSet[1.0, 2, 3]
- SortedSet[1, 2, 3].should_not == [1, 2, 3]
- end
- end
-end
diff --git a/spec/ruby/library/set/sortedset/exclusion_spec.rb b/spec/ruby/library/set/sortedset/exclusion_spec.rb
deleted file mode 100644
index 1967dfbfa6..0000000000
--- a/spec/ruby/library/set/sortedset/exclusion_spec.rb
+++ /dev/null
@@ -1,21 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.0" do
- require 'set'
-
- describe "SortedSet#^" do
- before :each do
- @set = SortedSet[1, 2, 3, 4]
- end
-
- it "returns a new SortedSet containing elements that are not in both self and the passed Enumerable" do
- (@set ^ SortedSet[3, 4, 5]).should == SortedSet[1, 2, 5]
- (@set ^ [3, 4, 5]).should == SortedSet[1, 2, 5]
- end
-
- it "raises an ArgumentError when passed a non-Enumerable" do
- -> { @set ^ 3 }.should raise_error(ArgumentError)
- -> { @set ^ Object.new }.should raise_error(ArgumentError)
- end
- end
-end
diff --git a/spec/ruby/library/set/sortedset/filter_spec.rb b/spec/ruby/library/set/sortedset/filter_spec.rb
deleted file mode 100644
index 3b9dcb63c9..0000000000
--- a/spec/ruby/library/set/sortedset/filter_spec.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.0" do
- require_relative 'shared/select'
- require 'set'
-
- describe "SortedSet#filter!" do
- it_behaves_like :sorted_set_select_bang, :filter!
- end
-end
diff --git a/spec/ruby/library/set/sortedset/flatten_merge_spec.rb b/spec/ruby/library/set/sortedset/flatten_merge_spec.rb
deleted file mode 100644
index 0d67cb331e..0000000000
--- a/spec/ruby/library/set/sortedset/flatten_merge_spec.rb
+++ /dev/null
@@ -1,11 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.0" do
- require 'set'
-
- describe "SortedSet#flatten_merge" do
- it "is protected" do
- SortedSet.should have_protected_instance_method("flatten_merge")
- end
- end
-end
diff --git a/spec/ruby/library/set/sortedset/flatten_spec.rb b/spec/ruby/library/set/sortedset/flatten_spec.rb
deleted file mode 100644
index e83ad1044a..0000000000
--- a/spec/ruby/library/set/sortedset/flatten_spec.rb
+++ /dev/null
@@ -1,47 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.0" do
- require 'set'
-
- # Note: Flatten make little sens on sorted sets, because SortedSets are not (by default)
- # comparable. For a SortedSet to be both valid and nested, we need to define a comparison operator:
- module SortedSet_FlattenSpecs
- class ComparableSortedSet < SortedSet
- def <=>(other)
- return puts "#{other} vs #{self}" unless other.is_a?(ComparableSortedSet)
- to_a <=> other.to_a
- end
- end
- end
-
- describe "SortedSet#flatten" do
- it "returns a copy of self with each included SortedSet flattened" do
- klass = SortedSet_FlattenSpecs::ComparableSortedSet
- set = klass[klass[1,2], klass[3,4], klass[5,6,7], klass[8]]
- flattened_set = set.flatten
-
- flattened_set.should_not equal(set)
- flattened_set.should == klass[1, 2, 3, 4, 5, 6, 7, 8]
- end
- end
-
- describe "SortedSet#flatten!" do
- it "flattens self" do
- klass = SortedSet_FlattenSpecs::ComparableSortedSet
- set = klass[klass[1,2], klass[3,4], klass[5,6,7], klass[8]]
- set.flatten!
- set.should == klass[1, 2, 3, 4, 5, 6, 7, 8]
- end
-
- it "returns self when self was modified" do
- klass = SortedSet_FlattenSpecs::ComparableSortedSet
- set = klass[klass[1,2], klass[3,4]]
- set.flatten!.should equal(set)
- end
-
- it "returns nil when self was not modified" do
- set = SortedSet[1, 2, 3, 4]
- set.flatten!.should be_nil
- end
- end
-end
diff --git a/spec/ruby/library/set/sortedset/hash_spec.rb b/spec/ruby/library/set/sortedset/hash_spec.rb
deleted file mode 100644
index 40676de7fc..0000000000
--- a/spec/ruby/library/set/sortedset/hash_spec.rb
+++ /dev/null
@@ -1,16 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.0" do
- require 'set'
-
- describe "SortedSet#hash" do
- it "is static" do
- SortedSet[].hash.should == SortedSet[].hash
- SortedSet[1, 2, 3].hash.should == SortedSet[1, 2, 3].hash
- SortedSet["a", "b", "c"].hash.should == SortedSet["c", "b", "a"].hash
-
- SortedSet[].hash.should_not == SortedSet[1, 2, 3].hash
- SortedSet[1, 2, 3].hash.should_not == SortedSet["a", "b", "c"].hash
- end
- end
-end
diff --git a/spec/ruby/library/set/sortedset/include_spec.rb b/spec/ruby/library/set/sortedset/include_spec.rb
deleted file mode 100644
index ec2ad987d5..0000000000
--- a/spec/ruby/library/set/sortedset/include_spec.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.0" do
- require_relative 'shared/include'
- require 'set'
-
- describe "SortedSet#include?" do
- it_behaves_like :sorted_set_include, :include?
- end
-end
diff --git a/spec/ruby/library/set/sortedset/initialize_spec.rb b/spec/ruby/library/set/sortedset/initialize_spec.rb
deleted file mode 100644
index 4d1707b72a..0000000000
--- a/spec/ruby/library/set/sortedset/initialize_spec.rb
+++ /dev/null
@@ -1,33 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.0" do
- require 'set'
-
- describe "SortedSet#initialize" do
- it "is private" do
- SortedSet.should have_private_instance_method("initialize")
- end
-
- it "adds all elements of the passed Enumerable to self" do
- s = SortedSet.new([1, 2, 3])
- s.size.should eql(3)
- s.should include(1)
- s.should include(2)
- s.should include(3)
- end
-
- it "preprocesses all elements by a passed block before adding to self" do
- s = SortedSet.new([1, 2, 3]) { |x| x * x }
- s.size.should eql(3)
- s.should include(1)
- s.should include(4)
- s.should include(9)
- end
-
- it "raises on incompatible <=> comparison" do
- # Use #to_a here as elements are sorted only when needed.
- # Therefore the <=> incompatibility is only noticed on sorting.
- -> { SortedSet.new(['00', nil]).to_a }.should raise_error(ArgumentError)
- end
- end
-end
diff --git a/spec/ruby/library/set/sortedset/inspect_spec.rb b/spec/ruby/library/set/sortedset/inspect_spec.rb
deleted file mode 100644
index 1c4dd9e6e2..0000000000
--- a/spec/ruby/library/set/sortedset/inspect_spec.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.0" do
- require 'set'
-
- describe "SortedSet#inspect" do
- it "returns a String representation of self" do
- SortedSet[].inspect.should be_kind_of(String)
- SortedSet[1, 2, 3].inspect.should be_kind_of(String)
- SortedSet["1", "2", "3"].inspect.should be_kind_of(String)
- end
- end
-end
diff --git a/spec/ruby/library/set/sortedset/intersection_spec.rb b/spec/ruby/library/set/sortedset/intersection_spec.rb
deleted file mode 100644
index 6daa271b73..0000000000
--- a/spec/ruby/library/set/sortedset/intersection_spec.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.0" do
- require_relative 'shared/intersection'
- require 'set'
-
- describe "SortedSet#intersection" do
- it_behaves_like :sorted_set_intersection, :intersection
- end
-
- describe "SortedSet#&" do
- it_behaves_like :sorted_set_intersection, :&
- end
-end
diff --git a/spec/ruby/library/set/sortedset/keep_if_spec.rb b/spec/ruby/library/set/sortedset/keep_if_spec.rb
deleted file mode 100644
index 3e5f3bbc47..0000000000
--- a/spec/ruby/library/set/sortedset/keep_if_spec.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.0" do
- require 'set'
-
- describe "SortedSet#keep_if" do
- before :each do
- @set = SortedSet["one", "two", "three"]
- end
-
- it "yields each Object in self in sorted order" do
- ret = []
- @set.keep_if { |x| ret << x }
- ret.should == ["one", "two", "three"].sort
- end
-
- it "keeps every element from self for which the passed block returns true" do
- @set.keep_if { |x| x.size != 3 }
- @set.to_a.should == ["three"]
- end
-
- it "returns self" do
- @set.keep_if {}.should equal(@set)
- end
-
- it "returns an Enumerator when passed no block" do
- enum = @set.keep_if
- enum.should be_an_instance_of(Enumerator)
-
- enum.each { |x| x.size != 3 }
- @set.to_a.should == ["three"]
- end
- end
-end
diff --git a/spec/ruby/library/set/sortedset/length_spec.rb b/spec/ruby/library/set/sortedset/length_spec.rb
deleted file mode 100644
index de6791f6bb..0000000000
--- a/spec/ruby/library/set/sortedset/length_spec.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.0" do
- require_relative 'shared/length'
- require 'set'
-
- describe "SortedSet#length" do
- it_behaves_like :sorted_set_length, :length
- end
-end
diff --git a/spec/ruby/library/set/sortedset/map_spec.rb b/spec/ruby/library/set/sortedset/map_spec.rb
deleted file mode 100644
index 4971b9529b..0000000000
--- a/spec/ruby/library/set/sortedset/map_spec.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.0" do
- require 'set'
- require_relative 'shared/collect'
-
- describe "SortedSet#map!" do
- it_behaves_like :sorted_set_collect_bang, :map!
- end
-end
diff --git a/spec/ruby/library/set/sortedset/member_spec.rb b/spec/ruby/library/set/sortedset/member_spec.rb
deleted file mode 100644
index 142b09b651..0000000000
--- a/spec/ruby/library/set/sortedset/member_spec.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.0" do
- require_relative 'shared/include'
- require 'set'
-
- describe "SortedSet#member?" do
- it_behaves_like :sorted_set_include, :member?
- end
-end
diff --git a/spec/ruby/library/set/sortedset/merge_spec.rb b/spec/ruby/library/set/sortedset/merge_spec.rb
deleted file mode 100644
index c4cbc6d2b4..0000000000
--- a/spec/ruby/library/set/sortedset/merge_spec.rb
+++ /dev/null
@@ -1,22 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.0" do
- require 'set'
-
- describe "SortedSet#merge" do
- it "adds the elements of the passed Enumerable to self" do
- SortedSet["a", "b"].merge(SortedSet["b", "c", "d"]).should == SortedSet["a", "b", "c", "d"]
- SortedSet[1, 2].merge([3, 4]).should == SortedSet[1, 2, 3, 4]
- end
-
- it "returns self" do
- set = SortedSet[1, 2]
- set.merge([3, 4]).should equal(set)
- end
-
- it "raises an ArgumentError when passed a non-Enumerable" do
- -> { SortedSet[1, 2].merge(1) }.should raise_error(ArgumentError)
- -> { SortedSet[1, 2].merge(Object.new) }.should raise_error(ArgumentError)
- end
- end
-end
diff --git a/spec/ruby/library/set/sortedset/minus_spec.rb b/spec/ruby/library/set/sortedset/minus_spec.rb
deleted file mode 100644
index d6abc5e204..0000000000
--- a/spec/ruby/library/set/sortedset/minus_spec.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.0" do
- require 'set'
- require_relative 'shared/difference'
-
- describe "SortedSet#-" do
- it_behaves_like :sorted_set_difference, :-
- end
-end
diff --git a/spec/ruby/library/set/sortedset/plus_spec.rb b/spec/ruby/library/set/sortedset/plus_spec.rb
deleted file mode 100644
index 13fc873ad1..0000000000
--- a/spec/ruby/library/set/sortedset/plus_spec.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.0" do
- require_relative 'shared/union'
- require 'set'
-
- describe "SortedSet#+" do
- it_behaves_like :sorted_set_union, :+
- end
-end
diff --git a/spec/ruby/library/set/sortedset/pretty_print_cycle_spec.rb b/spec/ruby/library/set/sortedset/pretty_print_cycle_spec.rb
deleted file mode 100644
index e97f509406..0000000000
--- a/spec/ruby/library/set/sortedset/pretty_print_cycle_spec.rb
+++ /dev/null
@@ -1,13 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.0" do
- require 'set'
-
- describe "SortedSet#pretty_print_cycle" do
- it "passes the 'pretty print' representation of a self-referencing SortedSet to the pretty print writer" do
- pp = mock("PrettyPrint")
- pp.should_receive(:text).with("#<SortedSet: {...}>")
- SortedSet[1, 2, 3].pretty_print_cycle(pp)
- end
- end
-end
diff --git a/spec/ruby/library/set/sortedset/pretty_print_spec.rb b/spec/ruby/library/set/sortedset/pretty_print_spec.rb
deleted file mode 100644
index a8088bf797..0000000000
--- a/spec/ruby/library/set/sortedset/pretty_print_spec.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.0" do
- require 'set'
-
- describe "SortedSet#pretty_print" do
- it "passes the 'pretty print' representation of self to the pretty print writer" do
- pp = mock("PrettyPrint")
- set = SortedSet[1, 2, 3]
-
- pp.should_receive(:text).with("#<SortedSet: {")
- pp.should_receive(:text).with("}>")
-
- pp.should_receive(:nest).with(1).and_yield
- pp.should_receive(:seplist).with(set)
-
- set.pretty_print(pp)
- end
- end
-end
diff --git a/spec/ruby/library/set/sortedset/proper_subset_spec.rb b/spec/ruby/library/set/sortedset/proper_subset_spec.rb
deleted file mode 100644
index 34fb89d13d..0000000000
--- a/spec/ruby/library/set/sortedset/proper_subset_spec.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.0" do
- require 'set'
-
- describe "SortedSet#proper_subset?" do
- before :each do
- @set = SortedSet[1, 2, 3, 4]
- end
-
- it "returns true if passed a SortedSet that self is a proper subset of" do
- SortedSet[].proper_subset?(@set).should be_true
- SortedSet[].proper_subset?(SortedSet[1, 2, 3]).should be_true
- SortedSet[].proper_subset?(SortedSet["a", "b", "c"]).should be_true
-
- SortedSet[1, 2, 3].proper_subset?(@set).should be_true
- SortedSet[1, 3].proper_subset?(@set).should be_true
- SortedSet[1, 2].proper_subset?(@set).should be_true
- SortedSet[1].proper_subset?(@set).should be_true
-
- SortedSet[5].proper_subset?(@set).should be_false
- SortedSet[1, 5].proper_subset?(@set).should be_false
- SortedSet["test"].proper_subset?(@set).should be_false
-
- @set.proper_subset?(@set).should be_false
- SortedSet[].proper_subset?(SortedSet[]).should be_false
- end
-
- it "raises an ArgumentError when passed a non-SortedSet" do
- -> { SortedSet[].proper_subset?([]) }.should raise_error(ArgumentError)
- -> { SortedSet[].proper_subset?(1) }.should raise_error(ArgumentError)
- -> { SortedSet[].proper_subset?("test") }.should raise_error(ArgumentError)
- -> { SortedSet[].proper_subset?(Object.new) }.should raise_error(ArgumentError)
- end
- end
-end
diff --git a/spec/ruby/library/set/sortedset/proper_superset_spec.rb b/spec/ruby/library/set/sortedset/proper_superset_spec.rb
deleted file mode 100644
index 8b92444f72..0000000000
--- a/spec/ruby/library/set/sortedset/proper_superset_spec.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.0" do
- require 'set'
-
- describe "SortedSet#proper_superset?" do
- before :each do
- @set = SortedSet[1, 2, 3, 4]
- end
-
- it "returns true if passed a SortedSet that self is a proper superset of" do
- @set.proper_superset?(SortedSet[]).should be_true
- SortedSet[1, 2, 3].proper_superset?(SortedSet[]).should be_true
- SortedSet["a", "b", "c"].proper_superset?(SortedSet[]).should be_true
-
- @set.proper_superset?(SortedSet[1, 2, 3]).should be_true
- @set.proper_superset?(SortedSet[1, 3]).should be_true
- @set.proper_superset?(SortedSet[1, 2]).should be_true
- @set.proper_superset?(SortedSet[1]).should be_true
-
- @set.proper_superset?(SortedSet[5]).should be_false
- @set.proper_superset?(SortedSet[1, 5]).should be_false
- @set.proper_superset?(SortedSet["test"]).should be_false
-
- @set.proper_superset?(@set).should be_false
- SortedSet[].proper_superset?(SortedSet[]).should be_false
- end
-
- it "raises an ArgumentError when passed a non-SortedSet" do
- -> { SortedSet[].proper_superset?([]) }.should raise_error(ArgumentError)
- -> { SortedSet[].proper_superset?(1) }.should raise_error(ArgumentError)
- -> { SortedSet[].proper_superset?("test") }.should raise_error(ArgumentError)
- -> { SortedSet[].proper_superset?(Object.new) }.should raise_error(ArgumentError)
- end
- end
-end
diff --git a/spec/ruby/library/set/sortedset/reject_spec.rb b/spec/ruby/library/set/sortedset/reject_spec.rb
deleted file mode 100644
index 396b864cc5..0000000000
--- a/spec/ruby/library/set/sortedset/reject_spec.rb
+++ /dev/null
@@ -1,45 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.0" do
- require 'set'
-
- describe "SortedSet#reject!" do
- before :each do
- @set = SortedSet["one", "two", "three"]
- end
-
- it "yields each Object in self in sorted order" do
- res = []
- @set.reject! { |x| res << x }
- res.should == ["one", "two", "three"].sort
- end
-
- it "deletes every element from self for which the passed block returns true" do
- @set.reject! { |x| x.size == 3 }
- @set.size.should eql(1)
-
- @set.should_not include("one")
- @set.should_not include("two")
- @set.should include("three")
- end
-
- it "returns self when self was modified" do
- @set.reject! { |x| true }.should equal(@set)
- end
-
- it "returns nil when self was not modified" do
- @set.reject! { |x| false }.should be_nil
- end
-
- it "returns an Enumerator when passed no block" do
- enum = @set.reject!
- enum.should be_an_instance_of(Enumerator)
-
- enum.each { |x| x.size == 3 }
-
- @set.should_not include("one")
- @set.should_not include("two")
- @set.should include("three")
- end
- end
-end
diff --git a/spec/ruby/library/set/sortedset/replace_spec.rb b/spec/ruby/library/set/sortedset/replace_spec.rb
deleted file mode 100644
index 2900221c01..0000000000
--- a/spec/ruby/library/set/sortedset/replace_spec.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.0" do
- require 'set'
-
- describe "SortedSet#replace" do
- before :each do
- @set = SortedSet["a", "b", "c"]
- end
-
- it "replaces the contents with other and returns self" do
- @set.replace(SortedSet[1, 2, 3]).should == @set
- @set.should == SortedSet[1, 2, 3]
- end
-
- it "accepts any enumerable as other" do
- @set.replace([1, 2, 3]).should == SortedSet[1, 2, 3]
- end
- end
-end
diff --git a/spec/ruby/library/set/sortedset/select_spec.rb b/spec/ruby/library/set/sortedset/select_spec.rb
deleted file mode 100644
index fc4c15ee4d..0000000000
--- a/spec/ruby/library/set/sortedset/select_spec.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.0" do
- require_relative 'shared/select'
- require 'set'
-
- describe "SortedSet#select!" do
- it_behaves_like :sorted_set_select_bang, :select!
- end
-end
diff --git a/spec/ruby/library/set/sortedset/shared/add.rb b/spec/ruby/library/set/sortedset/shared/add.rb
deleted file mode 100644
index 95ef1b090e..0000000000
--- a/spec/ruby/library/set/sortedset/shared/add.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-describe :sorted_set_add, shared: true do
- before :each do
- @set = SortedSet.new
- end
-
- it "adds the passed Object to self" do
- @set.send(@method, "dog")
- @set.should include("dog")
- end
-
- it "returns self" do
- @set.send(@method, "dog").should equal(@set)
- end
-end
diff --git a/spec/ruby/library/set/sortedset/shared/collect.rb b/spec/ruby/library/set/sortedset/shared/collect.rb
deleted file mode 100644
index e53304d427..0000000000
--- a/spec/ruby/library/set/sortedset/shared/collect.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-describe :sorted_set_collect_bang, shared: true do
- before :each do
- @set = SortedSet[1, 2, 3, 4, 5]
- end
-
- it "yields each Object in self in sorted order" do
- res = []
- SortedSet["one", "two", "three"].send(@method) { |x| res << x; x }
- res.should == ["one", "two", "three"].sort
- end
-
- it "returns self" do
- @set.send(@method) { |x| x }.should equal(@set)
- end
-
- it "replaces self with the return values of the block" do
- @set.send(@method) { |x| x * 2 }
- @set.should == SortedSet[2, 4, 6, 8, 10]
- end
-end
diff --git a/spec/ruby/library/set/sortedset/shared/difference.rb b/spec/ruby/library/set/sortedset/shared/difference.rb
deleted file mode 100644
index 688e23a7a7..0000000000
--- a/spec/ruby/library/set/sortedset/shared/difference.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-describe :sorted_set_difference, shared: true do
- before :each do
- @set = SortedSet["a", "b", "c"]
- end
-
- it "returns a new SortedSet containing self's elements excluding the elements in the passed Enumerable" do
- @set.send(@method, SortedSet["a", "b"]).should == SortedSet["c"]
- @set.send(@method, ["b", "c"]).should == SortedSet["a"]
- end
-
- it "raises an ArgumentError when passed a non-Enumerable" do
- -> { @set.send(@method, 1) }.should raise_error(ArgumentError)
- -> { @set.send(@method, Object.new) }.should raise_error(ArgumentError)
- end
-end
diff --git a/spec/ruby/library/set/sortedset/shared/include.rb b/spec/ruby/library/set/sortedset/shared/include.rb
deleted file mode 100644
index cd1758819d..0000000000
--- a/spec/ruby/library/set/sortedset/shared/include.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-describe :sorted_set_include, shared: true do
- it "returns true when self contains the passed Object" do
- set = SortedSet["a", "b", "c"]
- set.send(@method, "a").should be_true
- set.send(@method, "e").should be_false
- end
-end
diff --git a/spec/ruby/library/set/sortedset/shared/intersection.rb b/spec/ruby/library/set/sortedset/shared/intersection.rb
deleted file mode 100644
index 045716ad05..0000000000
--- a/spec/ruby/library/set/sortedset/shared/intersection.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-describe :sorted_set_intersection, shared: true do
- before :each do
- @set = SortedSet["a", "b", "c"]
- end
-
- it "returns a new SortedSet containing only elements shared by self and the passed Enumerable" do
- @set.send(@method, SortedSet["b", "c", "d", "e"]).should == SortedSet["b", "c"]
- @set.send(@method, ["b", "c", "d"]).should == SortedSet["b", "c"]
- end
-
- it "raises an ArgumentError when passed a non-Enumerable" do
- -> { @set.send(@method, 1) }.should raise_error(ArgumentError)
- -> { @set.send(@method, Object.new) }.should raise_error(ArgumentError)
- end
-end
diff --git a/spec/ruby/library/set/sortedset/shared/length.rb b/spec/ruby/library/set/sortedset/shared/length.rb
deleted file mode 100644
index d1dfee1cff..0000000000
--- a/spec/ruby/library/set/sortedset/shared/length.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-describe :sorted_set_length, shared: true do
- it "returns the number of elements in the set" do
- set = SortedSet["a", "b", "c"]
- set.send(@method).should == 3
- end
-end
diff --git a/spec/ruby/library/set/sortedset/shared/select.rb b/spec/ruby/library/set/sortedset/shared/select.rb
deleted file mode 100644
index e13311eda5..0000000000
--- a/spec/ruby/library/set/sortedset/shared/select.rb
+++ /dev/null
@@ -1,35 +0,0 @@
-require_relative '../../../../spec_helper'
-require 'set'
-
-describe :sorted_set_select_bang, shared: true do
- before :each do
- @set = SortedSet["one", "two", "three"]
- end
-
- it "yields each Object in self in sorted order" do
- res = []
- @set.send(@method) { |x| res << x }
- res.should == ["one", "two", "three"].sort
- end
-
- it "keeps every element from self for which the passed block returns true" do
- @set.send(@method) { |x| x.size != 3 }
- @set.to_a.should == ["three"]
- end
-
- it "returns self when self was modified" do
- @set.send(@method) { false }.should equal(@set)
- end
-
- it "returns nil when self was not modified" do
- @set.send(@method) { true }.should be_nil
- end
-
- it "returns an Enumerator when passed no block" do
- enum = @set.send(@method)
- enum.should be_an_instance_of(Enumerator)
-
- enum.each { |x| x.size != 3 }
- @set.to_a.should == ["three"]
- end
-end
diff --git a/spec/ruby/library/set/sortedset/shared/union.rb b/spec/ruby/library/set/sortedset/shared/union.rb
deleted file mode 100644
index 9015bdc8e3..0000000000
--- a/spec/ruby/library/set/sortedset/shared/union.rb
+++ /dev/null
@@ -1,15 +0,0 @@
-describe :sorted_set_union, shared: true do
- before :each do
- @set = SortedSet["a", "b", "c"]
- end
-
- it "returns a new SortedSet containing all elements of self and the passed Enumerable" do
- @set.send(@method, SortedSet["b", "d", "e"]).should == SortedSet["a", "b", "c", "d", "e"]
- @set.send(@method, ["b", "e"]).should == SortedSet["a", "b", "c", "e"]
- end
-
- it "raises an ArgumentError when passed a non-Enumerable" do
- -> { @set.send(@method, 1) }.should raise_error(ArgumentError)
- -> { @set.send(@method, Object.new) }.should raise_error(ArgumentError)
- end
-end
diff --git a/spec/ruby/library/set/sortedset/size_spec.rb b/spec/ruby/library/set/sortedset/size_spec.rb
deleted file mode 100644
index d908b33b53..0000000000
--- a/spec/ruby/library/set/sortedset/size_spec.rb
+++ /dev/null
@@ -1,10 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.0" do
- require_relative 'shared/length'
- require 'set'
-
- describe "SortedSet#size" do
- it_behaves_like :sorted_set_length, :size
- end
-end
diff --git a/spec/ruby/library/set/sortedset/sortedset_spec.rb b/spec/ruby/library/set/sortedset/sortedset_spec.rb
index 3ead5495fc..67993dee29 100644
--- a/spec/ruby/library/set/sortedset/sortedset_spec.rb
+++ b/spec/ruby/library/set/sortedset/sortedset_spec.rb
@@ -1,22 +1,12 @@
require_relative '../../../spec_helper'
require 'set'
-ruby_version_is "3.0" do
- describe "SortedSet" do
- it "raises error including message that it has been extracted from the set stdlib" do
- -> {
- SortedSet
- }.should raise_error(RuntimeError) { |e|
- e.message.should.include?("The `SortedSet` class has been extracted from the `set` library")
- }
- end
- end
-end
-
-ruby_version_is ""..."3.0" do
- describe "SortedSet" do
- it "is part of the set stdlib" do
- SortedSet.superclass.should == Set
- end
+describe "SortedSet" do
+ it "raises error including message that it has been extracted from the set stdlib" do
+ -> {
+ SortedSet
+ }.should raise_error(RuntimeError) { |e|
+ e.message.should.include?("The `SortedSet` class has been extracted from the `set` library")
+ }
end
end
diff --git a/spec/ruby/library/set/sortedset/subset_spec.rb b/spec/ruby/library/set/sortedset/subset_spec.rb
deleted file mode 100644
index 272e3f985e..0000000000
--- a/spec/ruby/library/set/sortedset/subset_spec.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.0" do
- require 'set'
-
- describe "SortedSet#subset?" do
- before :each do
- @set = SortedSet[1, 2, 3, 4]
- end
-
- it "returns true if passed a SortedSet that is equal to self or self is a subset of" do
- @set.subset?(@set).should be_true
- SortedSet[].subset?(SortedSet[]).should be_true
-
- SortedSet[].subset?(@set).should be_true
- SortedSet[].subset?(SortedSet[1, 2, 3]).should be_true
- SortedSet[].subset?(SortedSet["a", "b", "c"]).should be_true
-
- SortedSet[1, 2, 3].subset?(@set).should be_true
- SortedSet[1, 3].subset?(@set).should be_true
- SortedSet[1, 2].subset?(@set).should be_true
- SortedSet[1].subset?(@set).should be_true
-
- SortedSet[5].subset?(@set).should be_false
- SortedSet[1, 5].subset?(@set).should be_false
- SortedSet["test"].subset?(@set).should be_false
- end
-
- it "raises an ArgumentError when passed a non-SortedSet" do
- -> { SortedSet[].subset?([]) }.should raise_error(ArgumentError)
- -> { SortedSet[].subset?(1) }.should raise_error(ArgumentError)
- -> { SortedSet[].subset?("test") }.should raise_error(ArgumentError)
- -> { SortedSet[].subset?(Object.new) }.should raise_error(ArgumentError)
- end
- end
-end
diff --git a/spec/ruby/library/set/sortedset/subtract_spec.rb b/spec/ruby/library/set/sortedset/subtract_spec.rb
deleted file mode 100644
index b2af127f89..0000000000
--- a/spec/ruby/library/set/sortedset/subtract_spec.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.0" do
- require 'set'
-
- describe "SortedSet#subtract" do
- before :each do
- @set = SortedSet["a", "b", "c"]
- end
-
- it "deletes any elements contained in other and returns self" do
- @set.subtract(SortedSet["b", "c"]).should == @set
- @set.should == SortedSet["a"]
- end
-
- it "accepts any enumerable as other" do
- @set.subtract(["c"]).should == SortedSet["a", "b"]
- end
- end
-end
diff --git a/spec/ruby/library/set/sortedset/superset_spec.rb b/spec/ruby/library/set/sortedset/superset_spec.rb
deleted file mode 100644
index a1bbacb966..0000000000
--- a/spec/ruby/library/set/sortedset/superset_spec.rb
+++ /dev/null
@@ -1,36 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.0" do
- require 'set'
-
- describe "SortedSet#superset?" do
- before :each do
- @set = SortedSet[1, 2, 3, 4]
- end
-
- it "returns true if passed a SortedSet that equals self or self is a proper superset of" do
- @set.superset?(@set).should be_true
- SortedSet[].superset?(SortedSet[]).should be_true
-
- @set.superset?(SortedSet[]).should be_true
- SortedSet[1, 2, 3].superset?(SortedSet[]).should be_true
- SortedSet["a", "b", "c"].superset?(SortedSet[]).should be_true
-
- @set.superset?(SortedSet[1, 2, 3]).should be_true
- @set.superset?(SortedSet[1, 3]).should be_true
- @set.superset?(SortedSet[1, 2]).should be_true
- @set.superset?(SortedSet[1]).should be_true
-
- @set.superset?(SortedSet[5]).should be_false
- @set.superset?(SortedSet[1, 5]).should be_false
- @set.superset?(SortedSet["test"]).should be_false
- end
-
- it "raises an ArgumentError when passed a non-SortedSet" do
- -> { SortedSet[].superset?([]) }.should raise_error(ArgumentError)
- -> { SortedSet[].superset?(1) }.should raise_error(ArgumentError)
- -> { SortedSet[].superset?("test") }.should raise_error(ArgumentError)
- -> { SortedSet[].superset?(Object.new) }.should raise_error(ArgumentError)
- end
- end
-end
diff --git a/spec/ruby/library/set/sortedset/to_a_spec.rb b/spec/ruby/library/set/sortedset/to_a_spec.rb
deleted file mode 100644
index bb54cd7cdb..0000000000
--- a/spec/ruby/library/set/sortedset/to_a_spec.rb
+++ /dev/null
@@ -1,20 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.0" do
- require 'set'
-
- describe "SortedSet#to_a" do
- it "returns an array containing elements" do
- set = SortedSet.new [1, 2, 3]
- set.to_a.should == [1, 2, 3]
- end
-
- it "returns a sorted array containing elements" do
- set = SortedSet[2, 3, 1]
- set.to_a.should == [1, 2, 3]
-
- set = SortedSet.new [5, 6, 4, 4]
- set.to_a.should == [4, 5, 6]
- end
- end
-end
diff --git a/spec/ruby/library/set/sortedset/union_spec.rb b/spec/ruby/library/set/sortedset/union_spec.rb
deleted file mode 100644
index c942f20d3e..0000000000
--- a/spec/ruby/library/set/sortedset/union_spec.rb
+++ /dev/null
@@ -1,14 +0,0 @@
-require_relative '../../../spec_helper'
-
-ruby_version_is ""..."3.0" do
- require_relative 'shared/union'
- require 'set'
-
- describe "SortedSet#union" do
- it_behaves_like :sorted_set_union, :union
- end
-
- describe "SortedSet#|" do
- it_behaves_like :sorted_set_union, :|
- end
-end
diff --git a/spec/ruby/library/set/subset_spec.rb b/spec/ruby/library/set/subset_spec.rb
index f375efa6df..85666d633f 100644
--- a/spec/ruby/library/set/subset_spec.rb
+++ b/spec/ruby/library/set/subset_spec.rb
@@ -1,6 +1,7 @@
require_relative '../../spec_helper'
require_relative 'fixtures/set_like'
require 'set'
+set_version = defined?(Set::VERSION) ? Set::VERSION : '1.0.0'
describe "Set#subset?" do
before :each do
@@ -33,9 +34,11 @@ describe "Set#subset?" do
-> { Set[].subset?(Object.new) }.should raise_error(ArgumentError)
end
- context "when comparing to a Set-like object" do
- it "returns true if passed a Set-like object that self is a subset of" do
- Set[1, 2, 3].subset?(SetSpecs::SetLike.new([1, 2, 3, 4])).should be_true
+ version_is(set_version, ""..."1.1.0") do #ruby_version_is ""..."3.3" do
+ context "when comparing to a Set-like object" do
+ it "returns true if passed a Set-like object that self is a subset of" do
+ Set[1, 2, 3].subset?(SetSpecs::SetLike.new([1, 2, 3, 4])).should be_true
+ end
end
end
end
diff --git a/spec/ruby/library/set/to_s_spec.rb b/spec/ruby/library/set/to_s_spec.rb
index 7b9f7b6603..3c26ae9346 100644
--- a/spec/ruby/library/set/to_s_spec.rb
+++ b/spec/ruby/library/set/to_s_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../spec_helper"
require_relative 'shared/inspect'
require 'set'
diff --git a/spec/ruby/library/shellwords/shellwords_spec.rb b/spec/ruby/library/shellwords/shellwords_spec.rb
index 2975fd9974..fe86b6faab 100644
--- a/spec/ruby/library/shellwords/shellwords_spec.rb
+++ b/spec/ruby/library/shellwords/shellwords_spec.rb
@@ -1,34 +1,33 @@
require_relative '../../spec_helper'
require 'shellwords'
-include Shellwords
describe "Shellwords#shellwords" do
it "honors quoted strings" do
- shellwords('a "b b" a').should == ['a', 'b b', 'a']
+ Shellwords.shellwords('a "b b" a').should == ['a', 'b b', 'a']
end
it "honors escaped double quotes" do
- shellwords('a "\"b\" c" d').should == ['a', '"b" c', 'd']
+ Shellwords.shellwords('a "\"b\" c" d').should == ['a', '"b" c', 'd']
end
it "honors escaped single quotes" do
- shellwords("a \"'b' c\" d").should == ['a', "'b' c", 'd']
+ Shellwords.shellwords("a \"'b' c\" d").should == ['a', "'b' c", 'd']
end
it "honors escaped spaces" do
- shellwords('a b\ c d').should == ['a', 'b c', 'd']
+ Shellwords.shellwords('a b\ c d').should == ['a', 'b c', 'd']
end
it "raises ArgumentError when double quoted strings are misquoted" do
- -> { shellwords('a "b c d e') }.should raise_error(ArgumentError)
+ -> { Shellwords.shellwords('a "b c d e') }.should raise_error(ArgumentError)
end
it "raises ArgumentError when single quoted strings are misquoted" do
- -> { shellwords("a 'b c d e") }.should raise_error(ArgumentError)
+ -> { Shellwords.shellwords("a 'b c d e") }.should raise_error(ArgumentError)
end
# https://bugs.ruby-lang.org/issues/10055
it "matches POSIX sh behavior for backslashes within double quoted strings" do
- shellsplit('printf "%s\n"').should == ['printf', '%s\n']
+ Shellwords.shellsplit('printf "%s\n"').should == ['printf', '%s\n']
end
end
diff --git a/spec/ruby/library/socket/addrinfo/initialize_spec.rb b/spec/ruby/library/socket/addrinfo/initialize_spec.rb
index 00250439fd..83b204b575 100644
--- a/spec/ruby/library/socket/addrinfo/initialize_spec.rb
+++ b/spec/ruby/library/socket/addrinfo/initialize_spec.rb
@@ -91,7 +91,7 @@ describe "Addrinfo#initialize" do
@addrinfo.afamily.should == Socket::AF_INET6
end
- it "returns the 0 socket type" do
+ it "returns the specified socket type" do
@addrinfo.socktype.should == Socket::SOCK_STREAM
end
diff --git a/spec/ruby/library/socket/addrinfo/shared/to_sockaddr.rb b/spec/ruby/library/socket/addrinfo/shared/to_sockaddr.rb
index c32da5986d..4f7cf439a0 100644
--- a/spec/ruby/library/socket/addrinfo/shared/to_sockaddr.rb
+++ b/spec/ruby/library/socket/addrinfo/shared/to_sockaddr.rb
@@ -1,5 +1,4 @@
-describe :socket_addrinfo_to_sockaddr, :shared => true do
-
+describe :socket_addrinfo_to_sockaddr, shared: true do
describe "for an ipv4 socket" do
before :each do
@addrinfo = Addrinfo.tcp("127.0.0.1", 80)
@@ -47,5 +46,4 @@ describe :socket_addrinfo_to_sockaddr, :shared => true do
addr.send(@method).should == Socket.sockaddr_in(0, '')
end
end
-
end
diff --git a/spec/ruby/library/socket/basicsocket/read_nonblock_spec.rb b/spec/ruby/library/socket/basicsocket/read_nonblock_spec.rb
index df44a50afa..ea5e65da5c 100644
--- a/spec/ruby/library/socket/basicsocket/read_nonblock_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/read_nonblock_spec.rb
@@ -18,7 +18,37 @@ describe "BasicSocket#read_nonblock" do
it "receives data after it's ready" do
IO.select([@r], nil, nil, 2)
- @r.recv_nonblock(5).should == "aaa"
+ @r.read_nonblock(5).should == "aaa"
+ end
+
+ platform_is_not :windows do
+ it 'returned data is binary encoded regardless of the external encoding' do
+ IO.select([@r], nil, nil, 2)
+ @r.read_nonblock(1).encoding.should == Encoding::BINARY
+
+ @w.send("bbb", 0, @r.getsockname)
+ @r.set_encoding(Encoding::ISO_8859_1)
+ IO.select([@r], nil, nil, 2)
+ buffer = @r.read_nonblock(3)
+ buffer.should == "bbb"
+ buffer.encoding.should == Encoding::BINARY
+ end
+ end
+
+ it 'replaces the content of the provided buffer without changing its encoding' do
+ buffer = "initial data".dup.force_encoding(Encoding::UTF_8)
+
+ IO.select([@r], nil, nil, 2)
+ @r.read_nonblock(3, buffer)
+ buffer.should == "aaa"
+ buffer.encoding.should == Encoding::UTF_8
+
+ @w.send("bbb", 0, @r.getsockname)
+ @r.set_encoding(Encoding::ISO_8859_1)
+ IO.select([@r], nil, nil, 2)
+ @r.read_nonblock(3, buffer)
+ buffer.should == "bbb"
+ buffer.encoding.should == Encoding::UTF_8
end
platform_is :linux do
diff --git a/spec/ruby/library/socket/basicsocket/read_spec.rb b/spec/ruby/library/socket/basicsocket/read_spec.rb
new file mode 100644
index 0000000000..ba9de7d5cf
--- /dev/null
+++ b/spec/ruby/library/socket/basicsocket/read_spec.rb
@@ -0,0 +1,47 @@
+require_relative '../spec_helper'
+require_relative '../fixtures/classes'
+
+describe "BasicSocket#read" do
+ SocketSpecs.each_ip_protocol do |family, ip_address|
+ before :each do
+ @r = Socket.new(family, :DGRAM)
+ @w = Socket.new(family, :DGRAM)
+
+ @r.bind(Socket.pack_sockaddr_in(0, ip_address))
+ @w.send("aaa", 0, @r.getsockname)
+ end
+
+ after :each do
+ @r.close unless @r.closed?
+ @w.close unless @w.closed?
+ end
+
+ it "receives data after it's ready" do
+ @r.read(3).should == "aaa"
+ end
+
+ it 'returned data is binary encoded regardless of the external encoding' do
+ @r.read(3).encoding.should == Encoding::BINARY
+
+ @w.send("bbb", 0, @r.getsockname)
+ @r.set_encoding(Encoding::UTF_8)
+ buffer = @r.read(3)
+ buffer.should == "bbb"
+ buffer.encoding.should == Encoding::BINARY
+ end
+
+ it 'replaces the content of the provided buffer without changing its encoding' do
+ buffer = "initial data".dup.force_encoding(Encoding::UTF_8)
+
+ @r.read(3, buffer)
+ buffer.should == "aaa"
+ buffer.encoding.should == Encoding::UTF_8
+
+ @w.send("bbb", 0, @r.getsockname)
+ @r.set_encoding(Encoding::ISO_8859_1)
+ @r.read(3, buffer)
+ buffer.should == "bbb"
+ buffer.encoding.should == Encoding::UTF_8
+ end
+ end
+end
diff --git a/spec/ruby/library/socket/basicsocket/recv_nonblock_spec.rb b/spec/ruby/library/socket/basicsocket/recv_nonblock_spec.rb
index b6ab8a9cea..17c846054d 100644
--- a/spec/ruby/library/socket/basicsocket/recv_nonblock_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/recv_nonblock_spec.rb
@@ -52,7 +52,7 @@ describe "Socket::BasicSocket#recv_nonblock" do
@s2.send("data", 0, @s1.getsockname)
IO.select([@s1], nil, nil, 2)
- buf = "foo"
+ buf = +"foo"
@s1.recv_nonblock(5, 0, buf)
buf.should == "data"
end
diff --git a/spec/ruby/library/socket/basicsocket/recv_spec.rb b/spec/ruby/library/socket/basicsocket/recv_spec.rb
index b6ccda5d00..9fe8c52f9a 100644
--- a/spec/ruby/library/socket/basicsocket/recv_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/recv_spec.rb
@@ -32,6 +32,25 @@ describe "BasicSocket#recv" do
ScratchPad.recorded.should == 'hello'
end
+ ruby_version_is "3.3" do
+ it "returns nil on a closed stream socket" do
+ t = Thread.new do
+ client = @server.accept
+ packet = client.recv(10)
+ client.close
+ packet
+ end
+
+ Thread.pass while t.status and t.status != "sleep"
+ t.status.should_not be_nil
+
+ socket = TCPSocket.new('127.0.0.1', @port)
+ socket.close
+
+ t.value.should be_nil
+ end
+ end
+
platform_is_not :solaris do
it "accepts flags to specify unusual receiving behaviour" do
t = Thread.new do
@@ -81,7 +100,7 @@ describe "BasicSocket#recv" do
socket.write("data")
client = @server.accept
- buf = "foo"
+ buf = +"foo"
begin
client.recv(4, 0, buf)
ensure
diff --git a/spec/ruby/library/socket/basicsocket/send_spec.rb b/spec/ruby/library/socket/basicsocket/send_spec.rb
index 868801df30..86b5567026 100644
--- a/spec/ruby/library/socket/basicsocket/send_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/send_spec.rb
@@ -17,12 +17,12 @@ describe "BasicSocket#send" do
end
it "sends a message to another socket and returns the number of bytes sent" do
- data = ""
+ data = +""
t = Thread.new do
client = @server.accept
loop do
got = client.recv(5)
- break if got.empty?
+ break if got.nil? || got.empty?
data << got
end
client.close
@@ -62,12 +62,12 @@ describe "BasicSocket#send" do
end
it "accepts a sockaddr as recipient address" do
- data = ""
+ data = +""
t = Thread.new do
client = @server.accept
loop do
got = client.recv(5)
- break if got.empty?
+ break if got.nil? || got.empty?
data << got
end
client.close
diff --git a/spec/ruby/library/socket/basicsocket/shutdown_spec.rb b/spec/ruby/library/socket/basicsocket/shutdown_spec.rb
index 41d9581bde..c78b32de38 100644
--- a/spec/ruby/library/socket/basicsocket/shutdown_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/shutdown_spec.rb
@@ -23,7 +23,7 @@ platform_is_not :windows do # hangs
it 'shuts down a socket for reading' do
@client.shutdown(Socket::SHUT_RD)
- @client.recv(1).should be_empty
+ @client.recv(1).to_s.should be_empty
end
it 'shuts down a socket for writing' do
@@ -35,7 +35,7 @@ platform_is_not :windows do # hangs
it 'shuts down a socket for reading and writing' do
@client.shutdown(Socket::SHUT_RDWR)
- @client.recv(1).should be_empty
+ @client.recv(1).to_s.should be_empty
-> { @client.write('hello') }.should raise_error(Errno::EPIPE)
end
@@ -49,13 +49,13 @@ platform_is_not :windows do # hangs
it 'shuts down a socket for reading using :RD' do
@client.shutdown(:RD)
- @client.recv(1).should be_empty
+ @client.recv(1).to_s.should be_empty
end
it 'shuts down a socket for reading using :SHUT_RD' do
@client.shutdown(:SHUT_RD)
- @client.recv(1).should be_empty
+ @client.recv(1).to_s.should be_empty
end
it 'shuts down a socket for writing using :WR' do
@@ -73,7 +73,7 @@ platform_is_not :windows do # hangs
it 'shuts down a socket for reading and writing' do
@client.shutdown(:RDWR)
- @client.recv(1).should be_empty
+ @client.recv(1).to_s.should be_empty
-> { @client.write('hello') }.should raise_error(Errno::EPIPE)
end
@@ -87,13 +87,13 @@ platform_is_not :windows do # hangs
it 'shuts down a socket for reading using "RD"' do
@client.shutdown('RD')
- @client.recv(1).should be_empty
+ @client.recv(1).to_s.should be_empty
end
it 'shuts down a socket for reading using "SHUT_RD"' do
@client.shutdown('SHUT_RD')
- @client.recv(1).should be_empty
+ @client.recv(1).to_s.should be_empty
end
it 'shuts down a socket for writing using "WR"' do
@@ -123,7 +123,7 @@ platform_is_not :windows do # hangs
@client.shutdown(@dummy)
- @client.recv(1).should be_empty
+ @client.recv(1).to_s.should be_empty
end
it 'shuts down a socket for reading using "SHUT_RD"' do
@@ -131,7 +131,7 @@ platform_is_not :windows do # hangs
@client.shutdown(@dummy)
- @client.recv(1).should be_empty
+ @client.recv(1).to_s.should be_empty
end
it 'shuts down a socket for reading and writing' do
@@ -139,7 +139,7 @@ platform_is_not :windows do # hangs
@client.shutdown(@dummy)
- @client.recv(1).should be_empty
+ @client.recv(1).to_s.should be_empty
-> { @client.write('hello') }.should raise_error(Errno::EPIPE)
end
diff --git a/spec/ruby/library/socket/fixtures/classes.rb b/spec/ruby/library/socket/fixtures/classes.rb
index 4a590502ca..786629d2ef 100644
--- a/spec/ruby/library/socket/fixtures/classes.rb
+++ b/spec/ruby/library/socket/fixtures/classes.rb
@@ -37,7 +37,9 @@ module SocketSpecs
# Check for too long unix socket path (max 104 bytes on macOS)
# Note that Linux accepts not null-terminated paths but the man page advises against it.
if path.bytesize > 104
- path = "/tmp/unix_server_spec.socket"
+ # rm_r in spec/mspec/lib/mspec/helpers/fs.rb fails against
+ # "/tmp/unix_server_spec.socket"
+ skip "too long unix socket path: #{path}"
end
rm_socket(path)
path
@@ -111,7 +113,7 @@ module SocketSpecs
begin
data = socket.recv(1024)
- return if data.empty?
+ return if data.nil? || data.empty?
log "SpecTCPServer received: #{data.inspect}"
return if data == "QUIT"
diff --git a/spec/ruby/library/socket/ipsocket/getaddress_spec.rb b/spec/ruby/library/socket/ipsocket/getaddress_spec.rb
index 746d2ab86b..96324982e5 100644
--- a/spec/ruby/library/socket/ipsocket/getaddress_spec.rb
+++ b/spec/ruby/library/socket/ipsocket/getaddress_spec.rb
@@ -19,7 +19,7 @@ describe "Socket::IPSocket#getaddress" do
# traditionally invalidly named ones.
it "raises an error on unknown hostnames" do
-> {
- IPSocket.getaddress("rubyspecdoesntexist.fallingsnow.net")
+ IPSocket.getaddress("rubyspecdoesntexist.ruby-lang.org")
}.should raise_error(SocketError)
end
end
diff --git a/spec/ruby/library/socket/shared/pack_sockaddr.rb b/spec/ruby/library/socket/shared/pack_sockaddr.rb
index 2df09027c9..26fdf682b1 100644
--- a/spec/ruby/library/socket/shared/pack_sockaddr.rb
+++ b/spec/ruby/library/socket/shared/pack_sockaddr.rb
@@ -17,6 +17,16 @@ describe :socket_pack_sockaddr_in, shared: true do
sockaddr_in = Socket.public_send(@method, nil, '127.0.0.1')
Socket.unpack_sockaddr_in(sockaddr_in).should == [0, '127.0.0.1']
+
+ sockaddr_in = Socket.public_send(@method, 80, Socket::INADDR_ANY)
+ Socket.unpack_sockaddr_in(sockaddr_in).should == [80, '0.0.0.0']
+ end
+
+ platform_is_not :solaris do
+ it 'resolves the service name to a port' do
+ sockaddr_in = Socket.public_send(@method, 'http', '127.0.0.1')
+ Socket.unpack_sockaddr_in(sockaddr_in).should == [80, '127.0.0.1']
+ end
end
describe 'using an IPv4 address' do
diff --git a/spec/ruby/library/socket/shared/partially_closable_sockets.rb b/spec/ruby/library/socket/shared/partially_closable_sockets.rb
index 1bdff08bf6..b1c2ebabe1 100644
--- a/spec/ruby/library/socket/shared/partially_closable_sockets.rb
+++ b/spec/ruby/library/socket/shared/partially_closable_sockets.rb
@@ -1,4 +1,4 @@
-describe "partially closable sockets", shared: true do
+describe :partially_closable_sockets, shared: true do
it "if the write end is closed then the other side can read past EOF without blocking" do
@s1.write("foo")
@s1.close_write
diff --git a/spec/ruby/library/socket/socket/getnameinfo_spec.rb b/spec/ruby/library/socket/socket/getnameinfo_spec.rb
index b406348aa8..4f13bf484d 100644
--- a/spec/ruby/library/socket/socket/getnameinfo_spec.rb
+++ b/spec/ruby/library/socket/socket/getnameinfo_spec.rb
@@ -70,7 +70,7 @@ describe 'Socket.getnameinfo' do
it 'raises SocketError or TypeError when using an invalid String' do
-> { Socket.getnameinfo('cats') }.should raise_error(Exception) { |e|
- [SocketError, TypeError].should include(e.class)
+ (e.is_a?(SocketError) || e.is_a?(TypeError)).should == true
}
end
diff --git a/spec/ruby/library/socket/socket/new_spec.rb b/spec/ruby/library/socket/socket/new_spec.rb
deleted file mode 100644
index b2ec607f6a..0000000000
--- a/spec/ruby/library/socket/socket/new_spec.rb
+++ /dev/null
@@ -1,2 +0,0 @@
-require_relative '../spec_helper'
-require_relative '../fixtures/classes'
diff --git a/spec/ruby/library/socket/socket/pack_sockaddr_in_spec.rb b/spec/ruby/library/socket/socket/pack_sockaddr_in_spec.rb
index 63d4724453..ef2a2d4ba9 100644
--- a/spec/ruby/library/socket/socket/pack_sockaddr_in_spec.rb
+++ b/spec/ruby/library/socket/socket/pack_sockaddr_in_spec.rb
@@ -2,6 +2,6 @@ require_relative '../spec_helper'
require_relative '../fixtures/classes'
require_relative '../shared/pack_sockaddr'
-describe "Socket#pack_sockaddr_in" do
+describe "Socket.pack_sockaddr_in" do
it_behaves_like :socket_pack_sockaddr_in, :pack_sockaddr_in
end
diff --git a/spec/ruby/library/socket/socket/pair_spec.rb b/spec/ruby/library/socket/socket/pair_spec.rb
index 292eacd38d..8dd470a95e 100644
--- a/spec/ruby/library/socket/socket/pair_spec.rb
+++ b/spec/ruby/library/socket/socket/pair_spec.rb
@@ -2,6 +2,6 @@ require_relative '../spec_helper'
require_relative '../fixtures/classes'
require_relative '../shared/socketpair'
-describe "Socket#pair" do
+describe "Socket.pair" do
it_behaves_like :socket_socketpair, :pair
end
diff --git a/spec/ruby/library/socket/socket/socketpair_spec.rb b/spec/ruby/library/socket/socket/socketpair_spec.rb
index 5b8311124e..551c376d49 100644
--- a/spec/ruby/library/socket/socket/socketpair_spec.rb
+++ b/spec/ruby/library/socket/socket/socketpair_spec.rb
@@ -2,6 +2,6 @@ require_relative '../spec_helper'
require_relative '../fixtures/classes'
require_relative '../shared/socketpair'
-describe "Socket#socketpair" do
+describe "Socket.socketpair" do
it_behaves_like :socket_socketpair, :socketpair
end
diff --git a/spec/ruby/library/socket/tcpserver/accept_spec.rb b/spec/ruby/library/socket/tcpserver/accept_spec.rb
index d38d95e0e1..d8892cd5f0 100644
--- a/spec/ruby/library/socket/tcpserver/accept_spec.rb
+++ b/spec/ruby/library/socket/tcpserver/accept_spec.rb
@@ -69,7 +69,7 @@ describe "TCPServer#accept" do
Thread.pass while t.status and t.status != "sleep"
# Thread#backtrace uses SIGVTALRM on TruffleRuby and potentially other implementations.
# Sending a signal to a thread is not possible with Ruby APIs.
- t.backtrace.join("\n").should.include?("in `accept'")
+ t.backtrace.join("\n").should =~ /in [`'](?:TCPServer#)?accept'/
socket = TCPSocket.new('127.0.0.1', @port)
socket.write("OK")
@@ -114,6 +114,19 @@ describe 'TCPServer#accept' do
@socket = @server.accept
@socket.should be_an_instance_of(TCPSocket)
end
+
+ platform_is_not :windows do
+ it "returns a TCPSocket which is set to nonblocking" do
+ require 'io/nonblock'
+ @socket = @server.accept
+ @socket.should.nonblock?
+ end
+ end
+
+ it "returns a TCPSocket which is set to close on exec" do
+ @socket = @server.accept
+ @socket.should.close_on_exec?
+ end
end
end
end
diff --git a/spec/ruby/library/socket/tcpserver/new_spec.rb b/spec/ruby/library/socket/tcpserver/new_spec.rb
index 8d9696c9d8..dd1ba676bd 100644
--- a/spec/ruby/library/socket/tcpserver/new_spec.rb
+++ b/spec/ruby/library/socket/tcpserver/new_spec.rb
@@ -97,6 +97,12 @@ describe "TCPServer.new" do
addr[1].should be_kind_of(Integer)
end
+ it "does not use the given block and warns to use TCPServer::open" do
+ -> {
+ @server = TCPServer.new(0) { raise }
+ }.should complain(/warning: TCPServer::new\(\) does not take block; use TCPServer::open\(\) instead/)
+ end
+
it "raises Errno::EADDRNOTAVAIL when the address is unknown" do
-> { TCPServer.new("1.2.3.4", 0) }.should raise_error(Errno::EADDRNOTAVAIL)
end
diff --git a/spec/ruby/library/socket/tcpsocket/initialize_spec.rb b/spec/ruby/library/socket/tcpsocket/initialize_spec.rb
index 065c8f4190..d7feb9751b 100644
--- a/spec/ruby/library/socket/tcpsocket/initialize_spec.rb
+++ b/spec/ruby/library/socket/tcpsocket/initialize_spec.rb
@@ -4,6 +4,27 @@ require_relative 'shared/new'
describe 'TCPSocket#initialize' do
it_behaves_like :tcpsocket_new, :new
+
+ describe "with a running server" do
+ before :each do
+ @server = SocketSpecs::SpecTCPServer.new
+ @hostname = @server.hostname
+ end
+
+ after :each do
+ if @socket
+ @socket.write "QUIT"
+ @socket.close
+ end
+ @server.shutdown
+ end
+
+ it "does not use the given block and warns to use TCPSocket::open" do
+ -> {
+ @socket = TCPSocket.new(@hostname, @server.port, nil) { raise }
+ }.should complain(/warning: TCPSocket::new\(\) does not take block; use TCPSocket::open\(\) instead/)
+ end
+ end
end
describe 'TCPSocket#initialize' do
@@ -51,6 +72,19 @@ describe 'TCPSocket#initialize' do
@client.remote_address.ip_port.should == @server.local_address.ip_port
end
+ platform_is_not :windows do
+ it "creates a socket which is set to nonblocking" do
+ require 'io/nonblock'
+ @client = TCPSocket.new(ip_address, @port)
+ @client.should.nonblock?
+ end
+ end
+
+ it "creates a socket which is set to close on exec" do
+ @client = TCPSocket.new(ip_address, @port)
+ @client.should.close_on_exec?
+ end
+
describe 'using a local address and service' do
it 'binds the client socket to the local address and service' do
@client = TCPSocket.new(ip_address, @port, ip_address, 0)
diff --git a/spec/ruby/library/socket/tcpsocket/open_spec.rb b/spec/ruby/library/socket/tcpsocket/open_spec.rb
index 31b630a23b..0c0b579064 100644
--- a/spec/ruby/library/socket/tcpsocket/open_spec.rb
+++ b/spec/ruby/library/socket/tcpsocket/open_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
require_relative 'shared/new'
describe "TCPSocket.open" do
diff --git a/spec/ruby/library/socket/tcpsocket/partially_closable_spec.rb b/spec/ruby/library/socket/tcpsocket/partially_closable_spec.rb
index a381627a39..d365ecd335 100644
--- a/spec/ruby/library/socket/tcpsocket/partially_closable_spec.rb
+++ b/spec/ruby/library/socket/tcpsocket/partially_closable_spec.rb
@@ -16,6 +16,6 @@ describe "TCPSocket partial closability" do
@s2.close
end
- it_should_behave_like "partially closable sockets"
+ it_should_behave_like :partially_closable_sockets
end
diff --git a/spec/ruby/library/socket/tcpsocket/shared/new.rb b/spec/ruby/library/socket/tcpsocket/shared/new.rb
index 4189acc2f8..90f8d7e6a2 100644
--- a/spec/ruby/library/socket/tcpsocket/shared/new.rb
+++ b/spec/ruby/library/socket/tcpsocket/shared/new.rb
@@ -14,11 +14,25 @@ describe :tcpsocket_new, shared: true do
}
end
- ruby_version_is "3.0" do
+ ruby_version_is ""..."3.2" do
it 'raises Errno::ETIMEDOUT with :connect_timeout when no server is listening on the given address' do
-> {
TCPSocket.send(@method, "192.0.2.1", 80, connect_timeout: 0)
}.should raise_error(Errno::ETIMEDOUT)
+ rescue Errno::ENETUNREACH
+ # In the case all network interfaces down.
+ # raise_error cannot deal with multiple expected exceptions
+ end
+ end
+
+ ruby_version_is "3.2" do
+ it 'raises IO::TimeoutError with :connect_timeout when no server is listening on the given address' do
+ -> {
+ TCPSocket.send(@method, "192.0.2.1", 80, connect_timeout: 0)
+ }.should raise_error(IO::TimeoutError)
+ rescue Errno::ENETUNREACH
+ # In the case all network interfaces down.
+ # raise_error cannot deal with multiple expected exceptions
end
end
@@ -84,11 +98,9 @@ describe :tcpsocket_new, shared: true do
@socket.addr[2].should =~ /^#{@hostname}/
end
- ruby_version_is "3.0" do
- it "connects to a server when passed connect_timeout argument" do
- @socket = TCPSocket.send(@method, @hostname, @server.port, connect_timeout: 1)
- @socket.should be_an_instance_of(TCPSocket)
- end
+ it "connects to a server when passed connect_timeout argument" do
+ @socket = TCPSocket.send(@method, @hostname, @server.port, connect_timeout: 1)
+ @socket.should be_an_instance_of(TCPSocket)
end
end
end
diff --git a/spec/ruby/library/socket/udpsocket/initialize_spec.rb b/spec/ruby/library/socket/udpsocket/initialize_spec.rb
index 1d635149f7..ecf0043c10 100644
--- a/spec/ruby/library/socket/udpsocket/initialize_spec.rb
+++ b/spec/ruby/library/socket/udpsocket/initialize_spec.rb
@@ -30,6 +30,19 @@ describe 'UDPSocket#initialize' do
@socket.binmode?.should be_true
end
+ platform_is_not :windows do
+ it 'sets the socket to nonblock' do
+ require 'io/nonblock'
+ @socket = UDPSocket.new(:INET)
+ @socket.should.nonblock?
+ end
+ end
+
+ it 'sets the socket to close on exec' do
+ @socket = UDPSocket.new(:INET)
+ @socket.should.close_on_exec?
+ end
+
it 'raises Errno::EAFNOSUPPORT or Errno::EPROTONOSUPPORT when given an invalid address family' do
-> {
UDPSocket.new(666)
diff --git a/spec/ruby/library/socket/udpsocket/new_spec.rb b/spec/ruby/library/socket/udpsocket/new_spec.rb
index 6cc0cadbcb..79bfcb624d 100644
--- a/spec/ruby/library/socket/udpsocket/new_spec.rb
+++ b/spec/ruby/library/socket/udpsocket/new_spec.rb
@@ -26,6 +26,12 @@ describe 'UDPSocket.new' do
@socket.should be_an_instance_of(UDPSocket)
end
+ it "does not use the given block and warns to use UDPSocket::open" do
+ -> {
+ @socket = UDPSocket.new { raise }
+ }.should complain(/warning: UDPSocket::new\(\) does not take block; use UDPSocket::open\(\) instead/)
+ end
+
it 'raises Errno::EAFNOSUPPORT or Errno::EPROTONOSUPPORT if unsupported family passed' do
-> { UDPSocket.new(-1) }.should raise_error(SystemCallError) { |e|
[Errno::EAFNOSUPPORT, Errno::EPROTONOSUPPORT].should include(e.class)
diff --git a/spec/ruby/library/socket/udpsocket/send_spec.rb b/spec/ruby/library/socket/udpsocket/send_spec.rb
index 5d5de684af..6dd5f67bea 100644
--- a/spec/ruby/library/socket/udpsocket/send_spec.rb
+++ b/spec/ruby/library/socket/udpsocket/send_spec.rb
@@ -63,7 +63,7 @@ describe "UDPSocket#send" do
@msg[1][3].should == "127.0.0.1"
end
- it "raises EMSGSIZE if data is too too big" do
+ it "raises EMSGSIZE if data is too big" do
@socket = UDPSocket.open
begin
-> do
diff --git a/spec/ruby/library/socket/unixserver/accept_nonblock_spec.rb b/spec/ruby/library/socket/unixserver/accept_nonblock_spec.rb
index 30688b46b6..dba3de7359 100644
--- a/spec/ruby/library/socket/unixserver/accept_nonblock_spec.rb
+++ b/spec/ruby/library/socket/unixserver/accept_nonblock_spec.rb
@@ -1,9 +1,8 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-describe "UNIXServer#accept_nonblock" do
-
- platform_is_not :windows do
+with_feature :unix_socket do
+ describe "UNIXServer#accept_nonblock" do
before :each do
@path = SocketSpecs.socket_path
@server = UNIXServer.open(@path)
@@ -33,9 +32,7 @@ describe "UNIXServer#accept_nonblock" do
@server.accept_nonblock(exception: false).should == :wait_readable
end
end
-end
-with_feature :unix_socket do
describe 'UNIXServer#accept_nonblock' do
before do
@path = SocketSpecs.socket_path
diff --git a/spec/ruby/library/socket/unixserver/accept_spec.rb b/spec/ruby/library/socket/unixserver/accept_spec.rb
index c05fbe7f22..1305bc6220 100644
--- a/spec/ruby/library/socket/unixserver/accept_spec.rb
+++ b/spec/ruby/library/socket/unixserver/accept_spec.rb
@@ -1,7 +1,7 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-platform_is_not :windows do
+with_feature :unix_socket do
describe "UNIXServer#accept" do
before :each do
@path = SocketSpecs.socket_path
@@ -110,6 +110,17 @@ with_feature :unix_socket do
@socket = @server.accept
@socket.recv(5).should == 'hello'
end
+
+ it "is set to nonblocking" do
+ require 'io/nonblock'
+ @socket = @server.accept
+ @socket.should.nonblock?
+ end
+
+ it "is set to close on exec" do
+ @socket = @server.accept
+ @socket.should.close_on_exec?
+ end
end
end
end
diff --git a/spec/ruby/library/socket/unixserver/for_fd_spec.rb b/spec/ruby/library/socket/unixserver/for_fd_spec.rb
index 4f3816ad37..8cc55ef391 100644
--- a/spec/ruby/library/socket/unixserver/for_fd_spec.rb
+++ b/spec/ruby/library/socket/unixserver/for_fd_spec.rb
@@ -1,8 +1,8 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-platform_is_not :windows do
- describe "UNIXServer#for_fd" do
+with_feature :unix_socket do
+ describe "UNIXServer.for_fd" do
before :each do
@unix_path = SocketSpecs.socket_path
@unix = UNIXServer.new(@unix_path)
diff --git a/spec/ruby/library/socket/unixserver/new_spec.rb b/spec/ruby/library/socket/unixserver/new_spec.rb
index f831f40bc6..a160e3ce5c 100644
--- a/spec/ruby/library/socket/unixserver/new_spec.rb
+++ b/spec/ruby/library/socket/unixserver/new_spec.rb
@@ -1,6 +1,14 @@
require_relative '../spec_helper'
require_relative 'shared/new'
-describe "UNIXServer.new" do
- it_behaves_like :unixserver_new, :new
+with_feature :unix_socket do
+ describe "UNIXServer.new" do
+ it_behaves_like :unixserver_new, :new
+
+ it "does not use the given block and warns to use UNIXServer::open" do
+ -> {
+ @server = UNIXServer.new(@path) { raise }
+ }.should complain(/warning: UNIXServer::new\(\) does not take block; use UNIXServer::open\(\) instead/)
+ end
+ end
end
diff --git a/spec/ruby/library/socket/unixserver/open_spec.rb b/spec/ruby/library/socket/unixserver/open_spec.rb
index f2506d9f6f..16453dd3bd 100644
--- a/spec/ruby/library/socket/unixserver/open_spec.rb
+++ b/spec/ruby/library/socket/unixserver/open_spec.rb
@@ -2,10 +2,10 @@ require_relative '../spec_helper'
require_relative '../fixtures/classes'
require_relative 'shared/new'
-describe "UNIXServer.open" do
- it_behaves_like :unixserver_new, :open
+with_feature :unix_socket do
+ describe "UNIXServer.open" do
+ it_behaves_like :unixserver_new, :open
- platform_is_not :windows do
before :each do
@path = SocketSpecs.socket_path
end
diff --git a/spec/ruby/library/socket/unixserver/shared/new.rb b/spec/ruby/library/socket/unixserver/shared/new.rb
index 35395826c9..b537f2a871 100644
--- a/spec/ruby/library/socket/unixserver/shared/new.rb
+++ b/spec/ruby/library/socket/unixserver/shared/new.rb
@@ -2,21 +2,19 @@ require_relative '../../spec_helper'
require_relative '../../fixtures/classes'
describe :unixserver_new, shared: true do
- platform_is_not :windows do
- before :each do
- @path = SocketSpecs.socket_path
- end
+ before :each do
+ @path = SocketSpecs.socket_path
+ end
- after :each do
- @server.close if @server
- @server = nil
- SocketSpecs.rm_socket @path
- end
+ after :each do
+ @server.close if @server
+ @server = nil
+ SocketSpecs.rm_socket @path
+ end
- it "creates a new UNIXServer" do
- @server = UNIXServer.send(@method, @path)
- @server.path.should == @path
- @server.addr.should == ["AF_UNIX", @path]
- end
+ it "creates a new UNIXServer" do
+ @server = UNIXServer.send(@method, @path)
+ @server.path.should == @path
+ @server.addr.should == ["AF_UNIX", @path]
end
end
diff --git a/spec/ruby/library/socket/unixsocket/addr_spec.rb b/spec/ruby/library/socket/unixsocket/addr_spec.rb
index e8431bea16..d93e061312 100644
--- a/spec/ruby/library/socket/unixsocket/addr_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/addr_spec.rb
@@ -1,9 +1,8 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-describe "UNIXSocket#addr" do
-
- platform_is_not :windows do
+with_feature :unix_socket do
+ describe "UNIXSocket#addr" do
before :each do
@path = SocketSpecs.socket_path
@server = UNIXServer.open(@path)
diff --git a/spec/ruby/library/socket/unixsocket/initialize_spec.rb b/spec/ruby/library/socket/unixsocket/initialize_spec.rb
index 13b6972f03..bf7896ab0e 100644
--- a/spec/ruby/library/socket/unixsocket/initialize_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/initialize_spec.rb
@@ -33,6 +33,16 @@ with_feature :unix_socket do
it 'sets the socket to binmode' do
@socket.binmode?.should be_true
end
+
+ it 'sets the socket to nonblock' do
+ require 'io/nonblock'
+ @socket.should.nonblock?
+ end
+
+ it 'sets the socket to close on exec' do
+ @socket.should.close_on_exec?
+ end
+
end
end
end
diff --git a/spec/ruby/library/socket/unixsocket/inspect_spec.rb b/spec/ruby/library/socket/unixsocket/inspect_spec.rb
index d2e3cabbd3..a542ba6db5 100644
--- a/spec/ruby/library/socket/unixsocket/inspect_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/inspect_spec.rb
@@ -1,8 +1,8 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-describe "UNIXSocket#inspect" do
- platform_is_not :windows do
+with_feature :unix_socket do
+ describe "UNIXSocket#inspect" do
it "returns sockets fd for unnamed sockets" do
begin
s1, s2 = UNIXSocket.socketpair
diff --git a/spec/ruby/library/socket/unixsocket/local_address_spec.rb b/spec/ruby/library/socket/unixsocket/local_address_spec.rb
index cbf315f9f4..734253e7f5 100644
--- a/spec/ruby/library/socket/unixsocket/local_address_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/local_address_spec.rb
@@ -46,9 +46,7 @@ with_feature :unix_socket do
end
end
end
-end
-with_feature :unix_socket do
describe 'UNIXSocket#local_address with a UNIX socket pair' do
before :each do
@sock, @sock2 = Socket.pair(Socket::AF_UNIX, Socket::SOCK_STREAM)
diff --git a/spec/ruby/library/socket/unixsocket/new_spec.rb b/spec/ruby/library/socket/unixsocket/new_spec.rb
index 05a6b3eda2..6d8ea6dcfe 100644
--- a/spec/ruby/library/socket/unixsocket/new_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/new_spec.rb
@@ -1,6 +1,14 @@
require_relative '../spec_helper'
require_relative 'shared/new'
-describe "UNIXSocket.new" do
- it_behaves_like :unixsocket_new, :new
+with_feature :unix_socket do
+ describe "UNIXSocket.new" do
+ it_behaves_like :unixsocket_new, :new
+
+ it "does not use the given block and warns to use UNIXSocket::open" do
+ -> {
+ @client = UNIXSocket.new(@path) { raise }
+ }.should complain(/warning: UNIXSocket::new\(\) does not take block; use UNIXSocket::open\(\) instead/)
+ end
+ end
end
diff --git a/spec/ruby/library/socket/unixsocket/open_spec.rb b/spec/ruby/library/socket/unixsocket/open_spec.rb
index 99ad151bb8..61def30abb 100644
--- a/spec/ruby/library/socket/unixsocket/open_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/open_spec.rb
@@ -2,12 +2,12 @@ require_relative '../spec_helper'
require_relative '../fixtures/classes'
require_relative 'shared/new'
-describe "UNIXSocket.open" do
- it_behaves_like :unixsocket_new, :open
-end
+with_feature :unix_socket do
+ describe "UNIXSocket.open" do
+ it_behaves_like :unixsocket_new, :open
+ end
-describe "UNIXSocket.open" do
- platform_is_not :windows do
+ describe "UNIXSocket.open" do
before :each do
@path = SocketSpecs.socket_path
@server = UNIXServer.open(@path)
diff --git a/spec/ruby/library/socket/unixsocket/pair_spec.rb b/spec/ruby/library/socket/unixsocket/pair_spec.rb
index 845ff76ecc..d80b60894d 100644
--- a/spec/ruby/library/socket/unixsocket/pair_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/pair_spec.rb
@@ -2,10 +2,9 @@ require_relative '../spec_helper'
require_relative '../fixtures/classes'
require_relative '../shared/partially_closable_sockets'
-describe "UNIXSocket#pair" do
- platform_is_not :windows do
-
- it_should_behave_like "partially closable sockets"
+with_feature :unix_socket do
+ describe "UNIXSocket.pair" do
+ it_should_behave_like :partially_closable_sockets
before :each do
@s1, @s2 = UNIXSocket.pair
diff --git a/spec/ruby/library/socket/unixsocket/partially_closable_spec.rb b/spec/ruby/library/socket/unixsocket/partially_closable_spec.rb
index 78a64fe6be..ef7d0f0b2a 100644
--- a/spec/ruby/library/socket/unixsocket/partially_closable_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/partially_closable_spec.rb
@@ -2,9 +2,8 @@ require_relative '../spec_helper'
require_relative '../fixtures/classes'
require_relative '../shared/partially_closable_sockets'
-platform_is_not :windows do
+with_feature :unix_socket do
describe "UNIXSocket partial closability" do
-
before :each do
@path = SocketSpecs.socket_path
@server = UNIXServer.open(@path)
@@ -19,7 +18,6 @@ platform_is_not :windows do
SocketSpecs.rm_socket @path
end
- it_should_behave_like "partially closable sockets"
-
+ it_should_behave_like :partially_closable_sockets
end
end
diff --git a/spec/ruby/library/socket/unixsocket/path_spec.rb b/spec/ruby/library/socket/unixsocket/path_spec.rb
index 317ffc0975..a608378e4f 100644
--- a/spec/ruby/library/socket/unixsocket/path_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/path_spec.rb
@@ -1,9 +1,8 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-describe "UNIXSocket#path" do
-
- platform_is_not :windows do
+with_feature :unix_socket do
+ describe "UNIXSocket#path" do
before :each do
@path = SocketSpecs.socket_path
@server = UNIXServer.open(@path)
@@ -24,5 +23,4 @@ describe "UNIXSocket#path" do
@client.path.should == ""
end
end
-
end
diff --git a/spec/ruby/library/socket/unixsocket/peeraddr_spec.rb b/spec/ruby/library/socket/unixsocket/peeraddr_spec.rb
index 0b6b1ccf04..72bc96b1fe 100644
--- a/spec/ruby/library/socket/unixsocket/peeraddr_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/peeraddr_spec.rb
@@ -1,9 +1,8 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-describe "UNIXSocket#peeraddr" do
-
- platform_is_not :windows do
+with_feature :unix_socket do
+ describe "UNIXSocket#peeraddr" do
before :each do
@path = SocketSpecs.socket_path
@server = UNIXServer.open(@path)
@@ -26,5 +25,4 @@ describe "UNIXSocket#peeraddr" do
}.should raise_error(Errno::ENOTCONN)
end
end
-
end
diff --git a/spec/ruby/library/socket/unixsocket/recv_io_spec.rb b/spec/ruby/library/socket/unixsocket/recv_io_spec.rb
index 533f02a0fa..1dbc4538e3 100644
--- a/spec/ruby/library/socket/unixsocket/recv_io_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/recv_io_spec.rb
@@ -1,9 +1,8 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-describe "UNIXSocket#recv_io" do
-
- platform_is_not :windows do
+with_feature :unix_socket do
+ describe "UNIXSocket#recv_io" do
before :each do
@path = SocketSpecs.socket_path
@server = UNIXServer.open(@path)
@@ -41,9 +40,7 @@ describe "UNIXSocket#recv_io" do
@io.should be_an_instance_of(File)
end
end
-end
-with_feature :unix_socket do
describe 'UNIXSocket#recv_io' do
before do
@file = File.open('/dev/null', 'w')
diff --git a/spec/ruby/library/socket/unixsocket/recvfrom_spec.rb b/spec/ruby/library/socket/unixsocket/recvfrom_spec.rb
index c0e1cf670b..fedf74bb2f 100644
--- a/spec/ruby/library/socket/unixsocket/recvfrom_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/recvfrom_spec.rb
@@ -1,8 +1,8 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-describe "UNIXSocket#recvfrom" do
- platform_is_not :windows do
+with_feature :unix_socket do
+ describe "UNIXSocket#recvfrom" do
before :each do
@path = SocketSpecs.socket_path
@server = UNIXServer.open(@path)
@@ -42,10 +42,7 @@ describe "UNIXSocket#recvfrom" do
sock.close
end
end
-end
-
-with_feature :unix_socket do
describe 'UNIXSocket#recvfrom' do
describe 'using a socket pair' do
before do
diff --git a/spec/ruby/library/socket/unixsocket/send_io_spec.rb b/spec/ruby/library/socket/unixsocket/send_io_spec.rb
index a2a7d26539..80f3550c6d 100644
--- a/spec/ruby/library/socket/unixsocket/send_io_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/send_io_spec.rb
@@ -1,9 +1,8 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
-describe "UNIXSocket#send_io" do
-
- platform_is_not :windows do
+with_feature :unix_socket do
+ describe "UNIXSocket#send_io" do
before :each do
@path = SocketSpecs.socket_path
@server = UNIXServer.open(@path)
@@ -32,9 +31,7 @@ describe "UNIXSocket#send_io" do
@io.read.should == File.read(@send_io_path)
end
end
-end
-with_feature :unix_socket do
describe 'UNIXSocket#send_io' do
before do
@file = File.open('/dev/null', 'w')
diff --git a/spec/ruby/library/socket/unixsocket/shared/new.rb b/spec/ruby/library/socket/unixsocket/shared/new.rb
index bfb7ed3886..f075b03c5e 100644
--- a/spec/ruby/library/socket/unixsocket/shared/new.rb
+++ b/spec/ruby/library/socket/unixsocket/shared/new.rb
@@ -2,23 +2,21 @@ require_relative '../../spec_helper'
require_relative '../../fixtures/classes'
describe :unixsocket_new, shared: true do
- platform_is_not :windows do
- before :each do
- @path = SocketSpecs.socket_path
- @server = UNIXServer.open(@path)
- end
+ before :each do
+ @path = SocketSpecs.socket_path
+ @server = UNIXServer.open(@path)
+ end
- after :each do
- @client.close if @client
- @server.close
- SocketSpecs.rm_socket @path
- end
+ after :each do
+ @client.close if @client
+ @server.close
+ SocketSpecs.rm_socket @path
+ end
- it "opens a unix socket on the specified file" do
- @client = UNIXSocket.send(@method, @path)
+ it "opens a unix socket on the specified file" do
+ @client = UNIXSocket.send(@method, @path)
- @client.addr[0].should == "AF_UNIX"
- @client.should_not.closed?
- end
+ @client.addr[0].should == "AF_UNIX"
+ @client.should_not.closed?
end
end
diff --git a/spec/ruby/library/stringio/append_spec.rb b/spec/ruby/library/stringio/append_spec.rb
index d0cf5550cd..cb50d73d1b 100644
--- a/spec/ruby/library/stringio/append_spec.rb
+++ b/spec/ruby/library/stringio/append_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "StringIO#<< when passed [Object]" do
before :each do
- @io = StringIO.new("example")
+ @io = StringIO.new(+"example")
end
it "returns self" do
@@ -29,20 +29,6 @@ describe "StringIO#<< when passed [Object]" do
@io.string.should == "example\000\000\000\000\000\000\000\000just testing"
end
- ruby_version_is ""..."2.7" do
- it "taints self's String when the passed argument is tainted" do
- (@io << "test".taint)
- @io.string.tainted?.should be_true
- end
- end
-
- ruby_version_is ""..."3.0" do
- it "does not taint self when the passed argument is tainted" do
- (@io << "test".taint)
- @io.tainted?.should be_false
- end
- end
-
it "updates self's position" do
@io << "test"
@io.pos.should eql(4)
@@ -58,10 +44,10 @@ end
describe "StringIO#<< when self is not writable" do
it "raises an IOError" do
- io = StringIO.new("test", "r")
+ io = StringIO.new(+"test", "r")
-> { io << "test" }.should raise_error(IOError)
- io = StringIO.new("test")
+ io = StringIO.new(+"test")
io.close_write
-> { io << "test" }.should raise_error(IOError)
end
@@ -69,7 +55,7 @@ end
describe "StringIO#<< when in append mode" do
before :each do
- @io = StringIO.new("example", "a")
+ @io = StringIO.new(+"example", "a")
end
it "appends the passed argument to the end of self, ignoring current position" do
diff --git a/spec/ruby/library/stringio/binmode_spec.rb b/spec/ruby/library/stringio/binmode_spec.rb
index 853d9c9bd6..9e92c63814 100644
--- a/spec/ruby/library/stringio/binmode_spec.rb
+++ b/spec/ruby/library/stringio/binmode_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "StringIO#binmode" do
it "returns self" do
- io = StringIO.new("example")
+ io = StringIO.new(+"example")
io.binmode.should equal(io)
end
diff --git a/spec/ruby/library/stringio/bytes_spec.rb b/spec/ruby/library/stringio/bytes_spec.rb
deleted file mode 100644
index 4ef7a490a5..0000000000
--- a/spec/ruby/library/stringio/bytes_spec.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-require_relative '../../spec_helper'
-require 'stringio'
-require_relative 'shared/each_byte'
-
-ruby_version_is ''...'3.0' do
- describe "StringIO#bytes" do
- before :each do
- @verbose, $VERBOSE = $VERBOSE, nil
- end
-
- after :each do
- $VERBOSE = @verbose
- end
-
- it_behaves_like :stringio_each_byte, :bytes
- end
-
- describe "StringIO#bytes when self is not readable" do
- before :each do
- @verbose, $VERBOSE = $VERBOSE, nil
- end
-
- after :each do
- $VERBOSE = @verbose
- end
-
- it_behaves_like :stringio_each_byte_not_readable, :bytes
- end
-end
diff --git a/spec/ruby/library/stringio/chars_spec.rb b/spec/ruby/library/stringio/chars_spec.rb
deleted file mode 100644
index 58cba77634..0000000000
--- a/spec/ruby/library/stringio/chars_spec.rb
+++ /dev/null
@@ -1,29 +0,0 @@
-require_relative '../../spec_helper'
-require 'stringio'
-require_relative 'shared/each_char'
-
-ruby_version_is ''...'3.0' do
- describe "StringIO#chars" do
- before :each do
- @verbose, $VERBOSE = $VERBOSE, nil
- end
-
- after :each do
- $VERBOSE = @verbose
- end
-
- it_behaves_like :stringio_each_char, :chars
- end
-
- describe "StringIO#chars when self is not readable" do
- before :each do
- @verbose, $VERBOSE = $VERBOSE, nil
- end
-
- after :each do
- $VERBOSE = @verbose
- end
-
- it_behaves_like :stringio_each_char_not_readable, :chars
- end
-end
diff --git a/spec/ruby/library/stringio/close_read_spec.rb b/spec/ruby/library/stringio/close_read_spec.rb
index 80bd547e85..0f08e1ff2e 100644
--- a/spec/ruby/library/stringio/close_read_spec.rb
+++ b/spec/ruby/library/stringio/close_read_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "StringIO#close_read" do
before :each do
- @io = StringIO.new("example")
+ @io = StringIO.new(+"example")
end
it "returns nil" do
@@ -21,7 +21,7 @@ describe "StringIO#close_read" do
end
it "raises an IOError when in write-only mode" do
- io = StringIO.new("example", "w")
+ io = StringIO.new(+"example", "w")
-> { io.close_read }.should raise_error(IOError)
io = StringIO.new("example")
diff --git a/spec/ruby/library/stringio/close_write_spec.rb b/spec/ruby/library/stringio/close_write_spec.rb
index 1a4cfa113e..c86c3f9826 100644
--- a/spec/ruby/library/stringio/close_write_spec.rb
+++ b/spec/ruby/library/stringio/close_write_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "StringIO#close_write" do
before :each do
- @io = StringIO.new("example")
+ @io = StringIO.new(+"example")
end
it "returns nil" do
@@ -21,10 +21,10 @@ describe "StringIO#close_write" do
end
it "raises an IOError when in read-only mode" do
- io = StringIO.new("example", "r")
+ io = StringIO.new(+"example", "r")
-> { io.close_write }.should raise_error(IOError)
- io = StringIO.new("example")
+ io = StringIO.new(+"example")
io.close_write
io.close_write.should == nil
end
diff --git a/spec/ruby/library/stringio/closed_read_spec.rb b/spec/ruby/library/stringio/closed_read_spec.rb
index cb4267ac98..b4dcadc3a4 100644
--- a/spec/ruby/library/stringio/closed_read_spec.rb
+++ b/spec/ruby/library/stringio/closed_read_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "StringIO#closed_read?" do
it "returns true if self is not readable" do
- io = StringIO.new("example", "r+")
+ io = StringIO.new(+"example", "r+")
io.close_write
io.closed_read?.should be_false
io.close_read
diff --git a/spec/ruby/library/stringio/closed_spec.rb b/spec/ruby/library/stringio/closed_spec.rb
index ca8a2232a8..bf7ba63184 100644
--- a/spec/ruby/library/stringio/closed_spec.rb
+++ b/spec/ruby/library/stringio/closed_spec.rb
@@ -3,13 +3,13 @@ require_relative 'fixtures/classes'
describe "StringIO#closed?" do
it "returns true if self is completely closed" do
- io = StringIO.new("example", "r+")
+ io = StringIO.new(+"example", "r+")
io.close_read
io.closed?.should be_false
io.close_write
io.closed?.should be_true
- io = StringIO.new("example", "r+")
+ io = StringIO.new(+"example", "r+")
io.close
io.closed?.should be_true
end
diff --git a/spec/ruby/library/stringio/closed_write_spec.rb b/spec/ruby/library/stringio/closed_write_spec.rb
index 5c111affd8..2bd3e6fa8b 100644
--- a/spec/ruby/library/stringio/closed_write_spec.rb
+++ b/spec/ruby/library/stringio/closed_write_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "StringIO#closed_write?" do
it "returns true if self is not writable" do
- io = StringIO.new("example", "r+")
+ io = StringIO.new(+"example", "r+")
io.close_read
io.closed_write?.should be_false
io.close_write
diff --git a/spec/ruby/library/stringio/codepoints_spec.rb b/spec/ruby/library/stringio/codepoints_spec.rb
deleted file mode 100644
index ceaadefc32..0000000000
--- a/spec/ruby/library/stringio/codepoints_spec.rb
+++ /dev/null
@@ -1,19 +0,0 @@
-# -*- encoding: utf-8 -*-
-require_relative '../../spec_helper'
-require_relative 'fixtures/classes'
-require_relative 'shared/codepoints'
-
-ruby_version_is ''...'3.0' do
- # See redmine #1667
- describe "StringIO#codepoints" do
- before :each do
- @verbose, $VERBOSE = $VERBOSE, nil
- end
-
- after :each do
- $VERBOSE = @verbose
- end
-
- it_behaves_like :stringio_codepoints, :codepoints
- end
-end
diff --git a/spec/ruby/library/stringio/each_line_spec.rb b/spec/ruby/library/stringio/each_line_spec.rb
index 1389408399..c68f7dae82 100644
--- a/spec/ruby/library/stringio/each_line_spec.rb
+++ b/spec/ruby/library/stringio/each_line_spec.rb
@@ -17,3 +17,7 @@ end
describe "StringIO#each_line when passed chomp" do
it_behaves_like :stringio_each_chomp, :each_line
end
+
+describe "StringIO#each_line when passed limit" do
+ it_behaves_like :stringio_each_limit, :each_line
+end
diff --git a/spec/ruby/library/stringio/each_spec.rb b/spec/ruby/library/stringio/each_spec.rb
index a76460049b..2c30ed5cda 100644
--- a/spec/ruby/library/stringio/each_spec.rb
+++ b/spec/ruby/library/stringio/each_spec.rb
@@ -17,3 +17,11 @@ end
describe "StringIO#each when passed chomp" do
it_behaves_like :stringio_each_chomp, :each
end
+
+describe "StringIO#each when passed chomp" do
+ it_behaves_like :stringio_each_separator_and_chomp, :each
+end
+
+describe "StringIO#each when passed limit" do
+ it_behaves_like :stringio_each_limit, :each
+end
diff --git a/spec/ruby/library/stringio/flush_spec.rb b/spec/ruby/library/stringio/flush_spec.rb
index 17a16dfdd5..4dc58b1d48 100644
--- a/spec/ruby/library/stringio/flush_spec.rb
+++ b/spec/ruby/library/stringio/flush_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "StringIO#flush" do
it "returns self" do
- io = StringIO.new("flush")
+ io = StringIO.new(+"flush")
io.flush.should equal(io)
end
end
diff --git a/spec/ruby/library/stringio/fsync_spec.rb b/spec/ruby/library/stringio/fsync_spec.rb
index 8fb2b59a24..85053cb2e5 100644
--- a/spec/ruby/library/stringio/fsync_spec.rb
+++ b/spec/ruby/library/stringio/fsync_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "StringIO#fsync" do
it "returns zero" do
- io = StringIO.new("fsync")
+ io = StringIO.new(+"fsync")
io.fsync.should eql(0)
end
end
diff --git a/spec/ruby/library/stringio/gets_spec.rb b/spec/ruby/library/stringio/gets_spec.rb
index 97429e6a29..4af7704a41 100644
--- a/spec/ruby/library/stringio/gets_spec.rb
+++ b/spec/ruby/library/stringio/gets_spec.rb
@@ -171,6 +171,10 @@ describe "StringIO#gets when passed [limit]" do
it "returns a blank string when passed a limit of 0" do
@io.gets(0).should == ""
end
+
+ it "ignores it when passed a negative limit" do
+ @io.gets(-4).should == "this>is>an>example"
+ end
end
describe "StringIO#gets when passed [separator] and [limit]" do
@@ -229,7 +233,7 @@ end
describe "StringIO#gets when in write-only mode" do
it "raises an IOError" do
- io = StringIO.new("xyz", "w")
+ io = StringIO.new(+"xyz", "w")
-> { io.gets }.should raise_error(IOError)
io = StringIO.new("xyz")
diff --git a/spec/ruby/library/stringio/initialize_spec.rb b/spec/ruby/library/stringio/initialize_spec.rb
index 1e8096e3bb..ad067a0be1 100644
--- a/spec/ruby/library/stringio/initialize_spec.rb
+++ b/spec/ruby/library/stringio/initialize_spec.rb
@@ -13,99 +13,99 @@ describe "StringIO#initialize when passed [Object, mode]" do
it "sets the mode based on the passed mode" do
io = StringIO.allocate
- io.send(:initialize, "example", "r")
+ io.send(:initialize, +"example", "r")
io.closed_read?.should be_false
io.closed_write?.should be_true
io = StringIO.allocate
- io.send(:initialize, "example", "rb")
+ io.send(:initialize, +"example", "rb")
io.closed_read?.should be_false
io.closed_write?.should be_true
io = StringIO.allocate
- io.send(:initialize, "example", "r+")
+ io.send(:initialize, +"example", "r+")
io.closed_read?.should be_false
io.closed_write?.should be_false
io = StringIO.allocate
- io.send(:initialize, "example", "rb+")
+ io.send(:initialize, +"example", "rb+")
io.closed_read?.should be_false
io.closed_write?.should be_false
io = StringIO.allocate
- io.send(:initialize, "example", "w")
+ io.send(:initialize, +"example", "w")
io.closed_read?.should be_true
io.closed_write?.should be_false
io = StringIO.allocate
- io.send(:initialize, "example", "wb")
+ io.send(:initialize, +"example", "wb")
io.closed_read?.should be_true
io.closed_write?.should be_false
io = StringIO.allocate
- io.send(:initialize, "example", "w+")
+ io.send(:initialize, +"example", "w+")
io.closed_read?.should be_false
io.closed_write?.should be_false
io = StringIO.allocate
- io.send(:initialize, "example", "wb+")
+ io.send(:initialize, +"example", "wb+")
io.closed_read?.should be_false
io.closed_write?.should be_false
io = StringIO.allocate
- io.send(:initialize, "example", "a")
+ io.send(:initialize, +"example", "a")
io.closed_read?.should be_true
io.closed_write?.should be_false
io = StringIO.allocate
- io.send(:initialize, "example", "ab")
+ io.send(:initialize, +"example", "ab")
io.closed_read?.should be_true
io.closed_write?.should be_false
io = StringIO.allocate
- io.send(:initialize, "example", "a+")
+ io.send(:initialize, +"example", "a+")
io.closed_read?.should be_false
io.closed_write?.should be_false
io = StringIO.allocate
- io.send(:initialize, "example", "ab+")
+ io.send(:initialize, +"example", "ab+")
io.closed_read?.should be_false
io.closed_write?.should be_false
end
it "allows passing the mode as an Integer" do
io = StringIO.allocate
- io.send(:initialize, "example", IO::RDONLY)
+ io.send(:initialize, +"example", IO::RDONLY)
io.closed_read?.should be_false
io.closed_write?.should be_true
io = StringIO.allocate
- io.send(:initialize, "example", IO::RDWR)
+ io.send(:initialize, +"example", IO::RDWR)
io.closed_read?.should be_false
io.closed_write?.should be_false
io = StringIO.allocate
- io.send(:initialize, "example", IO::WRONLY)
+ io.send(:initialize, +"example", IO::WRONLY)
io.closed_read?.should be_true
io.closed_write?.should be_false
io = StringIO.allocate
- io.send(:initialize, "example", IO::WRONLY | IO::TRUNC)
+ io.send(:initialize, +"example", IO::WRONLY | IO::TRUNC)
io.closed_read?.should be_true
io.closed_write?.should be_false
io = StringIO.allocate
- io.send(:initialize, "example", IO::RDWR | IO::TRUNC)
+ io.send(:initialize, +"example", IO::RDWR | IO::TRUNC)
io.closed_read?.should be_false
io.closed_write?.should be_false
io = StringIO.allocate
- io.send(:initialize, "example", IO::WRONLY | IO::APPEND)
+ io.send(:initialize, +"example", IO::WRONLY | IO::APPEND)
io.closed_read?.should be_true
io.closed_write?.should be_false
io = StringIO.allocate
- io.send(:initialize, "example", IO::RDWR | IO::APPEND)
+ io.send(:initialize, +"example", IO::RDWR | IO::APPEND)
io.closed_read?.should be_false
io.closed_write?.should be_false
end
@@ -118,7 +118,7 @@ describe "StringIO#initialize when passed [Object, mode]" do
it "tries to convert the passed mode to a String using #to_str" do
obj = mock('to_str')
obj.should_receive(:to_str).and_return("r")
- @io.send(:initialize, "example", obj)
+ @io.send(:initialize, +"example", obj)
@io.closed_read?.should be_false
@io.closed_write?.should be_true
@@ -142,12 +142,18 @@ describe "StringIO#initialize when passed [Object]" do
@io.string.should equal(str)
end
- it "sets the mode to read-write" do
- @io.send(:initialize, "example")
+ it "sets the mode to read-write if the string is mutable" do
+ @io.send(:initialize, +"example")
@io.closed_read?.should be_false
@io.closed_write?.should be_false
end
+ it "sets the mode to read if the string is frozen" do
+ @io.send(:initialize, -"example")
+ @io.closed_read?.should be_false
+ @io.closed_write?.should be_true
+ end
+
it "tries to convert the passed Object to a String using #to_str" do
obj = mock('to_str')
obj.should_receive(:to_str).and_return("example")
@@ -163,6 +169,91 @@ describe "StringIO#initialize when passed [Object]" do
end
end
+# NOTE: Synchronise with core/io/new_spec.rb (core/io/shared/new.rb)
+describe "StringIO#initialize when passed keyword arguments" do
+ it "sets the mode based on the passed :mode option" do
+ io = StringIO.new("example", "r")
+ io.closed_read?.should be_false
+ io.closed_write?.should be_true
+ end
+
+ it "accepts a mode argument set to nil with a valid :mode option" do
+ @io = StringIO.new(+'', nil, mode: "w")
+ @io.write("foo").should == 3
+ end
+
+ it "accepts a mode argument with a :mode option set to nil" do
+ @io = StringIO.new(+'', "w", mode: nil)
+ @io.write("foo").should == 3
+ end
+
+ it "sets binmode from :binmode option" do
+ @io = StringIO.new(+'', 'w', binmode: true)
+ @io.external_encoding.to_s.should == "ASCII-8BIT" # #binmode? isn't implemented in StringIO
+ end
+
+ it "does not set binmode from false :binmode" do
+ @io = StringIO.new(+'', 'w', binmode: false)
+ @io.external_encoding.to_s.should == "UTF-8" # #binmode? isn't implemented in StringIO
+ end
+end
+
+# NOTE: Synchronise with core/io/new_spec.rb (core/io/shared/new.rb)
+describe "StringIO#initialize when passed keyword arguments and error happens" do
+ it "raises an error if passed encodings two ways" do
+ -> {
+ @io = StringIO.new(+'', 'w:ISO-8859-1', encoding: 'ISO-8859-1')
+ }.should raise_error(ArgumentError)
+ -> {
+ @io = StringIO.new(+'', 'w:ISO-8859-1', external_encoding: 'ISO-8859-1')
+ }.should raise_error(ArgumentError)
+ -> {
+ @io = StringIO.new(+'', 'w:ISO-8859-1:UTF-8', internal_encoding: 'ISO-8859-1')
+ }.should raise_error(ArgumentError)
+ end
+
+ it "raises an error if passed matching binary/text mode two ways" do
+ -> {
+ @io = StringIO.new(+'', "wb", binmode: true)
+ }.should raise_error(ArgumentError)
+ -> {
+ @io = StringIO.new(+'', "wt", textmode: true)
+ }.should raise_error(ArgumentError)
+
+ -> {
+ @io = StringIO.new(+'', "wb", textmode: false)
+ }.should raise_error(ArgumentError)
+ -> {
+ @io = StringIO.new(+'', "wt", binmode: false)
+ }.should raise_error(ArgumentError)
+ end
+
+ it "raises an error if passed conflicting binary/text mode two ways" do
+ -> {
+ @io = StringIO.new(+'', "wb", binmode: false)
+ }.should raise_error(ArgumentError)
+ -> {
+ @io = StringIO.new(+'', "wt", textmode: false)
+ }.should raise_error(ArgumentError)
+
+ -> {
+ @io = StringIO.new(+'', "wb", textmode: true)
+ }.should raise_error(ArgumentError)
+ -> {
+ @io = StringIO.new(+'', "wt", binmode: true)
+ }.should raise_error(ArgumentError)
+ end
+
+ it "raises an error when trying to set both binmode and textmode" do
+ -> {
+ @io = StringIO.new(+'', "w", textmode: true, binmode: true)
+ }.should raise_error(ArgumentError)
+ -> {
+ @io = StringIO.new(+'', File::Constants::WRONLY, textmode: true, binmode: true)
+ }.should raise_error(ArgumentError)
+ end
+end
+
describe "StringIO#initialize when passed no arguments" do
before :each do
@io = StringIO.allocate
@@ -173,7 +264,7 @@ describe "StringIO#initialize when passed no arguments" do
end
it "sets the mode to read-write" do
- @io.send(:initialize, "example")
+ @io.send(:initialize)
@io.closed_read?.should be_false
@io.closed_write?.should be_false
end
@@ -204,19 +295,14 @@ describe "StringIO#initialize sets" do
end
it "the encoding to the encoding of the String when passed a String" do
- s = ''.force_encoding(Encoding::EUC_JP)
+ s = ''.dup.force_encoding(Encoding::EUC_JP)
io = StringIO.new(s)
io.string.encoding.should == Encoding::EUC_JP
end
- guard_not -> { # [Bug #16497]
- stringio_version = StringIO.const_defined?(:VERSION) ? StringIO::VERSION : "0.0.2"
- version_is(stringio_version, "0.0.3"..."0.1.1")
- } do
- it "the #external_encoding to the encoding of the String when passed a String" do
- s = ''.force_encoding(Encoding::EUC_JP)
- io = StringIO.new(s)
- io.external_encoding.should == Encoding::EUC_JP
- end
+ it "the #external_encoding to the encoding of the String when passed a String" do
+ s = ''.dup.force_encoding(Encoding::EUC_JP)
+ io = StringIO.new(s)
+ io.external_encoding.should == Encoding::EUC_JP
end
end
diff --git a/spec/ruby/library/stringio/lines_spec.rb b/spec/ruby/library/stringio/lines_spec.rb
deleted file mode 100644
index 42d11772ae..0000000000
--- a/spec/ruby/library/stringio/lines_spec.rb
+++ /dev/null
@@ -1,53 +0,0 @@
-require_relative '../../spec_helper'
-require 'stringio'
-require_relative 'shared/each'
-
-ruby_version_is ''...'3.0' do
- describe "StringIO#lines when passed a separator" do
- before :each do
- @verbose, $VERBOSE = $VERBOSE, nil
- end
-
- after :each do
- $VERBOSE = @verbose
- end
-
- it_behaves_like :stringio_each_separator, :lines
- end
-
- describe "StringIO#lines when passed no arguments" do
- before :each do
- @verbose, $VERBOSE = $VERBOSE, nil
- end
-
- after :each do
- $VERBOSE = @verbose
- end
-
- it_behaves_like :stringio_each_no_arguments, :lines
- end
-
- describe "StringIO#lines when self is not readable" do
- before :each do
- @verbose, $VERBOSE = $VERBOSE, nil
- end
-
- after :each do
- $VERBOSE = @verbose
- end
-
- it_behaves_like :stringio_each_not_readable, :lines
- end
-
- describe "StringIO#lines when passed chomp" do
- before :each do
- @verbose, $VERBOSE = $VERBOSE, nil
- end
-
- after :each do
- $VERBOSE = @verbose
- end
-
- it_behaves_like :stringio_each_chomp, :lines
- end
-end
diff --git a/spec/ruby/library/stringio/new_spec.rb b/spec/ruby/library/stringio/new_spec.rb
new file mode 100644
index 0000000000..ec4b32aa11
--- /dev/null
+++ b/spec/ruby/library/stringio/new_spec.rb
@@ -0,0 +1,10 @@
+require_relative '../../spec_helper'
+require 'stringio'
+
+describe "StringIO.new" do
+ it "does not use the given block and warns to use StringIO::open" do
+ -> {
+ StringIO.new { raise }
+ }.should complain(/warning: StringIO::new\(\) does not take block; use StringIO::open\(\) instead/)
+ end
+end
diff --git a/spec/ruby/library/stringio/open_spec.rb b/spec/ruby/library/stringio/open_spec.rb
index acab6e9056..b7c90661f9 100644
--- a/spec/ruby/library/stringio/open_spec.rb
+++ b/spec/ruby/library/stringio/open_spec.rb
@@ -8,26 +8,26 @@ describe "StringIO.open when passed [Object, mode]" do
end
it "returns the blocks return value when yielding" do
- ret = StringIO.open("example", "r") { :test }
+ ret = StringIO.open(+"example", "r") { :test }
ret.should equal(:test)
end
it "yields self to the passed block" do
io = nil
- StringIO.open("example", "r") { |strio| io = strio }
+ StringIO.open(+"example", "r") { |strio| io = strio }
io.should be_kind_of(StringIO)
end
it "closes self after yielding" do
io = nil
- StringIO.open("example", "r") { |strio| io = strio }
+ StringIO.open(+"example", "r") { |strio| io = strio }
io.closed?.should be_true
end
it "even closes self when an exception is raised while yielding" do
io = nil
begin
- StringIO.open("example", "r") do |strio|
+ StringIO.open(+"example", "r") do |strio|
io = strio
raise "Error"
end
@@ -38,14 +38,14 @@ describe "StringIO.open when passed [Object, mode]" do
it "sets self's string to nil after yielding" do
io = nil
- StringIO.open("example", "r") { |strio| io = strio }
+ StringIO.open(+"example", "r") { |strio| io = strio }
io.string.should be_nil
end
it "even sets self's string to nil when an exception is raised while yielding" do
io = nil
begin
- StringIO.open("example", "r") do |strio|
+ StringIO.open(+"example", "r") do |strio|
io = strio
raise "Error"
end
@@ -55,81 +55,81 @@ describe "StringIO.open when passed [Object, mode]" do
end
it "sets the mode based on the passed mode" do
- io = StringIO.open("example", "r")
+ io = StringIO.open(+"example", "r")
io.closed_read?.should be_false
io.closed_write?.should be_true
- io = StringIO.open("example", "rb")
+ io = StringIO.open(+"example", "rb")
io.closed_read?.should be_false
io.closed_write?.should be_true
- io = StringIO.open("example", "r+")
+ io = StringIO.open(+"example", "r+")
io.closed_read?.should be_false
io.closed_write?.should be_false
- io = StringIO.open("example", "rb+")
+ io = StringIO.open(+"example", "rb+")
io.closed_read?.should be_false
io.closed_write?.should be_false
- io = StringIO.open("example", "w")
+ io = StringIO.open(+"example", "w")
io.closed_read?.should be_true
io.closed_write?.should be_false
- io = StringIO.open("example", "wb")
+ io = StringIO.open(+"example", "wb")
io.closed_read?.should be_true
io.closed_write?.should be_false
- io = StringIO.open("example", "w+")
+ io = StringIO.open(+"example", "w+")
io.closed_read?.should be_false
io.closed_write?.should be_false
- io = StringIO.open("example", "wb+")
+ io = StringIO.open(+"example", "wb+")
io.closed_read?.should be_false
io.closed_write?.should be_false
- io = StringIO.open("example", "a")
+ io = StringIO.open(+"example", "a")
io.closed_read?.should be_true
io.closed_write?.should be_false
- io = StringIO.open("example", "ab")
+ io = StringIO.open(+"example", "ab")
io.closed_read?.should be_true
io.closed_write?.should be_false
- io = StringIO.open("example", "a+")
+ io = StringIO.open(+"example", "a+")
io.closed_read?.should be_false
io.closed_write?.should be_false
- io = StringIO.open("example", "ab+")
+ io = StringIO.open(+"example", "ab+")
io.closed_read?.should be_false
io.closed_write?.should be_false
end
it "allows passing the mode as an Integer" do
- io = StringIO.open("example", IO::RDONLY)
+ io = StringIO.open(+"example", IO::RDONLY)
io.closed_read?.should be_false
io.closed_write?.should be_true
- io = StringIO.open("example", IO::RDWR)
+ io = StringIO.open(+"example", IO::RDWR)
io.closed_read?.should be_false
io.closed_write?.should be_false
- io = StringIO.open("example", IO::WRONLY)
+ io = StringIO.open(+"example", IO::WRONLY)
io.closed_read?.should be_true
io.closed_write?.should be_false
- io = StringIO.open("example", IO::WRONLY | IO::TRUNC)
+ io = StringIO.open(+"example", IO::WRONLY | IO::TRUNC)
io.closed_read?.should be_true
io.closed_write?.should be_false
- io = StringIO.open("example", IO::RDWR | IO::TRUNC)
+ io = StringIO.open(+"example", IO::RDWR | IO::TRUNC)
io.closed_read?.should be_false
io.closed_write?.should be_false
- io = StringIO.open("example", IO::WRONLY | IO::APPEND)
+ io = StringIO.open(+"example", IO::WRONLY | IO::APPEND)
io.closed_read?.should be_true
io.closed_write?.should be_false
- io = StringIO.open("example", IO::RDWR | IO::APPEND)
+ io = StringIO.open(+"example", IO::RDWR | IO::APPEND)
io.closed_read?.should be_false
io.closed_write?.should be_false
end
@@ -141,7 +141,7 @@ describe "StringIO.open when passed [Object, mode]" do
it "tries to convert the passed mode to a String using #to_str" do
obj = mock('to_str')
obj.should_receive(:to_str).and_return("r")
- io = StringIO.open("example", obj)
+ io = StringIO.open(+"example", obj)
io.closed_read?.should be_false
io.closed_write?.should be_true
@@ -163,14 +163,18 @@ describe "StringIO.open when passed [Object]" do
it "yields self to the passed block" do
io = nil
- ret = StringIO.open("example") { |strio| io = strio }
+ ret = StringIO.open(+"example") { |strio| io = strio }
io.should equal(ret)
end
- it "sets the mode to read-write" do
- io = StringIO.open("example")
+ it "sets the mode to read-write (r+)" do
+ io = StringIO.open(+"example")
io.closed_read?.should be_false
io.closed_write?.should be_false
+
+ io = StringIO.new(+"example")
+ io.printf("%d", 123)
+ io.string.should == "123mple"
end
it "tries to convert the passed Object to a String using #to_str" do
@@ -195,10 +199,14 @@ describe "StringIO.open when passed no arguments" do
io.should equal(ret)
end
- it "sets the mode to read-write" do
+ it "sets the mode to read-write (r+)" do
io = StringIO.open
io.closed_read?.should be_false
io.closed_write?.should be_false
+
+ io = StringIO.new(+"example")
+ io.printf("%d", 123)
+ io.string.should == "123mple"
end
it "uses an empty String as the StringIO backend" do
diff --git a/spec/ruby/library/stringio/print_spec.rb b/spec/ruby/library/stringio/print_spec.rb
index 6ac6430900..00c33367dc 100644
--- a/spec/ruby/library/stringio/print_spec.rb
+++ b/spec/ruby/library/stringio/print_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "StringIO#print" do
before :each do
- @io = StringIO.new('example')
+ @io = StringIO.new(+'example')
end
it "prints $_ when passed no arguments" do
@@ -73,7 +73,7 @@ end
describe "StringIO#print when in append mode" do
before :each do
- @io = StringIO.new("example", "a")
+ @io = StringIO.new(+"example", "a")
end
it "appends the passed argument to the end of self" do
@@ -92,10 +92,10 @@ end
describe "StringIO#print when self is not writable" do
it "raises an IOError" do
- io = StringIO.new("test", "r")
+ io = StringIO.new(+"test", "r")
-> { io.print("test") }.should raise_error(IOError)
- io = StringIO.new("test")
+ io = StringIO.new(+"test")
io.close_write
-> { io.print("test") }.should raise_error(IOError)
end
diff --git a/spec/ruby/library/stringio/printf_spec.rb b/spec/ruby/library/stringio/printf_spec.rb
index 9dd1a3b410..ca82e84757 100644
--- a/spec/ruby/library/stringio/printf_spec.rb
+++ b/spec/ruby/library/stringio/printf_spec.rb
@@ -4,7 +4,7 @@ require_relative '../../core/kernel/shared/sprintf'
describe "StringIO#printf" do
before :each do
- @io = StringIO.new('example')
+ @io = StringIO.new()
end
it "returns nil" do
@@ -12,9 +12,9 @@ describe "StringIO#printf" do
end
it "pads self with \\000 when the current position is after the end" do
- @io.pos = 10
+ @io.pos = 3
@io.printf("%d", 123)
- @io.string.should == "example\000\000\000123"
+ @io.string.should == "\000\000\000123"
end
it "performs format conversion" do
@@ -39,9 +39,30 @@ describe "StringIO#printf" do
end
end
+describe "StringIO#printf when in read-write mode" do
+ before :each do
+ @io = StringIO.new(+"example", "r+")
+ end
+
+ it "starts from the beginning" do
+ @io.printf("%s", "abcdefghijk")
+ @io.string.should == "abcdefghijk"
+ end
+
+ it "does not truncate existing string" do
+ @io.printf("%s", "abc")
+ @io.string.should == "abcmple"
+ end
+
+ it "correctly updates self's position" do
+ @io.printf("%s", "abc")
+ @io.pos.should eql(3)
+ end
+end
+
describe "StringIO#printf when in append mode" do
before :each do
- @io = StringIO.new("example", "a")
+ @io = StringIO.new(+"example", "a")
end
it "appends the passed argument to the end of self" do
@@ -60,10 +81,10 @@ end
describe "StringIO#printf when self is not writable" do
it "raises an IOError" do
- io = StringIO.new("test", "r")
+ io = StringIO.new(+"test", "r")
-> { io.printf("test") }.should raise_error(IOError)
- io = StringIO.new("test")
+ io = StringIO.new(+"test")
io.close_write
-> { io.printf("test") }.should raise_error(IOError)
end
diff --git a/spec/ruby/library/stringio/putc_spec.rb b/spec/ruby/library/stringio/putc_spec.rb
index 223b3523e5..9f1ac8ffb2 100644
--- a/spec/ruby/library/stringio/putc_spec.rb
+++ b/spec/ruby/library/stringio/putc_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "StringIO#putc when passed [String]" do
before :each do
- @io = StringIO.new('example')
+ @io = StringIO.new(+'example')
end
it "overwrites the character at the current position" do
@@ -35,11 +35,26 @@ describe "StringIO#putc when passed [String]" do
@io.putc("t")
@io.pos.should == 3
end
+
+ it "handles concurrent writes correctly" do
+ @io = StringIO.new
+ n = 8
+ go = false
+ threads = n.times.map { |i|
+ Thread.new {
+ Thread.pass until go
+ @io.putc i.to_s
+ }
+ }
+ go = true
+ threads.each(&:join)
+ @io.string.size.should == n
+ end
end
describe "StringIO#putc when passed [Object]" do
before :each do
- @io = StringIO.new('example')
+ @io = StringIO.new(+'example')
end
it "it writes the passed Integer % 256 to self" do
@@ -70,7 +85,7 @@ end
describe "StringIO#putc when in append mode" do
it "appends to the end of self" do
- io = StringIO.new("test", "a")
+ io = StringIO.new(+"test", "a")
io.putc(?t)
io.string.should == "testt"
end
@@ -78,10 +93,10 @@ end
describe "StringIO#putc when self is not writable" do
it "raises an IOError" do
- io = StringIO.new("test", "r")
+ io = StringIO.new(+"test", "r")
-> { io.putc(?a) }.should raise_error(IOError)
- io = StringIO.new("test")
+ io = StringIO.new(+"test")
io.close_write
-> { io.putc("t") }.should raise_error(IOError)
end
diff --git a/spec/ruby/library/stringio/puts_spec.rb b/spec/ruby/library/stringio/puts_spec.rb
index a9f289a5a5..054ec8227f 100644
--- a/spec/ruby/library/stringio/puts_spec.rb
+++ b/spec/ruby/library/stringio/puts_spec.rb
@@ -101,6 +101,20 @@ describe "StringIO#puts when passed 1 or more objects" do
@io.puts ''
@io.string.should == "\n"
end
+
+ it "handles concurrent writes correctly" do
+ n = 8
+ go = false
+ threads = n.times.map { |i|
+ Thread.new {
+ Thread.pass until go
+ @io.puts i
+ }
+ }
+ go = true
+ threads.each(&:join)
+ @io.string.size.should == n.times.map { |i| "#{i}\n" }.join.size
+ end
end
describe "StringIO#puts when passed no arguments" do
@@ -131,7 +145,7 @@ end
describe "StringIO#puts when in append mode" do
before :each do
- @io = StringIO.new("example", "a")
+ @io = StringIO.new(+"example", "a")
end
it "appends the passed argument to the end of self" do
@@ -150,10 +164,10 @@ end
describe "StringIO#puts when self is not writable" do
it "raises an IOError" do
- io = StringIO.new("test", "r")
+ io = StringIO.new(+"test", "r")
-> { io.puts }.should raise_error(IOError)
- io = StringIO.new("test")
+ io = StringIO.new(+"test")
io.close_write
-> { io.puts }.should raise_error(IOError)
end
@@ -161,7 +175,7 @@ end
describe "StringIO#puts when passed an encoded string" do
it "stores the bytes unmodified" do
- io = StringIO.new("")
+ io = StringIO.new(+"")
io.puts "\x00\x01\x02"
io.puts "æåø"
diff --git a/spec/ruby/library/stringio/read_nonblock_spec.rb b/spec/ruby/library/stringio/read_nonblock_spec.rb
index 2a8f926bd0..74736f7792 100644
--- a/spec/ruby/library/stringio/read_nonblock_spec.rb
+++ b/spec/ruby/library/stringio/read_nonblock_spec.rb
@@ -5,10 +5,21 @@ require_relative 'shared/sysread'
describe "StringIO#read_nonblock when passed length, buffer" do
it_behaves_like :stringio_read, :read_nonblock
+
+ it "accepts :exception option" do
+ io = StringIO.new("example")
+ io.read_nonblock(3, buffer = +"", exception: true)
+ buffer.should == "exa"
+ end
end
describe "StringIO#read_nonblock when passed length" do
it_behaves_like :stringio_read_length, :read_nonblock
+
+ it "accepts :exception option" do
+ io = StringIO.new("example")
+ io.read_nonblock(3, exception: true).should == "exa"
+ end
end
describe "StringIO#read_nonblock when passed nil" do
@@ -29,7 +40,7 @@ describe "StringIO#read_nonblock" do
context "when exception option is set to false" do
context "when the end is reached" do
it "returns nil" do
- stringio = StringIO.new('')
+ stringio = StringIO.new(+'')
stringio << "hello"
stringio.rewind
diff --git a/spec/ruby/library/stringio/read_spec.rb b/spec/ruby/library/stringio/read_spec.rb
index 52ab3dcf47..e49f262127 100644
--- a/spec/ruby/library/stringio/read_spec.rb
+++ b/spec/ruby/library/stringio/read_spec.rb
@@ -53,7 +53,7 @@ describe "StringIO#read when passed length and a buffer" do
end
it "reads [length] characters into the buffer" do
- buf = "foo"
+ buf = +"foo"
result = @io.read(10, buf)
buf.should == "abcdefghij"
diff --git a/spec/ruby/library/stringio/readline_spec.rb b/spec/ruby/library/stringio/readline_spec.rb
index 94b67bc92d..b16a16e23f 100644
--- a/spec/ruby/library/stringio/readline_spec.rb
+++ b/spec/ruby/library/stringio/readline_spec.rb
@@ -113,7 +113,7 @@ end
describe "StringIO#readline when in write-only mode" do
it "raises an IOError" do
- io = StringIO.new("xyz", "w")
+ io = StringIO.new(+"xyz", "w")
-> { io.readline }.should raise_error(IOError)
io = StringIO.new("xyz")
@@ -128,3 +128,23 @@ describe "StringIO#readline when passed [chomp]" do
io.readline(chomp: true).should == "this>is>an>example"
end
end
+
+describe "StringIO#readline when passed [limit]" do
+ before :each do
+ @io = StringIO.new("this>is>an>example")
+ end
+
+ it "returns the data read until the limit is met" do
+ io = StringIO.new("this>is>an>example\n")
+ io.readline(3).should == "thi"
+ end
+
+ it "returns a blank string when passed a limit of 0" do
+ @io.readline(0).should == ""
+ end
+
+ it "ignores it when the limit is negative" do
+ seen = []
+ @io.readline(-4).should == "this>is>an>example"
+ end
+end
diff --git a/spec/ruby/library/stringio/readlines_spec.rb b/spec/ruby/library/stringio/readlines_spec.rb
index 4b007787e2..ed7cc22b3d 100644
--- a/spec/ruby/library/stringio/readlines_spec.rb
+++ b/spec/ruby/library/stringio/readlines_spec.rb
@@ -83,7 +83,7 @@ end
describe "StringIO#readlines when in write-only mode" do
it "raises an IOError" do
- io = StringIO.new("xyz", "w")
+ io = StringIO.new(+"xyz", "w")
-> { io.readlines }.should raise_error(IOError)
io = StringIO.new("xyz")
@@ -98,3 +98,21 @@ describe "StringIO#readlines when passed [chomp]" do
io.readlines(chomp: true).should == ["this>is", "an>example"]
end
end
+
+describe "StringIO#readlines when passed [limit]" do
+ before :each do
+ @io = StringIO.new("a b c d e\n1 2 3 4 5")
+ end
+
+ it "returns the data read until the limit is met" do
+ @io.readlines(4).should == ["a b ", "c d ", "e\n", "1 2 ", "3 4 ", "5"]
+ end
+
+ it "raises ArgumentError when limit is 0" do
+ -> { @io.readlines(0) }.should raise_error(ArgumentError)
+ end
+
+ it "ignores it when the limit is negative" do
+ @io.readlines(-4).should == ["a b c d e\n", "1 2 3 4 5"]
+ end
+end
diff --git a/spec/ruby/library/stringio/readpartial_spec.rb b/spec/ruby/library/stringio/readpartial_spec.rb
index 2601fe8c42..f25cef4014 100644
--- a/spec/ruby/library/stringio/readpartial_spec.rb
+++ b/spec/ruby/library/stringio/readpartial_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "StringIO#readpartial" do
before :each do
- @string = StringIO.new('Stop, look, listen')
+ @string = StringIO.new(+'Stop, look, listen')
end
after :each do
@@ -48,7 +48,7 @@ describe "StringIO#readpartial" do
end
it "discards the existing buffer content upon successful read" do
- buffer = "existing"
+ buffer = +"existing"
@string.readpartial(11, buffer)
buffer.should == "Stop, look,"
end
@@ -59,7 +59,7 @@ describe "StringIO#readpartial" do
end
it "discards the existing buffer content upon error" do
- buffer = 'hello'
+ buffer = +'hello'
@string.readpartial(100)
-> { @string.readpartial(1, buffer) }.should raise_error(EOFError)
buffer.should be_empty
diff --git a/spec/ruby/library/stringio/reopen_spec.rb b/spec/ruby/library/stringio/reopen_spec.rb
index 6752cf9970..7021ff17e5 100644
--- a/spec/ruby/library/stringio/reopen_spec.rb
+++ b/spec/ruby/library/stringio/reopen_spec.rb
@@ -12,31 +12,20 @@ describe "StringIO#reopen when passed [Object, Integer]" do
@io.closed_write?.should be_true
@io.string.should == "reopened"
- @io.reopen("reopened, twice", IO::WRONLY)
+ @io.reopen(+"reopened, twice", IO::WRONLY)
@io.closed_read?.should be_true
@io.closed_write?.should be_false
@io.string.should == "reopened, twice"
- @io.reopen("reopened, another time", IO::RDWR)
+ @io.reopen(+"reopened, another time", IO::RDWR)
@io.closed_read?.should be_false
@io.closed_write?.should be_false
@io.string.should == "reopened, another time"
end
- ruby_version_is ""..."3.0" do
- # NOTE: WEIRD!
- it "does not taint self when the passed Object was tainted" do
- @io.reopen("reopened".taint, IO::RDONLY)
- @io.tainted?.should be_false
-
- @io.reopen("reopened".taint, IO::WRONLY)
- @io.tainted?.should be_false
- end
- end
-
it "tries to convert the passed Object to a String using #to_str" do
obj = mock("to_str")
- obj.should_receive(:to_str).and_return("to_str")
+ obj.should_receive(:to_str).and_return(+"to_str")
@io.reopen(obj, IO::RDWR)
@io.string.should == "to_str"
end
@@ -71,38 +60,27 @@ describe "StringIO#reopen when passed [Object, Object]" do
@io.closed_write?.should be_true
@io.string.should == "reopened"
- @io.reopen("reopened, twice", "r+")
+ @io.reopen(+"reopened, twice", "r+")
@io.closed_read?.should be_false
@io.closed_write?.should be_false
@io.string.should == "reopened, twice"
- @io.reopen("reopened, another", "w+")
+ @io.reopen(+"reopened, another", "w+")
@io.closed_read?.should be_false
@io.closed_write?.should be_false
@io.string.should == ""
- @io.reopen("reopened, another time", "r+")
+ @io.reopen(+"reopened, another time", "r+")
@io.closed_read?.should be_false
@io.closed_write?.should be_false
@io.string.should == "reopened, another time"
end
it "truncates the passed String when opened in truncate mode" do
- @io.reopen(str = "reopened", "w")
+ @io.reopen(str = +"reopened", "w")
str.should == ""
end
- ruby_version_is ""..."3.0" do
- # NOTE: WEIRD!
- it "does not taint self when the passed Object was tainted" do
- @io.reopen("reopened".taint, "r")
- @io.tainted?.should be_false
-
- @io.reopen("reopened".taint, "w")
- @io.tainted?.should be_false
- end
- end
-
it "tries to convert the passed Object to a String using #to_str" do
obj = mock("to_str")
obj.should_receive(:to_str).and_return("to_str")
@@ -116,13 +94,13 @@ describe "StringIO#reopen when passed [Object, Object]" do
it "resets self's position to 0" do
@io.read(5)
- @io.reopen("reopened")
+ @io.reopen(+"reopened")
@io.pos.should eql(0)
end
it "resets self's line number to 0" do
@io.gets
- @io.reopen("reopened")
+ @io.reopen(+"reopened")
@io.lineno.should eql(0)
end
@@ -156,7 +134,7 @@ describe "StringIO#reopen when passed [String]" do
it "reopens self with the passed String in read-write mode" do
@io.close
- @io.reopen("reopened")
+ @io.reopen(+"reopened")
@io.closed_write?.should be_false
@io.closed_read?.should be_false
@@ -164,23 +142,15 @@ describe "StringIO#reopen when passed [String]" do
@io.string.should == "reopened"
end
- ruby_version_is ""..."3.0" do
- # NOTE: WEIRD!
- it "does not taint self when the passed Object was tainted" do
- @io.reopen("reopened".taint)
- @io.tainted?.should be_false
- end
- end
-
it "resets self's position to 0" do
@io.read(5)
- @io.reopen("reopened")
+ @io.reopen(+"reopened")
@io.pos.should eql(0)
end
it "resets self's line number to 0" do
@io.gets
- @io.reopen("reopened")
+ @io.reopen(+"reopened")
@io.lineno.should eql(0)
end
end
@@ -202,18 +172,10 @@ describe "StringIO#reopen when passed [Object]" do
it "tries to convert the passed Object to a StringIO using #to_strio" do
obj = mock("to_strio")
- obj.should_receive(:to_strio).and_return(StringIO.new("to_strio"))
+ obj.should_receive(:to_strio).and_return(StringIO.new(+"to_strio"))
@io.reopen(obj)
@io.string.should == "to_strio"
end
-
- # NOTE: WEIRD!
- ruby_version_is ""..."2.7" do
- it "taints self when the passed Object was tainted" do
- @io.reopen(StringIO.new("reopened").taint)
- @io.tainted?.should be_true
- end
- end
end
describe "StringIO#reopen when passed no arguments" do
@@ -246,49 +208,40 @@ end
# for details.
describe "StringIO#reopen" do
before :each do
- @io = StringIO.new('hello','a')
+ @io = StringIO.new(+'hello', 'a')
end
# TODO: find out if this is really a bug
it "reopens a stream when given a String argument" do
- @io.reopen('goodbye').should == @io
+ @io.reopen(+'goodbye').should == @io
@io.string.should == 'goodbye'
@io << 'x'
@io.string.should == 'xoodbye'
end
it "reopens a stream in append mode when flagged as such" do
- @io.reopen('goodbye', 'a').should == @io
+ @io.reopen(+'goodbye', 'a').should == @io
@io.string.should == 'goodbye'
@io << 'x'
@io.string.should == 'goodbyex'
end
it "reopens and truncate when reopened in write mode" do
- @io.reopen('goodbye', 'wb').should == @io
+ @io.reopen(+'goodbye', 'wb').should == @io
@io.string.should == ''
@io << 'x'
@io.string.should == 'x'
end
it "truncates the given string, not a copy" do
- str = 'goodbye'
+ str = +'goodbye'
@io.reopen(str, 'w')
@io.string.should == ''
str.should == ''
end
- ruby_version_is ""..."2.7" do
- it "taints self if the provided StringIO argument is tainted" do
- new_io = StringIO.new("tainted")
- new_io.taint
- @io.reopen(new_io)
- @io.should.tainted?
- end
- end
-
it "does not truncate the content even when the StringIO argument is in the truncate mode" do
- orig_io = StringIO.new("Original StringIO", IO::RDWR|IO::TRUNC)
+ orig_io = StringIO.new(+"Original StringIO", IO::RDWR|IO::TRUNC)
orig_io.write("BLAH") # make sure the content is not empty
@io.reopen(orig_io)
diff --git a/spec/ruby/library/stringio/set_encoding_spec.rb b/spec/ruby/library/stringio/set_encoding_spec.rb
index 21d45750f3..19ca0875bf 100644
--- a/spec/ruby/library/stringio/set_encoding_spec.rb
+++ b/spec/ruby/library/stringio/set_encoding_spec.rb
@@ -17,4 +17,12 @@ describe "StringIO#set_encoding" do
io.set_encoding Encoding::UTF_8
io.string.encoding.should == Encoding::US_ASCII
end
+
+ it "accepts a String" do
+ str = "".encode(Encoding::US_ASCII)
+ io = StringIO.new(str)
+ io.set_encoding("ASCII-8BIT")
+ io.external_encoding.should == Encoding::BINARY
+ str.encoding.should == Encoding::BINARY
+ end
end
diff --git a/spec/ruby/library/stringio/shared/codepoints.rb b/spec/ruby/library/stringio/shared/codepoints.rb
index 9d84aa4919..25333bb0fd 100644
--- a/spec/ruby/library/stringio/shared/codepoints.rb
+++ b/spec/ruby/library/stringio/shared/codepoints.rb
@@ -27,7 +27,7 @@ describe :stringio_codepoints, shared: true do
@io.close_read
-> { @enum.to_a }.should raise_error(IOError)
- io = StringIO.new("xyz", "w")
+ io = StringIO.new(+"xyz", "w")
-> { io.send(@method).to_a }.should raise_error(IOError)
end
diff --git a/spec/ruby/library/stringio/shared/each.rb b/spec/ruby/library/stringio/shared/each.rb
index 14b0a013b3..e0dd3f9b8f 100644
--- a/spec/ruby/library/stringio/shared/each.rb
+++ b/spec/ruby/library/stringio/shared/each.rb
@@ -36,11 +36,22 @@ describe :stringio_each_separator, shared: true do
seen.should == ["2 1 2 1 2"]
end
- it "yields each paragraph when passed an empty String as separator" do
- seen = []
- io = StringIO.new("para1\n\npara2\n\n\npara3")
- io.send(@method, "") {|s| seen << s}
- seen.should == ["para1\n\n", "para2\n\n", "para3"]
+ version_is StringIO::VERSION, ""..."3.0.4" do #ruby_version_is ""..."3.2" do
+ it "yields each paragraph with two separation characters when passed an empty String as separator" do
+ seen = []
+ io = StringIO.new("para1\n\npara2\n\n\npara3")
+ io.send(@method, "") {|s| seen << s}
+ seen.should == ["para1\n\n", "para2\n\n", "para3"]
+ end
+ end
+
+ version_is StringIO::VERSION, "3.0.4" do #ruby_version_is "3.2" do
+ it "yields each paragraph with all separation characters when passed an empty String as separator" do
+ seen = []
+ io = StringIO.new("para1\n\npara2\n\n\npara3")
+ io.send(@method, "") {|s| seen << s}
+ seen.should == ["para1\n\n", "para2\n\n\n", "para3"]
+ end
end
end
@@ -96,7 +107,7 @@ end
describe :stringio_each_not_readable, shared: true do
it "raises an IOError" do
- io = StringIO.new("a b c d e", "w")
+ io = StringIO.new(+"a b c d e", "w")
-> { io.send(@method) { |b| b } }.should raise_error(IOError)
io = StringIO.new("a b c d e")
@@ -112,4 +123,41 @@ describe :stringio_each_chomp, shared: true do
io.send(@method, chomp: true) {|s| seen << s }
seen.should == ["a b \rc d e", "1 2 3 4 5", "the end"]
end
+
+ it "returns each line with removed newline characters when called without block" do
+ seen = []
+ io = StringIO.new("a b \rc d e\n1 2 3 4 5\r\nthe end")
+ enum = io.send(@method, chomp: true)
+ enum.each {|s| seen << s }
+ seen.should == ["a b \rc d e", "1 2 3 4 5", "the end"]
+ end
+end
+
+describe :stringio_each_separator_and_chomp, shared: true do
+ it "yields each line with removed separator to the passed block" do
+ seen = []
+ io = StringIO.new("a b \nc d e|1 2 3 4 5\n|the end")
+ io.send(@method, "|", chomp: true) {|s| seen << s }
+ seen.should == ["a b \nc d e", "1 2 3 4 5\n", "the end"]
+ end
+
+ it "returns each line with removed separator when called without block" do
+ seen = []
+ io = StringIO.new("a b \nc d e|1 2 3 4 5\n|the end")
+ enum = io.send(@method, "|", chomp: true)
+ enum.each {|s| seen << s }
+ seen.should == ["a b \nc d e", "1 2 3 4 5\n", "the end"]
+ end
+end
+
+describe :stringio_each_limit, shared: true do
+ before :each do
+ @io = StringIO.new("a b c d e\n1 2 3 4 5")
+ end
+
+ it "returns the data read until the limit is met" do
+ seen = []
+ @io.send(@method, 4) { |s| seen << s }
+ seen.should == ["a b ", "c d ", "e\n", "1 2 ", "3 4 ", "5"]
+ end
end
diff --git a/spec/ruby/library/stringio/shared/each_byte.rb b/spec/ruby/library/stringio/shared/each_byte.rb
index 56734ff99d..b51fa38f2f 100644
--- a/spec/ruby/library/stringio/shared/each_byte.rb
+++ b/spec/ruby/library/stringio/shared/each_byte.rb
@@ -38,7 +38,7 @@ end
describe :stringio_each_byte_not_readable, shared: true do
it "raises an IOError" do
- io = StringIO.new("xyz", "w")
+ io = StringIO.new(+"xyz", "w")
-> { io.send(@method) { |b| b } }.should raise_error(IOError)
io = StringIO.new("xyz")
diff --git a/spec/ruby/library/stringio/shared/each_char.rb b/spec/ruby/library/stringio/shared/each_char.rb
index bcdac53282..197237c1c8 100644
--- a/spec/ruby/library/stringio/shared/each_char.rb
+++ b/spec/ruby/library/stringio/shared/each_char.rb
@@ -26,7 +26,7 @@ end
describe :stringio_each_char_not_readable, shared: true do
it "raises an IOError" do
- io = StringIO.new("xyz", "w")
+ io = StringIO.new(+"xyz", "w")
-> { io.send(@method) { |b| b } }.should raise_error(IOError)
io = StringIO.new("xyz")
diff --git a/spec/ruby/library/stringio/shared/getc.rb b/spec/ruby/library/stringio/shared/getc.rb
index 6318bcc30f..ba65040bce 100644
--- a/spec/ruby/library/stringio/shared/getc.rb
+++ b/spec/ruby/library/stringio/shared/getc.rb
@@ -33,7 +33,7 @@ end
describe :stringio_getc_not_readable, shared: true do
it "raises an IOError" do
- io = StringIO.new("xyz", "w")
+ io = StringIO.new(+"xyz", "w")
-> { io.send(@method) }.should raise_error(IOError)
io = StringIO.new("xyz")
diff --git a/spec/ruby/library/stringio/shared/isatty.rb b/spec/ruby/library/stringio/shared/isatty.rb
index 3da5999953..c9e7ee7321 100644
--- a/spec/ruby/library/stringio/shared/isatty.rb
+++ b/spec/ruby/library/stringio/shared/isatty.rb
@@ -1,5 +1,5 @@
describe :stringio_isatty, shared: true do
it "returns false" do
- StringIO.new('tty').send(@method).should be_false
+ StringIO.new("tty").send(@method).should be_false
end
end
diff --git a/spec/ruby/library/stringio/shared/read.rb b/spec/ruby/library/stringio/shared/read.rb
index c60677bba7..e3840786d9 100644
--- a/spec/ruby/library/stringio/shared/read.rb
+++ b/spec/ruby/library/stringio/shared/read.rb
@@ -5,19 +5,19 @@ describe :stringio_read, shared: true do
it "returns the passed buffer String" do
# Note: Rubinius bug:
- # @io.send(@method, 7, buffer = "").should equal(buffer)
- ret = @io.send(@method, 7, buffer = "")
+ # @io.send(@method, 7, buffer = +"").should equal(buffer)
+ ret = @io.send(@method, 7, buffer = +"")
ret.should equal(buffer)
end
it "reads length bytes and writes them to the buffer String" do
- @io.send(@method, 7, buffer = "")
+ @io.send(@method, 7, buffer = +"")
buffer.should == "example"
end
it "tries to convert the passed buffer Object to a String using #to_str" do
obj = mock("to_str")
- obj.should_receive(:to_str).and_return(buffer = "")
+ obj.should_receive(:to_str).and_return(buffer = +"")
@io.send(@method, 7, obj)
buffer.should == "example"
@@ -75,7 +75,7 @@ end
describe :stringio_read_no_arguments, shared: true do
before :each do
- @io = StringIO.new("example")
+ @io = StringIO.new(+"example")
end
it "reads the whole content starting from the current position" do
@@ -89,6 +89,12 @@ describe :stringio_read_no_arguments, shared: true do
@io.send(@method)
@io.pos.should eql(7)
end
+
+ it "correctly update the current position in bytes when multi-byte characters are used" do
+ @io.print("example\u03A3") # Overwrite the original string with 8 characters containing 9 bytes.
+ @io.send(@method)
+ @io.pos.should eql(9)
+ end
end
describe :stringio_read_nil, shared: true do
@@ -111,7 +117,7 @@ end
describe :stringio_read_not_readable, shared: true do
it "raises an IOError" do
- io = StringIO.new("test", "w")
+ io = StringIO.new(+"test", "w")
-> { io.send(@method) }.should raise_error(IOError)
io = StringIO.new("test")
diff --git a/spec/ruby/library/stringio/shared/readchar.rb b/spec/ruby/library/stringio/shared/readchar.rb
index 4248e75420..72d7446c36 100644
--- a/spec/ruby/library/stringio/shared/readchar.rb
+++ b/spec/ruby/library/stringio/shared/readchar.rb
@@ -19,7 +19,7 @@ end
describe :stringio_readchar_not_readable, shared: true do
it "raises an IOError" do
- io = StringIO.new("a b c d e", "w")
+ io = StringIO.new(+"a b c d e", "w")
-> { io.send(@method) }.should raise_error(IOError)
io = StringIO.new("a b c d e")
diff --git a/spec/ruby/library/stringio/shared/sysread.rb b/spec/ruby/library/stringio/shared/sysread.rb
index 3376bd9907..937bac705c 100644
--- a/spec/ruby/library/stringio/shared/sysread.rb
+++ b/spec/ruby/library/stringio/shared/sysread.rb
@@ -1,4 +1,4 @@
-describe :stringio_sysread_length, :shared => true do
+describe :stringio_sysread_length, shared: true do
before :each do
@io = StringIO.new("example")
end
diff --git a/spec/ruby/library/stringio/shared/write.rb b/spec/ruby/library/stringio/shared/write.rb
index 080729217b..404e08b93d 100644
--- a/spec/ruby/library/stringio/shared/write.rb
+++ b/spec/ruby/library/stringio/shared/write.rb
@@ -1,6 +1,6 @@
describe :stringio_write, shared: true do
before :each do
- @io = StringIO.new('12345')
+ @io = StringIO.new(+'12345')
end
it "tries to convert the passed Object to a String using #to_s" do
@@ -13,7 +13,7 @@ end
describe :stringio_write_string, shared: true do
before :each do
- @io = StringIO.new('12345')
+ @io = StringIO.new(+'12345')
end
# TODO: RDoc says that #write appends at the current position.
@@ -45,27 +45,71 @@ describe :stringio_write_string, shared: true do
@io.pos.should eql(4)
end
- ruby_version_is ""..."2.7" do
- it "taints self's String when the passed argument is tainted" do
- @io.send(@method, "test".taint)
- @io.string.tainted?.should be_true
- end
+ it "handles concurrent writes correctly" do
+ @io = StringIO.new
+ n = 8
+ go = false
+ threads = n.times.map { |i|
+ Thread.new {
+ Thread.pass until go
+ @io.write i.to_s
+ }
+ }
+ go = true
+ threads.each(&:join)
+ @io.string.size.should == n.times.map(&:to_s).join.size
end
- ruby_version_is ""..."3.0" do
- it "does not taint self when the passed argument is tainted" do
- @io.send(@method, "test".taint)
- @io.tainted?.should be_false
- end
+ it "handles writing non-ASCII UTF-8 after seek" do
+ @io.binmode
+ @io << "\x80"
+ @io.pos = 0
+ @io << "\x81"
+ @io.string.should == "\x812345".b
+ end
+
+ it "handles writing with position < buffer size" do
+ @io.pos = 2
+ @io.write "abc"
+ @io.string.should == "12abc"
+
+ @io.pos = 2
+ @io.write "de"
+ @io.string.should == "12dec"
+
+ @io.pos = 2
+ @io.write "fghi"
+ @io.string.should == "12fghi"
+ end
+
+ it "transcodes the given string when the external encoding is set and neither is BINARY" do
+ utf8_str = "hello"
+ io = StringIO.new.set_encoding(Encoding::UTF_16BE)
+ io.external_encoding.should == Encoding::UTF_16BE
+
+ io.send(@method, utf8_str)
+
+ expected = [0, 104, 0, 101, 0, 108, 0, 108, 0, 111] # UTF-16BE bytes for "hello"
+ io.string.bytes.should == expected
+ end
+
+ it "does not transcode the given string when the external encoding is set and the string encoding is BINARY" do
+ str = "été".b
+ io = StringIO.new.set_encoding(Encoding::UTF_16BE)
+ io.external_encoding.should == Encoding::UTF_16BE
+
+ io.send(@method, str)
+
+ io.string.bytes.should == str.bytes
end
end
describe :stringio_write_not_writable, shared: true do
it "raises an IOError" do
- io = StringIO.new("test", "r")
+ io = StringIO.new(+"test", "r")
-> { io.send(@method, "test") }.should raise_error(IOError)
- io = StringIO.new("test")
+ io = StringIO.new(+"test")
io.close_write
-> { io.send(@method, "test") }.should raise_error(IOError)
end
@@ -73,7 +117,7 @@ end
describe :stringio_write_append, shared: true do
before :each do
- @io = StringIO.new("example", "a")
+ @io = StringIO.new(+"example", "a")
end
it "appends the passed argument to the end of self" do
diff --git a/spec/ruby/library/stringio/truncate_spec.rb b/spec/ruby/library/stringio/truncate_spec.rb
index ba910ee98c..592ca5a6e1 100644
--- a/spec/ruby/library/stringio/truncate_spec.rb
+++ b/spec/ruby/library/stringio/truncate_spec.rb
@@ -3,13 +3,11 @@ require "stringio"
describe "StringIO#truncate when passed [length]" do
before :each do
- @io = StringIO.new('123456789')
+ @io = StringIO.new(+'123456789')
end
- # TODO: Report to Ruby-Core: The RDoc says it always returns 0
- it "returns the passed length" do
- @io.truncate(4).should eql(4)
- @io.truncate(10).should eql(10)
+ it "returns an Integer" do
+ @io.truncate(4).should be_kind_of(Integer)
end
it "truncated the underlying string down to the passed length" do
@@ -18,7 +16,7 @@ describe "StringIO#truncate when passed [length]" do
end
it "does not create a copy of the underlying string" do
- io = StringIO.new(str = "123456789")
+ io = StringIO.new(str = +"123456789")
io.truncate(4)
io.string.should equal(str)
end
@@ -47,12 +45,6 @@ describe "StringIO#truncate when passed [length]" do
@io.string.should == "1234"
end
- it "returns the passed length Object, NOT the result of #to_int" do
- obj = mock("to_int")
- obj.should_receive(:to_int).and_return(4)
- @io.truncate(obj).should equal(obj)
- end
-
it "raises a TypeError when the passed length can't be converted to an Integer" do
-> { @io.truncate(Object.new) }.should raise_error(TypeError)
end
@@ -60,10 +52,10 @@ end
describe "StringIO#truncate when self is not writable" do
it "raises an IOError" do
- io = StringIO.new("test", "r")
+ io = StringIO.new(+"test", "r")
-> { io.truncate(2) }.should raise_error(IOError)
- io = StringIO.new("test")
+ io = StringIO.new(+"test")
io.close_write
-> { io.truncate(2) }.should raise_error(IOError)
end
diff --git a/spec/ruby/library/stringio/ungetc_spec.rb b/spec/ruby/library/stringio/ungetc_spec.rb
index 91ef2100a1..bceafa79ff 100644
--- a/spec/ruby/library/stringio/ungetc_spec.rb
+++ b/spec/ruby/library/stringio/ungetc_spec.rb
@@ -3,7 +3,7 @@ require_relative 'fixtures/classes'
describe "StringIO#ungetc when passed [char]" do
before :each do
- @io = StringIO.new('1234')
+ @io = StringIO.new(+'1234')
end
it "writes the passed char before the current position" do
@@ -45,11 +45,11 @@ end
describe "StringIO#ungetc when self is not readable" do
it "raises an IOError" do
- io = StringIO.new("test", "w")
+ io = StringIO.new(+"test", "w")
io.pos = 1
-> { io.ungetc(?A) }.should raise_error(IOError)
- io = StringIO.new("test")
+ io = StringIO.new(+"test")
io.pos = 1
io.close_read
-> { io.ungetc(?A) }.should raise_error(IOError)
@@ -60,11 +60,11 @@ end
#
# describe "StringIO#ungetc when self is not writable" do
# it "raises an IOError" do
-# io = StringIO.new("test", "r")
+# io = StringIO.new(+"test", "r")
# io.pos = 1
# lambda { io.ungetc(?A) }.should raise_error(IOError)
#
-# io = StringIO.new("test")
+# io = StringIO.new(+"test")
# io.pos = 1
# io.close_write
# lambda { io.ungetc(?A) }.should raise_error(IOError)
diff --git a/spec/ruby/library/stringio/write_nonblock_spec.rb b/spec/ruby/library/stringio/write_nonblock_spec.rb
index 4f4c5039fe..b48ef6698a 100644
--- a/spec/ruby/library/stringio/write_nonblock_spec.rb
+++ b/spec/ruby/library/stringio/write_nonblock_spec.rb
@@ -8,6 +8,12 @@ end
describe "StringIO#write_nonblock when passed [String]" do
it_behaves_like :stringio_write_string, :write_nonblock
+
+ it "accepts :exception option" do
+ io = StringIO.new(+"12345", "a")
+ io.write_nonblock("67890", exception: true)
+ io.string.should == "1234567890"
+ end
end
describe "StringIO#write_nonblock when self is not writable" do
diff --git a/spec/ruby/library/stringscanner/check_spec.rb b/spec/ruby/library/stringscanner/check_spec.rb
index 21da785515..a97c26af83 100644
--- a/spec/ruby/library/stringscanner/check_spec.rb
+++ b/spec/ruby/library/stringscanner/check_spec.rb
@@ -14,14 +14,12 @@ describe "StringScanner#check" do
@s.matched.should == nil
end
- ruby_version_is "2.7" do
- it "treats String as the pattern itself" do
- @s.check("This").should == "This"
- @s.matched.should == "This"
- @s.pos.should == 0
- @s.check(/is/).should == nil
- @s.matched.should == nil
- end
+ it "treats String as the pattern itself" do
+ @s.check("This").should == "This"
+ @s.matched.should == "This"
+ @s.pos.should == 0
+ @s.check(/is/).should == nil
+ @s.matched.should == nil
end
end
diff --git a/spec/ruby/library/stringscanner/getch_spec.rb b/spec/ruby/library/stringscanner/getch_spec.rb
index a6be0d4221..449c20ad3b 100644
--- a/spec/ruby/library/stringscanner/getch_spec.rb
+++ b/spec/ruby/library/stringscanner/getch_spec.rb
@@ -13,7 +13,7 @@ describe "StringScanner#getch" do
it "is multi-byte character sensitive" do
# Japanese hiragana "A" in EUC-JP
- src = "\244\242".force_encoding("euc-jp")
+ src = "\244\242".dup.force_encoding("euc-jp")
s = StringScanner.new(src)
s.getch.should == src
diff --git a/spec/ruby/library/stringscanner/scan_spec.rb b/spec/ruby/library/stringscanner/scan_spec.rb
index 2269abd6b3..ea711767b9 100644
--- a/spec/ruby/library/stringscanner/scan_spec.rb
+++ b/spec/ruby/library/stringscanner/scan_spec.rb
@@ -50,17 +50,9 @@ describe "StringScanner#scan" do
@s.scan(/./).should be_nil
end
- ruby_version_is ""..."2.7" do
- it "raises a TypeError if pattern is a String" do
- -> { @s.scan("aoeu") }.should raise_error(TypeError)
- end
- end
-
- ruby_version_is "2.7" do
- it "treats String as the pattern itself" do
- @s.scan("this").should be_nil
- @s.scan("This").should == "This"
- end
+ it "treats String as the pattern itself" do
+ @s.scan("this").should be_nil
+ @s.scan("This").should == "This"
end
it "raises a TypeError if pattern isn't a Regexp nor String" do
@@ -75,23 +67,21 @@ describe "StringScanner#scan with fixed_anchor: true" do
@s = StringScanner.new("This\nis\na\ntest", fixed_anchor: true)
end
- ruby_version_is "2.7" do
- it "returns the matched string" do
- @s.scan(/\w+/).should == "This"
- @s.scan(/.../m).should == "\nis"
- @s.scan(//).should == ""
- @s.scan(/\s+/).should == "\n"
- end
+ it "returns the matched string" do
+ @s.scan(/\w+/).should == "This"
+ @s.scan(/.../m).should == "\nis"
+ @s.scan(//).should == ""
+ @s.scan(/\s+/).should == "\n"
+ end
- it "treats ^ as matching from the beginning of line" do
- @s.scan(/\w+\n/).should == "This\n"
- @s.scan(/^\w/).should == "i"
- @s.scan(/^\w/).should be_nil
- end
+ it "treats ^ as matching from the beginning of line" do
+ @s.scan(/\w+\n/).should == "This\n"
+ @s.scan(/^\w/).should == "i"
+ @s.scan(/^\w/).should be_nil
+ end
- it "treats \\A as matching from the beginning of string" do
- @s.scan(/\A\w/).should == "T"
- @s.scan(/\A\w/).should be_nil
- end
+ it "treats \\A as matching from the beginning of string" do
+ @s.scan(/\A\w/).should == "T"
+ @s.scan(/\A\w/).should be_nil
end
end
diff --git a/spec/ruby/library/stringscanner/shared/concat.rb b/spec/ruby/library/stringscanner/shared/concat.rb
index cb884a5c01..1dbae11f7c 100644
--- a/spec/ruby/library/stringscanner/shared/concat.rb
+++ b/spec/ruby/library/stringscanner/shared/concat.rb
@@ -1,6 +1,6 @@
describe :strscan_concat, shared: true do
it "concatenates the given argument to self and returns self" do
- s = StringScanner.new("hello ")
+ s = StringScanner.new(+"hello ")
s.send(@method, 'world').should == s
s.string.should == "hello world"
s.eos?.should be_false
diff --git a/spec/ruby/library/stringscanner/shared/extract_range.rb b/spec/ruby/library/stringscanner/shared/extract_range.rb
index 1c14f716c9..e7404fd0cb 100644
--- a/spec/ruby/library/stringscanner/shared/extract_range.rb
+++ b/spec/ruby/library/stringscanner/shared/extract_range.rb
@@ -8,17 +8,4 @@ describe :extract_range, shared: true do
ch.should_not be_kind_of(cls)
ch.should be_an_instance_of(String)
end
-
- ruby_version_is ''...'2.7' do
- it "taints the returned String if the input was tainted" do
- str = 'abc'
- str.taint
-
- s = StringScanner.new(str)
-
- s.send(@method).tainted?.should be_true
- s.send(@method).tainted?.should be_true
- s.send(@method).tainted?.should be_true
- end
- end
end
diff --git a/spec/ruby/library/stringscanner/shared/extract_range_matched.rb b/spec/ruby/library/stringscanner/shared/extract_range_matched.rb
index 5c536f5c01..070a132812 100644
--- a/spec/ruby/library/stringscanner/shared/extract_range_matched.rb
+++ b/spec/ruby/library/stringscanner/shared/extract_range_matched.rb
@@ -10,15 +10,4 @@ describe :extract_range_matched, shared: true do
ch.should_not be_kind_of(cls)
ch.should be_an_instance_of(String)
end
-
- ruby_version_is ''...'2.7' do
- it "taints the returned String if the input was tainted" do
- str = 'abc'
- str.taint
-
- s = StringScanner.new(str)
- s.scan(/\w{1}/)
- s.send(@method).tainted?.should be_true
- end
- end
end
diff --git a/spec/ruby/library/stringscanner/shared/peek.rb b/spec/ruby/library/stringscanner/shared/peek.rb
index 4e2e643353..4c757866c1 100644
--- a/spec/ruby/library/stringscanner/shared/peek.rb
+++ b/spec/ruby/library/stringscanner/shared/peek.rb
@@ -36,14 +36,4 @@ describe :strscan_peek, shared: true do
ch.should_not be_kind_of(cls)
ch.should be_an_instance_of(String)
end
-
- ruby_version_is ''...'2.7' do
- it "taints the returned String if the input was tainted" do
- str = 'abc'
- str.taint
-
- s = StringScanner.new(str)
- s.send(@method, 1).tainted?.should be_true
- end
- end
end
diff --git a/spec/ruby/library/stringscanner/string_spec.rb b/spec/ruby/library/stringscanner/string_spec.rb
index 28e2f0ed37..cba6bd51dd 100644
--- a/spec/ruby/library/stringscanner/string_spec.rb
+++ b/spec/ruby/library/stringscanner/string_spec.rb
@@ -3,7 +3,7 @@ require 'strscan'
describe "StringScanner#string" do
before :each do
- @string = "This is a test"
+ @string = +"This is a test"
@s = StringScanner.new(@string)
end
diff --git a/spec/ruby/library/time/to_datetime_spec.rb b/spec/ruby/library/time/to_datetime_spec.rb
index 0e37a61108..9c44f38e5c 100644
--- a/spec/ruby/library/time/to_datetime_spec.rb
+++ b/spec/ruby/library/time/to_datetime_spec.rb
@@ -1,11 +1,13 @@
require_relative '../../spec_helper'
require 'time'
+require 'date'
+date_version = defined?(Date::VERSION) ? Date::VERSION : '3.1.0'
describe "Time#to_datetime" do
it "returns a DateTime representing the same instant" do
- time = Time.utc(3, 12, 31, 23, 58, 59)
+ time = Time.utc(2012, 12, 31, 23, 58, 59)
datetime = time.to_datetime
- datetime.year.should == 3
+ datetime.year.should == 2012
datetime.month.should == 12
datetime.day.should == 31
datetime.hour.should == 23
@@ -13,6 +15,19 @@ describe "Time#to_datetime" do
datetime.sec.should == 59
end
+ version_is date_version, '3.2.3' do #ruby_version_is '3.2' do
+ it "returns a DateTime representing the same instant before Gregorian" do
+ time = Time.utc(1582, 10, 14, 23, 58, 59)
+ datetime = time.to_datetime
+ datetime.year.should == 1582
+ datetime.month.should == 10
+ datetime.day.should == 4
+ datetime.hour.should == 23
+ datetime.min.should == 58
+ datetime.sec.should == 59
+ end
+ end
+
it "roundtrips" do
time = Time.utc(3, 12, 31, 23, 58, 59)
datetime = time.to_datetime
diff --git a/spec/ruby/library/uri/generic/host_spec.rb b/spec/ruby/library/uri/generic/host_spec.rb
index f2076d2bc1..210124ef66 100644
--- a/spec/ruby/library/uri/generic/host_spec.rb
+++ b/spec/ruby/library/uri/generic/host_spec.rb
@@ -2,7 +2,12 @@ require_relative '../../../spec_helper'
require 'uri'
describe "URI::Generic#host" do
- it "needs to be reviewed for spec completeness"
+ version_is URI::VERSION, "0.12" do #ruby_version_is "3.2" do
+ # https://hackerone.com/reports/156615
+ it "returns empty string when host is empty" do
+ URI.parse('http:////foo.com').host.should == ''
+ end
+ end
end
describe "URI::Generic#host=" do
diff --git a/spec/ruby/library/uri/generic/to_s_spec.rb b/spec/ruby/library/uri/generic/to_s_spec.rb
index 8c90d7645b..8cebd374a1 100644
--- a/spec/ruby/library/uri/generic/to_s_spec.rb
+++ b/spec/ruby/library/uri/generic/to_s_spec.rb
@@ -2,5 +2,10 @@ require_relative '../../../spec_helper'
require 'uri'
describe "URI::Generic#to_s" do
- it "needs to be reviewed for spec completeness"
+ version_is URI::VERSION, "0.12" do #ruby_version_is "3.2" do
+ # https://hackerone.com/reports/156615
+ it "preserves / characters when host is empty" do
+ URI('http:///foo.com').to_s.should == 'http:///foo.com'
+ end
+ end
end
diff --git a/spec/ruby/library/win32ole/win32ole/_getproperty_spec.rb b/spec/ruby/library/win32ole/win32ole/_getproperty_spec.rb
index 940eebfb91..52cb978bea 100644
--- a/spec/ruby/library/win32ole/win32ole/_getproperty_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole/_getproperty_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require_relative '../fixtures/classes'
diff --git a/spec/ruby/library/win32ole/win32ole/_invoke_spec.rb b/spec/ruby/library/win32ole/win32ole/_invoke_spec.rb
index 91f5091d24..994c2e6d36 100644
--- a/spec/ruby/library/win32ole/win32ole/_invoke_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole/_invoke_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require_relative '../fixtures/classes'
diff --git a/spec/ruby/library/win32ole/win32ole/codepage_spec.rb b/spec/ruby/library/win32ole/win32ole/codepage_spec.rb
index 4e0cf5ca55..07e93646ac 100644
--- a/spec/ruby/library/win32ole/win32ole/codepage_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole/codepage_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require_relative '../fixtures/classes'
diff --git a/spec/ruby/library/win32ole/win32ole/connect_spec.rb b/spec/ruby/library/win32ole/win32ole/connect_spec.rb
index 72dceb1572..ac0976ddc1 100644
--- a/spec/ruby/library/win32ole/win32ole/connect_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole/connect_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require_relative '../fixtures/classes'
diff --git a/spec/ruby/library/win32ole/win32ole/const_load_spec.rb b/spec/ruby/library/win32ole/win32ole/const_load_spec.rb
index cacc7a2b22..2099c4aa66 100644
--- a/spec/ruby/library/win32ole/win32ole/const_load_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole/const_load_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require_relative '../fixtures/classes'
diff --git a/spec/ruby/library/win32ole/win32ole/constants_spec.rb b/spec/ruby/library/win32ole/win32ole/constants_spec.rb
index 978b7ade92..8533741440 100644
--- a/spec/ruby/library/win32ole/win32ole/constants_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole/constants_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require_relative '../fixtures/classes'
diff --git a/spec/ruby/library/win32ole/win32ole/create_guid_spec.rb b/spec/ruby/library/win32ole/win32ole/create_guid_spec.rb
index 2e18b6ab11..8aa853df9e 100644
--- a/spec/ruby/library/win32ole/win32ole/create_guid_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole/create_guid_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require_relative '../fixtures/classes'
diff --git a/spec/ruby/library/win32ole/win32ole/invoke_spec.rb b/spec/ruby/library/win32ole/win32ole/invoke_spec.rb
index 08a5156e05..d6ff7fade3 100644
--- a/spec/ruby/library/win32ole/win32ole/invoke_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole/invoke_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require_relative '../fixtures/classes'
diff --git a/spec/ruby/library/win32ole/win32ole/locale_spec.rb b/spec/ruby/library/win32ole/win32ole/locale_spec.rb
index 75a82ddd7f..78ede4375a 100644
--- a/spec/ruby/library/win32ole/win32ole/locale_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole/locale_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require_relative '../fixtures/classes'
diff --git a/spec/ruby/library/win32ole/win32ole/new_spec.rb b/spec/ruby/library/win32ole/win32ole/new_spec.rb
index 6b717195f1..7e91c2d3ea 100644
--- a/spec/ruby/library/win32ole/win32ole/new_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole/new_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require_relative '../fixtures/classes'
diff --git a/spec/ruby/library/win32ole/win32ole/ole_func_methods_spec.rb b/spec/ruby/library/win32ole/win32ole/ole_func_methods_spec.rb
index 75748182fe..2bbe8c27d4 100644
--- a/spec/ruby/library/win32ole/win32ole/ole_func_methods_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole/ole_func_methods_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require_relative '../fixtures/classes'
diff --git a/spec/ruby/library/win32ole/win32ole/ole_get_methods_spec.rb b/spec/ruby/library/win32ole/win32ole/ole_get_methods_spec.rb
index a991624a23..c1d1970214 100644
--- a/spec/ruby/library/win32ole/win32ole/ole_get_methods_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole/ole_get_methods_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require_relative '../fixtures/classes'
diff --git a/spec/ruby/library/win32ole/win32ole/ole_method_help_spec.rb b/spec/ruby/library/win32ole/win32ole/ole_method_help_spec.rb
index 8a26d79a20..9cb3f9e6cf 100644
--- a/spec/ruby/library/win32ole/win32ole/ole_method_help_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole/ole_method_help_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require_relative '../fixtures/classes'
require_relative 'shared/ole_method'
diff --git a/spec/ruby/library/win32ole/win32ole/ole_method_spec.rb b/spec/ruby/library/win32ole/win32ole/ole_method_spec.rb
index f82a212f5d..e48ff8d905 100644
--- a/spec/ruby/library/win32ole/win32ole/ole_method_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole/ole_method_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require_relative '../fixtures/classes'
require_relative 'shared/ole_method'
diff --git a/spec/ruby/library/win32ole/win32ole/ole_methods_spec.rb b/spec/ruby/library/win32ole/win32ole/ole_methods_spec.rb
index 5ac9ae9cfa..fe161ce9f0 100644
--- a/spec/ruby/library/win32ole/win32ole/ole_methods_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole/ole_methods_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require_relative '../fixtures/classes'
diff --git a/spec/ruby/library/win32ole/win32ole/ole_obj_help_spec.rb b/spec/ruby/library/win32ole/win32ole/ole_obj_help_spec.rb
index ef8944ee39..afcf16a051 100644
--- a/spec/ruby/library/win32ole/win32ole/ole_obj_help_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole/ole_obj_help_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require_relative '../fixtures/classes'
diff --git a/spec/ruby/library/win32ole/win32ole/ole_put_methods_spec.rb b/spec/ruby/library/win32ole/win32ole/ole_put_methods_spec.rb
index 727291e9f0..c091c83c95 100644
--- a/spec/ruby/library/win32ole/win32ole/ole_put_methods_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole/ole_put_methods_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require_relative '../fixtures/classes'
diff --git a/spec/ruby/library/win32ole/win32ole/setproperty_spec.rb b/spec/ruby/library/win32ole/win32ole/setproperty_spec.rb
index 7409823f20..bacdee63da 100644
--- a/spec/ruby/library/win32ole/win32ole/setproperty_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole/setproperty_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require_relative '../fixtures/classes'
require_relative 'shared/setproperty'
diff --git a/spec/ruby/library/win32ole/win32ole_event/new_spec.rb b/spec/ruby/library/win32ole/win32ole_event/new_spec.rb
index a1a1612393..94fabb1e3b 100644
--- a/spec/ruby/library/win32ole/win32ole_event/new_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_event/new_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require_relative '../fixtures/classes'
diff --git a/spec/ruby/library/win32ole/win32ole_event/on_event_spec.rb b/spec/ruby/library/win32ole/win32ole_event/on_event_spec.rb
index feb26b0637..0957bdd2d4 100644
--- a/spec/ruby/library/win32ole/win32ole_event/on_event_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_event/on_event_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require_relative '../fixtures/classes'
guard -> { WIN32OLESpecs::MSXML_AVAILABLE } do
diff --git a/spec/ruby/library/win32ole/win32ole_method/dispid_spec.rb b/spec/ruby/library/win32ole/win32ole_method/dispid_spec.rb
index 69068683b7..ece71df0d4 100644
--- a/spec/ruby/library/win32ole/win32ole_method/dispid_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/dispid_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_method/event_interface_spec.rb b/spec/ruby/library/win32ole/win32ole_method/event_interface_spec.rb
index 70c8b30cca..78634d2fde 100644
--- a/spec/ruby/library/win32ole/win32ole_method/event_interface_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/event_interface_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require_relative '../fixtures/classes'
guard -> { WIN32OLESpecs::SYSTEM_MONITOR_CONTROL_AVAILABLE } do
diff --git a/spec/ruby/library/win32ole/win32ole_method/event_spec.rb b/spec/ruby/library/win32ole/win32ole_method/event_spec.rb
index c41f8fe99d..9b642a010c 100644
--- a/spec/ruby/library/win32ole/win32ole_method/event_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/event_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require_relative '../fixtures/classes'
guard -> { WIN32OLESpecs::SYSTEM_MONITOR_CONTROL_AVAILABLE } do
diff --git a/spec/ruby/library/win32ole/win32ole_method/helpcontext_spec.rb b/spec/ruby/library/win32ole/win32ole_method/helpcontext_spec.rb
index 21b3ae8bde..d1c5ee3be2 100644
--- a/spec/ruby/library/win32ole/win32ole_method/helpcontext_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/helpcontext_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_method/helpfile_spec.rb b/spec/ruby/library/win32ole/win32ole_method/helpfile_spec.rb
index b6d0a19a37..59dad9244c 100644
--- a/spec/ruby/library/win32ole/win32ole_method/helpfile_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/helpfile_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_method/helpstring_spec.rb b/spec/ruby/library/win32ole/win32ole_method/helpstring_spec.rb
index 9f940fd4a0..b2f24ba151 100644
--- a/spec/ruby/library/win32ole/win32ole_method/helpstring_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/helpstring_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_method/invkind_spec.rb b/spec/ruby/library/win32ole/win32ole_method/invkind_spec.rb
index 7fff479daf..d7fedf0d36 100644
--- a/spec/ruby/library/win32ole/win32ole_method/invkind_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/invkind_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_method/invoke_kind_spec.rb b/spec/ruby/library/win32ole/win32ole_method/invoke_kind_spec.rb
index e8638abd91..d5536fd17b 100644
--- a/spec/ruby/library/win32ole/win32ole_method/invoke_kind_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/invoke_kind_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_method/name_spec.rb b/spec/ruby/library/win32ole/win32ole_method/name_spec.rb
index cd5404fc54..477b820f4d 100644
--- a/spec/ruby/library/win32ole/win32ole_method/name_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/name_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
require_relative 'shared/name'
platform_is :windows do
diff --git a/spec/ruby/library/win32ole/win32ole_method/new_spec.rb b/spec/ruby/library/win32ole/win32ole_method/new_spec.rb
index 8ebf93b992..4e427421b9 100644
--- a/spec/ruby/library/win32ole/win32ole_method/new_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/new_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_method/offset_vtbl_spec.rb b/spec/ruby/library/win32ole/win32ole_method/offset_vtbl_spec.rb
index 8e50c39787..b3da9a8303 100644
--- a/spec/ruby/library/win32ole/win32ole_method/offset_vtbl_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/offset_vtbl_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_method/params_spec.rb b/spec/ruby/library/win32ole/win32ole_method/params_spec.rb
index 2f8da3d45b..09fb0eb5ac 100644
--- a/spec/ruby/library/win32ole/win32ole_method/params_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/params_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_method/return_type_detail_spec.rb b/spec/ruby/library/win32ole/win32ole_method/return_type_detail_spec.rb
index f8ce3e1b3a..582a5951d5 100644
--- a/spec/ruby/library/win32ole/win32ole_method/return_type_detail_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/return_type_detail_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_method/return_type_spec.rb b/spec/ruby/library/win32ole/win32ole_method/return_type_spec.rb
index 58e26df77b..dd8add402d 100644
--- a/spec/ruby/library/win32ole/win32ole_method/return_type_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/return_type_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_method/return_vtype_spec.rb b/spec/ruby/library/win32ole/win32ole_method/return_vtype_spec.rb
index dc159dd09e..3fca3d54ed 100644
--- a/spec/ruby/library/win32ole/win32ole_method/return_vtype_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/return_vtype_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_method/size_opt_params_spec.rb b/spec/ruby/library/win32ole/win32ole_method/size_opt_params_spec.rb
index a38fe5c681..fe9facb53a 100644
--- a/spec/ruby/library/win32ole/win32ole_method/size_opt_params_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/size_opt_params_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_method/size_params_spec.rb b/spec/ruby/library/win32ole/win32ole_method/size_params_spec.rb
index 0c5a94c338..8ea6e61e7d 100644
--- a/spec/ruby/library/win32ole/win32ole_method/size_params_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/size_params_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_method/to_s_spec.rb b/spec/ruby/library/win32ole/win32ole_method/to_s_spec.rb
index ecb3c08038..11107a77fc 100644
--- a/spec/ruby/library/win32ole/win32ole_method/to_s_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/to_s_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
require_relative 'shared/name'
platform_is :windows do
diff --git a/spec/ruby/library/win32ole/win32ole_method/visible_spec.rb b/spec/ruby/library/win32ole/win32ole_method/visible_spec.rb
index 918b6ef782..d1a50523fc 100644
--- a/spec/ruby/library/win32ole/win32ole_method/visible_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_method/visible_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_param/default_spec.rb b/spec/ruby/library/win32ole/win32ole_param/default_spec.rb
index af08c84782..44bd3d7fd3 100644
--- a/spec/ruby/library/win32ole/win32ole_param/default_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_param/default_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_param/input_spec.rb b/spec/ruby/library/win32ole/win32ole_param/input_spec.rb
index e2a90daa56..e9134b1df8 100644
--- a/spec/ruby/library/win32ole/win32ole_param/input_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_param/input_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_param/name_spec.rb b/spec/ruby/library/win32ole/win32ole_param/name_spec.rb
index 0c20c24720..67a8955ba4 100644
--- a/spec/ruby/library/win32ole/win32ole_param/name_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_param/name_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
require_relative 'shared/name'
platform_is :windows do
diff --git a/spec/ruby/library/win32ole/win32ole_param/ole_type_detail_spec.rb b/spec/ruby/library/win32ole/win32ole_param/ole_type_detail_spec.rb
index e683d1c16e..f05455e3f1 100644
--- a/spec/ruby/library/win32ole/win32ole_param/ole_type_detail_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_param/ole_type_detail_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_param/ole_type_spec.rb b/spec/ruby/library/win32ole/win32ole_param/ole_type_spec.rb
index b9a3639c3e..1467130e03 100644
--- a/spec/ruby/library/win32ole/win32ole_param/ole_type_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_param/ole_type_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_param/optional_spec.rb b/spec/ruby/library/win32ole/win32ole_param/optional_spec.rb
index 3fb9dc1867..b39ee41179 100644
--- a/spec/ruby/library/win32ole/win32ole_param/optional_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_param/optional_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_param/retval_spec.rb b/spec/ruby/library/win32ole/win32ole_param/retval_spec.rb
index f5546e79e5..dd613dd29a 100644
--- a/spec/ruby/library/win32ole/win32ole_param/retval_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_param/retval_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_param/to_s_spec.rb b/spec/ruby/library/win32ole/win32ole_param/to_s_spec.rb
index 5b4b4c1c80..e9153a2eb2 100644
--- a/spec/ruby/library/win32ole/win32ole_param/to_s_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_param/to_s_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
require_relative 'shared/name'
platform_is :windows do
diff --git a/spec/ruby/library/win32ole/win32ole_type/guid_spec.rb b/spec/ruby/library/win32ole/win32ole_type/guid_spec.rb
index 25907c8e32..abdf8d34b9 100644
--- a/spec/ruby/library/win32ole/win32ole_type/guid_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/guid_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_type/helpcontext_spec.rb b/spec/ruby/library/win32ole/win32ole_type/helpcontext_spec.rb
index d436835188..eee23abc56 100644
--- a/spec/ruby/library/win32ole/win32ole_type/helpcontext_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/helpcontext_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_type/helpfile_spec.rb b/spec/ruby/library/win32ole/win32ole_type/helpfile_spec.rb
index 01e6945138..3a0a9ead94 100644
--- a/spec/ruby/library/win32ole/win32ole_type/helpfile_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/helpfile_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_type/helpstring_spec.rb b/spec/ruby/library/win32ole/win32ole_type/helpstring_spec.rb
index 3bd2cbe5dd..9ab0004668 100644
--- a/spec/ruby/library/win32ole/win32ole_type/helpstring_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/helpstring_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_type/major_version_spec.rb b/spec/ruby/library/win32ole/win32ole_type/major_version_spec.rb
index 7dae16617d..7d2731f778 100644
--- a/spec/ruby/library/win32ole/win32ole_type/major_version_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/major_version_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_type/minor_version_spec.rb b/spec/ruby/library/win32ole/win32ole_type/minor_version_spec.rb
index ff412dd100..3904e78d42 100644
--- a/spec/ruby/library/win32ole/win32ole_type/minor_version_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/minor_version_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_type/name_spec.rb b/spec/ruby/library/win32ole/win32ole_type/name_spec.rb
index b7a28c553a..d76998d7dc 100644
--- a/spec/ruby/library/win32ole/win32ole_type/name_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/name_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
require_relative 'shared/name'
platform_is :windows do
diff --git a/spec/ruby/library/win32ole/win32ole_type/new_spec.rb b/spec/ruby/library/win32ole/win32ole_type/new_spec.rb
index 3c3aa1c390..cc691ffa67 100644
--- a/spec/ruby/library/win32ole/win32ole_type/new_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/new_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_type/ole_classes_spec.rb b/spec/ruby/library/win32ole/win32ole_type/ole_classes_spec.rb
index 0ce0fc98a4..a3a1d4ac58 100644
--- a/spec/ruby/library/win32ole/win32ole_type/ole_classes_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/ole_classes_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_type/ole_methods_spec.rb b/spec/ruby/library/win32ole/win32ole_type/ole_methods_spec.rb
index 9265549d20..3b99b97a61 100644
--- a/spec/ruby/library/win32ole/win32ole_type/ole_methods_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/ole_methods_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_type/ole_type_spec.rb b/spec/ruby/library/win32ole/win32ole_type/ole_type_spec.rb
index 2bc19aa85e..24292b1c4f 100644
--- a/spec/ruby/library/win32ole/win32ole_type/ole_type_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/ole_type_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_type/progid_spec.rb b/spec/ruby/library/win32ole/win32ole_type/progid_spec.rb
index f0d80ba39e..340fdb34e8 100644
--- a/spec/ruby/library/win32ole/win32ole_type/progid_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/progid_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_type/progids_spec.rb b/spec/ruby/library/win32ole/win32ole_type/progids_spec.rb
index 19d8bf56e0..793535b48d 100644
--- a/spec/ruby/library/win32ole/win32ole_type/progids_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/progids_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_type/src_type_spec.rb b/spec/ruby/library/win32ole/win32ole_type/src_type_spec.rb
index 71e304d80a..3f89fe702a 100644
--- a/spec/ruby/library/win32ole/win32ole_type/src_type_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/src_type_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_type/to_s_spec.rb b/spec/ruby/library/win32ole/win32ole_type/to_s_spec.rb
index b713990ed2..9f086a5a35 100644
--- a/spec/ruby/library/win32ole/win32ole_type/to_s_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/to_s_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
require_relative 'shared/name'
platform_is :windows do
diff --git a/spec/ruby/library/win32ole/win32ole_type/typekind_spec.rb b/spec/ruby/library/win32ole/win32ole_type/typekind_spec.rb
index 35f3562721..391d505e01 100644
--- a/spec/ruby/library/win32ole/win32ole_type/typekind_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/typekind_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_type/typelibs_spec.rb b/spec/ruby/library/win32ole/win32ole_type/typelibs_spec.rb
index 369e0274f3..a487208caa 100644
--- a/spec/ruby/library/win32ole/win32ole_type/typelibs_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/typelibs_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_type/variables_spec.rb b/spec/ruby/library/win32ole/win32ole_type/variables_spec.rb
index fbf3dd0341..7f61b8af95 100644
--- a/spec/ruby/library/win32ole/win32ole_type/variables_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/variables_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_type/visible_spec.rb b/spec/ruby/library/win32ole/win32ole_type/visible_spec.rb
index 403b2b843b..99e34edcdd 100644
--- a/spec/ruby/library/win32ole/win32ole_type/visible_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_type/visible_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_variable/name_spec.rb b/spec/ruby/library/win32ole/win32ole_variable/name_spec.rb
index 8bac1a9891..dd9bfa594f 100644
--- a/spec/ruby/library/win32ole/win32ole_variable/name_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_variable/name_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
require_relative 'shared/name'
platform_is :windows do
diff --git a/spec/ruby/library/win32ole/win32ole_variable/ole_type_detail_spec.rb b/spec/ruby/library/win32ole/win32ole_variable/ole_type_detail_spec.rb
index dab4edabaa..7a9c791494 100644
--- a/spec/ruby/library/win32ole/win32ole_variable/ole_type_detail_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_variable/ole_type_detail_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_variable/ole_type_spec.rb b/spec/ruby/library/win32ole/win32ole_variable/ole_type_spec.rb
index d08acc9bde..03a9aa4c74 100644
--- a/spec/ruby/library/win32ole/win32ole_variable/ole_type_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_variable/ole_type_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_variable/to_s_spec.rb b/spec/ruby/library/win32ole/win32ole_variable/to_s_spec.rb
index 000ac14d7e..d4cab8e924 100644
--- a/spec/ruby/library/win32ole/win32ole_variable/to_s_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_variable/to_s_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
require_relative 'shared/name'
platform_is :windows do
diff --git a/spec/ruby/library/win32ole/win32ole_variable/value_spec.rb b/spec/ruby/library/win32ole/win32ole_variable/value_spec.rb
index 4f240b561c..b7849793c5 100644
--- a/spec/ruby/library/win32ole/win32ole_variable/value_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_variable/value_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_variable/variable_kind_spec.rb b/spec/ruby/library/win32ole/win32ole_variable/variable_kind_spec.rb
index 4cca7f8874..7a79d32ddc 100644
--- a/spec/ruby/library/win32ole/win32ole_variable/variable_kind_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_variable/variable_kind_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_variable/varkind_spec.rb b/spec/ruby/library/win32ole/win32ole_variable/varkind_spec.rb
index 56cd1c337a..9d7b8238c8 100644
--- a/spec/ruby/library/win32ole/win32ole_variable/varkind_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_variable/varkind_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/win32ole/win32ole_variable/visible_spec.rb b/spec/ruby/library/win32ole/win32ole_variable/visible_spec.rb
index 7f7a557b57..60252e8139 100644
--- a/spec/ruby/library/win32ole/win32ole_variable/visible_spec.rb
+++ b/spec/ruby/library/win32ole/win32ole_variable/visible_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
platform_is :windows do
require 'win32ole'
diff --git a/spec/ruby/library/yaml/dump_spec.rb b/spec/ruby/library/yaml/dump_spec.rb
index 3107a8f51d..ea94b2f856 100644
--- a/spec/ruby/library/yaml/dump_spec.rb
+++ b/spec/ruby/library/yaml/dump_spec.rb
@@ -1,17 +1,21 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/common'
-# TODO: WTF is this using a global?
+require 'yaml'
+
describe "YAML.dump" do
+ before :each do
+ @test_file = tmp("yaml_test_file")
+ end
+
after :each do
- rm_r $test_file
+ rm_r @test_file
end
it "converts an object to YAML and write result to io when io provided" do
- File.open($test_file, 'w' ) do |io|
+ File.open(@test_file, 'w' ) do |io|
YAML.dump( ['badger', 'elephant', 'tiger'], io )
end
- YAML.load_file($test_file).should == ['badger', 'elephant', 'tiger']
+ YAML.load_file(@test_file).should == ['badger', 'elephant', 'tiger']
end
it "returns a string containing dumped YAML when no io provided" do
diff --git a/spec/ruby/library/yaml/dump_stream_spec.rb b/spec/ruby/library/yaml/dump_stream_spec.rb
index 9d30fef819..f0578fa800 100644
--- a/spec/ruby/library/yaml/dump_stream_spec.rb
+++ b/spec/ruby/library/yaml/dump_stream_spec.rb
@@ -1,5 +1,6 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/common'
+
+require 'yaml'
describe "YAML.dump_stream" do
it "returns a YAML stream containing the objects passed" do
diff --git a/spec/ruby/library/yaml/fixtures/common.rb b/spec/ruby/library/yaml/fixtures/common.rb
deleted file mode 100644
index f7fb4037e7..0000000000
--- a/spec/ruby/library/yaml/fixtures/common.rb
+++ /dev/null
@@ -1,4 +0,0 @@
-require 'yaml'
-
-$test_file = tmp("yaml_test_file")
-$test_parse_file = File.dirname(__FILE__) + "/test_yaml.yml"
diff --git a/spec/ruby/library/yaml/fixtures/strings.rb b/spec/ruby/library/yaml/fixtures/strings.rb
index 6f66dc3659..f478f89823 100644
--- a/spec/ruby/library/yaml/fixtures/strings.rb
+++ b/spec/ruby/library/yaml/fixtures/strings.rb
@@ -1,36 +1,26 @@
-$complex_key_1 = <<EOY
- ? # PLAY SCHEDULE
- - Detroit Tigers
- - Chicago Cubs
- :
- - 2001-07-23
+module YAMLSpecs
+ COMPLEX_KEY_1 = <<~EOY
+ ? # PLAY SCHEDULE
+ - Detroit Tigers
+ - Chicago Cubs
+ :
+ - 2001-07-23
- ? [ New York Yankees,
- Atlanta Braves ]
- : [ 2001-07-02, 2001-08-12,
- 2001-08-14 ]
-EOY
+ ? [ New York Yankees,
+ Atlanta Braves ]
+ : [ 2001-07-02, 2001-08-12,
+ 2001-08-14 ]
+ EOY
-$to_yaml_hash =
-<<EOY
--
- avg: 0.278
- hr: 65
- name: Mark McGwire
--
- avg: 0.288
- hr: 63
- name: Sammy Sosa
-EOY
+ MULTIDOCUMENT = <<~EOY
+ ---
+ - Mark McGwire
+ - Sammy Sosa
+ - Ken Griffey
-$multidocument = <<EOY
----
-- Mark McGwire
-- Sammy Sosa
-- Ken Griffey
-
-# Team ranking
----
-- Chicago Cubs
-- St Louis Cardinals
-EOY
+ # Team ranking
+ ---
+ - Chicago Cubs
+ - St Louis Cardinals
+ EOY
+end
diff --git a/spec/ruby/library/yaml/load_file_spec.rb b/spec/ruby/library/yaml/load_file_spec.rb
index 2363c08120..4941d0485b 100644
--- a/spec/ruby/library/yaml/load_file_spec.rb
+++ b/spec/ruby/library/yaml/load_file_spec.rb
@@ -1,13 +1,18 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/common'
+
+require 'yaml'
describe "YAML.load_file" do
+ before :each do
+ @test_file = tmp("yaml_test_file")
+ end
+
after :each do
- rm_r $test_file
+ rm_r @test_file
end
it "returns a hash" do
- File.open($test_file,'w' ){|io| YAML.dump( {"bar"=>2, "car"=>1}, io ) }
- YAML.load_file($test_file).should == {"bar"=>2, "car"=>1}
+ File.open(@test_file,'w' ){|io| YAML.dump( {"bar"=>2, "car"=>1}, io ) }
+ YAML.load_file(@test_file).should == {"bar"=>2, "car"=>1}
end
end
diff --git a/spec/ruby/library/yaml/load_stream_spec.rb b/spec/ruby/library/yaml/load_stream_spec.rb
index 689653c8cd..31bc862f5e 100644
--- a/spec/ruby/library/yaml/load_stream_spec.rb
+++ b/spec/ruby/library/yaml/load_stream_spec.rb
@@ -1,8 +1,9 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/common'
require_relative 'fixtures/strings'
require_relative 'shared/each_document'
+require 'yaml'
+
describe "YAML.load_stream" do
it_behaves_like :yaml_each_document, :load_stream
end
diff --git a/spec/ruby/library/yaml/parse_file_spec.rb b/spec/ruby/library/yaml/parse_file_spec.rb
index 8c59a2d7ef..7bffcdc62f 100644
--- a/spec/ruby/library/yaml/parse_file_spec.rb
+++ b/spec/ruby/library/yaml/parse_file_spec.rb
@@ -1,8 +1,10 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/common'
-describe "YAML#parse_file" do
+require 'yaml'
+
+describe "YAML.parse_file" do
it "returns a YAML::Syck::Map object after parsing a YAML file" do
- YAML.parse_file($test_parse_file).should be_kind_of(Psych::Nodes::Document)
+ test_parse_file = fixture __FILE__, "test_yaml.yml"
+ YAML.parse_file(test_parse_file).should be_kind_of(Psych::Nodes::Document)
end
end
diff --git a/spec/ruby/library/yaml/parse_spec.rb b/spec/ruby/library/yaml/parse_spec.rb
index d5dbfdcee2..37e2b7fa0a 100644
--- a/spec/ruby/library/yaml/parse_spec.rb
+++ b/spec/ruby/library/yaml/parse_spec.rb
@@ -1,13 +1,14 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/common'
-describe "YAML#parse with an empty string" do
+require 'yaml'
+
+describe "YAML.parse with an empty string" do
it "returns false" do
YAML.parse('').should be_false
end
end
-describe "YAML#parse" do
+describe "YAML.parse" do
before :each do
@string_yaml = "foo".to_yaml
end
diff --git a/spec/ruby/library/yaml/shared/each_document.rb b/spec/ruby/library/yaml/shared/each_document.rb
index 999123dc2a..6f00aee297 100644
--- a/spec/ruby/library/yaml/shared/each_document.rb
+++ b/spec/ruby/library/yaml/shared/each_document.rb
@@ -1,7 +1,7 @@
describe :yaml_each_document, shared: true do
it "calls the block on each successive document" do
documents = []
- YAML.send(@method, $multidocument) do |doc|
+ YAML.send(@method, YAMLSpecs::MULTIDOCUMENT) do |doc|
documents << doc
end
documents.should == [["Mark McGwire", "Sammy Sosa", "Ken Griffey"],
@@ -9,7 +9,8 @@ describe :yaml_each_document, shared: true do
end
it "works on files" do
- File.open($test_parse_file, "r") do |file|
+ test_parse_file = fixture __FILE__, "test_yaml.yml"
+ File.open(test_parse_file, "r") do |file|
YAML.send(@method, file) do |doc|
doc.should == {"project"=>{"name"=>"RubySpec"}}
end
diff --git a/spec/ruby/library/yaml/shared/load.rb b/spec/ruby/library/yaml/shared/load.rb
index 185a5a60cd..bd55332fe5 100644
--- a/spec/ruby/library/yaml/shared/load.rb
+++ b/spec/ruby/library/yaml/shared/load.rb
@@ -1,14 +1,16 @@
-require_relative '../fixtures/common'
require_relative '../fixtures/strings'
+require 'yaml'
+
describe :yaml_load_safe, shared: true do
it "returns a document from current io stream when io provided" do
- File.open($test_file, 'w') do |io|
+ @test_file = tmp("yaml_test_file")
+ File.open(@test_file, 'w') do |io|
YAML.dump( ['badger', 'elephant', 'tiger'], io )
end
- File.open($test_file) { |yf| YAML.send(@method, yf ) }.should == ['badger', 'elephant', 'tiger']
+ File.open(@test_file) { |yf| YAML.send(@method, yf ) }.should == ['badger', 'elephant', 'tiger']
ensure
- rm_r $test_file
+ rm_r @test_file
end
it "loads strings" do
@@ -104,7 +106,7 @@ describe :yaml_load_unsafe, shared: true do
Date.new( 2001, 8, 12 ),
Date.new( 2001, 8, 14 ) ]
}
- YAML.send(@method, $complex_key_1).should == expected
+ YAML.send(@method, YAMLSpecs::COMPLEX_KEY_1).should == expected
end
describe "with iso8601 timestamp" do
diff --git a/spec/ruby/library/yaml/to_yaml_spec.rb b/spec/ruby/library/yaml/to_yaml_spec.rb
index 03ec4f6916..547009c942 100644
--- a/spec/ruby/library/yaml/to_yaml_spec.rb
+++ b/spec/ruby/library/yaml/to_yaml_spec.rb
@@ -1,7 +1,8 @@
require_relative '../../spec_helper'
-require_relative 'fixtures/common'
require_relative 'fixtures/example_class'
+require 'yaml'
+
describe "Object#to_yaml" do
it "returns the YAML representation of an Array object" do
@@ -12,13 +13,21 @@ describe "Object#to_yaml" do
{ "a" => "b"}.to_yaml.should match_yaml("--- \na: b\n")
end
- it "returns the YAML representation of a Class object" do
+ it "returns the YAML representation of an object" do
YAMLSpecs::Example.new("baz").to_yaml.should match_yaml("--- !ruby/object:YAMLSpecs::Example\nname: baz\n")
end
+ it "returns the YAML representation of a Class object" do
+ YAMLSpecs::Example.to_yaml.should match_yaml("--- !ruby/class 'YAMLSpecs::Example'\n")
+ end
+
+ it "returns the YAML representation of a Module object" do
+ Enumerable.to_yaml.should match_yaml("--- !ruby/module 'Enumerable'\n")
+ end
+
it "returns the YAML representation of a Date object" do
require 'date'
- Date.parse('1997/12/30').to_yaml.should match_yaml("--- 1997-12-30\n")
+ Date.new(1997, 12, 30).to_yaml.should match_yaml("--- 1997-12-30\n")
end
it "returns the YAML representation of a FalseClass" do
@@ -58,6 +67,11 @@ describe "Object#to_yaml" do
Person.new("Jane", "female").to_yaml.should match_yaml("--- !ruby/struct:Person\nname: Jane\ngender: female\n")
end
+ it "returns the YAML representation of an unnamed Struct object" do
+ person = Struct.new(:name, :gender)
+ person.new("Jane", "female").to_yaml.should match_yaml("--- !ruby/struct\nname: Jane\ngender: female\n")
+ end
+
it "returns the YAML representation of a Symbol object" do
:symbol.to_yaml.should match_yaml("--- :symbol\n")
end
@@ -72,16 +86,8 @@ describe "Object#to_yaml" do
true_klass.to_yaml.should match_yaml("--- true\n")
end
- ruby_version_is ""..."2.7" do
- it "returns the YAML representation of a Error object" do
- StandardError.new("foobar").to_yaml.should match_yaml("--- !ruby/exception:StandardError\nmessage: foobar\n")
- end
- end
-
- ruby_version_is "2.7" do
- it "returns the YAML representation of a Error object" do
- StandardError.new("foobar").to_yaml.should match_yaml("--- !ruby/exception:StandardError\nmessage: foobar\nbacktrace: \n")
- end
+ it "returns the YAML representation of a Error object" do
+ StandardError.new("foobar").to_yaml.should match_yaml("--- !ruby/exception:StandardError\nmessage: foobar\nbacktrace: \n")
end
it "returns the YAML representation for Range objects" do
diff --git a/spec/ruby/library/zlib/crc_table_spec.rb b/spec/ruby/library/zlib/crc_table_spec.rb
index f7fc2749fa..de8876086b 100644
--- a/spec/ruby/library/zlib/crc_table_spec.rb
+++ b/spec/ruby/library/zlib/crc_table_spec.rb
@@ -2,74 +2,79 @@ require_relative '../../spec_helper'
require "zlib"
describe "Zlib.crc_table" do
-
- it "returns the same value as zlib's get_crc_table()" do
- Zlib.crc_table.should == [
- 0, 1996959894, 3993919788, 2567524794,
- 124634137, 1886057615, 3915621685, 2657392035,
- 249268274, 2044508324, 3772115230, 2547177864,
- 162941995, 2125561021, 3887607047, 2428444049,
- 498536548, 1789927666, 4089016648, 2227061214,
- 450548861, 1843258603, 4107580753, 2211677639,
- 325883990, 1684777152, 4251122042, 2321926636,
- 335633487, 1661365465, 4195302755, 2366115317,
- 997073096, 1281953886, 3579855332, 2724688242,
- 1006888145, 1258607687, 3524101629, 2768942443,
- 901097722, 1119000684, 3686517206, 2898065728,
- 853044451, 1172266101, 3705015759, 2882616665,
- 651767980, 1373503546, 3369554304, 3218104598,
- 565507253, 1454621731, 3485111705, 3099436303,
- 671266974, 1594198024, 3322730930, 2970347812,
- 795835527, 1483230225, 3244367275, 3060149565,
- 1994146192, 31158534, 2563907772, 4023717930,
- 1907459465, 112637215, 2680153253, 3904427059,
- 2013776290, 251722036, 2517215374, 3775830040,
- 2137656763, 141376813, 2439277719, 3865271297,
- 1802195444, 476864866, 2238001368, 4066508878,
- 1812370925, 453092731, 2181625025, 4111451223,
- 1706088902, 314042704, 2344532202, 4240017532,
- 1658658271, 366619977, 2362670323, 4224994405,
- 1303535960, 984961486, 2747007092, 3569037538,
- 1256170817, 1037604311, 2765210733, 3554079995,
- 1131014506, 879679996, 2909243462, 3663771856,
- 1141124467, 855842277, 2852801631, 3708648649,
- 1342533948, 654459306, 3188396048, 3373015174,
- 1466479909, 544179635, 3110523913, 3462522015,
- 1591671054, 702138776, 2966460450, 3352799412,
- 1504918807, 783551873, 3082640443, 3233442989,
- 3988292384, 2596254646, 62317068, 1957810842,
- 3939845945, 2647816111, 81470997, 1943803523,
- 3814918930, 2489596804, 225274430, 2053790376,
- 3826175755, 2466906013, 167816743, 2097651377,
- 4027552580, 2265490386, 503444072, 1762050814,
- 4150417245, 2154129355, 426522225, 1852507879,
- 4275313526, 2312317920, 282753626, 1742555852,
- 4189708143, 2394877945, 397917763, 1622183637,
- 3604390888, 2714866558, 953729732, 1340076626,
- 3518719985, 2797360999, 1068828381, 1219638859,
- 3624741850, 2936675148, 906185462, 1090812512,
- 3747672003, 2825379669, 829329135, 1181335161,
- 3412177804, 3160834842, 628085408, 1382605366,
- 3423369109, 3138078467, 570562233, 1426400815,
- 3317316542, 2998733608, 733239954, 1555261956,
- 3268935591, 3050360625, 752459403, 1541320221,
- 2607071920, 3965973030, 1969922972, 40735498,
- 2617837225, 3943577151, 1913087877, 83908371,
- 2512341634, 3803740692, 2075208622, 213261112,
- 2463272603, 3855990285, 2094854071, 198958881,
- 2262029012, 4057260610, 1759359992, 534414190,
- 2176718541, 4139329115, 1873836001, 414664567,
- 2282248934, 4279200368, 1711684554, 285281116,
- 2405801727, 4167216745, 1634467795, 376229701,
- 2685067896, 3608007406, 1308918612, 956543938,
- 2808555105, 3495958263, 1231636301, 1047427035,
- 2932959818, 3654703836, 1088359270, 936918000,
- 2847714899, 3736837829, 1202900863, 817233897,
- 3183342108, 3401237130, 1404277552, 615818150,
- 3134207493, 3453421203, 1423857449, 601450431,
- 3009837614, 3294710456, 1567103746, 711928724,
- 3020668471, 3272380065, 1510334235, 755167117,
- ]
+ # This spec fails when zlib.h and libz.so are not from the same version.
+ # In older zlib (< 1.2.7 it seems), get_crc_table() is stored as u64[],
+ # but in newer zlib, get_crc_table() is stored as u32[].
+ # Technically, there is ABI breakage between those zlib versions,
+ # but get_crc_table() is an "undocumented function" according to zlib.h.
+ guard -> { ENV["RUBY_SPEC_TEST_ZLIB_CRC_TABLE"] != "false" } do
+ it "returns the same value as zlib's get_crc_table()" do
+ Zlib.crc_table.should == [
+ 0, 1996959894, 3993919788, 2567524794,
+ 124634137, 1886057615, 3915621685, 2657392035,
+ 249268274, 2044508324, 3772115230, 2547177864,
+ 162941995, 2125561021, 3887607047, 2428444049,
+ 498536548, 1789927666, 4089016648, 2227061214,
+ 450548861, 1843258603, 4107580753, 2211677639,
+ 325883990, 1684777152, 4251122042, 2321926636,
+ 335633487, 1661365465, 4195302755, 2366115317,
+ 997073096, 1281953886, 3579855332, 2724688242,
+ 1006888145, 1258607687, 3524101629, 2768942443,
+ 901097722, 1119000684, 3686517206, 2898065728,
+ 853044451, 1172266101, 3705015759, 2882616665,
+ 651767980, 1373503546, 3369554304, 3218104598,
+ 565507253, 1454621731, 3485111705, 3099436303,
+ 671266974, 1594198024, 3322730930, 2970347812,
+ 795835527, 1483230225, 3244367275, 3060149565,
+ 1994146192, 31158534, 2563907772, 4023717930,
+ 1907459465, 112637215, 2680153253, 3904427059,
+ 2013776290, 251722036, 2517215374, 3775830040,
+ 2137656763, 141376813, 2439277719, 3865271297,
+ 1802195444, 476864866, 2238001368, 4066508878,
+ 1812370925, 453092731, 2181625025, 4111451223,
+ 1706088902, 314042704, 2344532202, 4240017532,
+ 1658658271, 366619977, 2362670323, 4224994405,
+ 1303535960, 984961486, 2747007092, 3569037538,
+ 1256170817, 1037604311, 2765210733, 3554079995,
+ 1131014506, 879679996, 2909243462, 3663771856,
+ 1141124467, 855842277, 2852801631, 3708648649,
+ 1342533948, 654459306, 3188396048, 3373015174,
+ 1466479909, 544179635, 3110523913, 3462522015,
+ 1591671054, 702138776, 2966460450, 3352799412,
+ 1504918807, 783551873, 3082640443, 3233442989,
+ 3988292384, 2596254646, 62317068, 1957810842,
+ 3939845945, 2647816111, 81470997, 1943803523,
+ 3814918930, 2489596804, 225274430, 2053790376,
+ 3826175755, 2466906013, 167816743, 2097651377,
+ 4027552580, 2265490386, 503444072, 1762050814,
+ 4150417245, 2154129355, 426522225, 1852507879,
+ 4275313526, 2312317920, 282753626, 1742555852,
+ 4189708143, 2394877945, 397917763, 1622183637,
+ 3604390888, 2714866558, 953729732, 1340076626,
+ 3518719985, 2797360999, 1068828381, 1219638859,
+ 3624741850, 2936675148, 906185462, 1090812512,
+ 3747672003, 2825379669, 829329135, 1181335161,
+ 3412177804, 3160834842, 628085408, 1382605366,
+ 3423369109, 3138078467, 570562233, 1426400815,
+ 3317316542, 2998733608, 733239954, 1555261956,
+ 3268935591, 3050360625, 752459403, 1541320221,
+ 2607071920, 3965973030, 1969922972, 40735498,
+ 2617837225, 3943577151, 1913087877, 83908371,
+ 2512341634, 3803740692, 2075208622, 213261112,
+ 2463272603, 3855990285, 2094854071, 198958881,
+ 2262029012, 4057260610, 1759359992, 534414190,
+ 2176718541, 4139329115, 1873836001, 414664567,
+ 2282248934, 4279200368, 1711684554, 285281116,
+ 2405801727, 4167216745, 1634467795, 376229701,
+ 2685067896, 3608007406, 1308918612, 956543938,
+ 2808555105, 3495958263, 1231636301, 1047427035,
+ 2932959818, 3654703836, 1088359270, 936918000,
+ 2847714899, 3736837829, 1202900863, 817233897,
+ 3183342108, 3401237130, 1404277552, 615818150,
+ 3134207493, 3453421203, 1423857449, 601450431,
+ 3009837614, 3294710456, 1567103746, 711928724,
+ 3020668471, 3272380065, 1510334235, 755167117,
+ ]
+ end
end
-
end
diff --git a/spec/ruby/library/zlib/deflate/deflate_spec.rb b/spec/ruby/library/zlib/deflate/deflate_spec.rb
index 828880f8d8..e16e6ad0ef 100644
--- a/spec/ruby/library/zlib/deflate/deflate_spec.rb
+++ b/spec/ruby/library/zlib/deflate/deflate_spec.rb
@@ -23,7 +23,7 @@ describe "Zlib::Deflate.deflate" do
it "deflates chunked data" do
random_generator = Random.new(0)
- deflated = ''
+ deflated = +''
Zlib::Deflate.deflate(random_generator.bytes(20000)) do |chunk|
deflated << chunk
@@ -58,6 +58,11 @@ describe "Zlib::Deflate#deflate" do
Array.new(31, 0) +
[24, 128, 0, 0, 1]).pack('C*')
end
+
+ it "has a binary encoding" do
+ @deflator.deflate("").encoding.should == Encoding::BINARY
+ @deflator.finish.encoding.should == Encoding::BINARY
+ end
end
describe "Zlib::Deflate#deflate" do
@@ -65,7 +70,7 @@ describe "Zlib::Deflate#deflate" do
before :each do
@deflator = Zlib::Deflate.new
@random_generator = Random.new(0)
- @original = ''
+ @original = +''
@chunks = []
end
diff --git a/spec/ruby/library/zlib/deflate/new_spec.rb b/spec/ruby/library/zlib/deflate/new_spec.rb
deleted file mode 100644
index e15f14f95f..0000000000
--- a/spec/ruby/library/zlib/deflate/new_spec.rb
+++ /dev/null
@@ -1 +0,0 @@
-require_relative '../../../spec_helper'
diff --git a/spec/ruby/library/zlib/deflate/params_spec.rb b/spec/ruby/library/zlib/deflate/params_spec.rb
index 0b1cca8c8a..0242653528 100644
--- a/spec/ruby/library/zlib/deflate/params_spec.rb
+++ b/spec/ruby/library/zlib/deflate/params_spec.rb
@@ -3,7 +3,7 @@ require 'zlib'
describe "Zlib::Deflate#params" do
it "changes the deflate parameters" do
- data = 'abcdefghijklm'
+ data = +'abcdefghijklm'
d = Zlib::Deflate.new Zlib::NO_COMPRESSION, Zlib::MAX_WBITS,
Zlib::DEF_MEM_LEVEL, Zlib::DEFAULT_STRATEGY
diff --git a/spec/ruby/library/zlib/gzipreader/each_line_spec.rb b/spec/ruby/library/zlib/gzipreader/each_line_spec.rb
index efaf27d6bb..6f17365879 100644
--- a/spec/ruby/library/zlib/gzipreader/each_line_spec.rb
+++ b/spec/ruby/library/zlib/gzipreader/each_line_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
require_relative 'shared/each'
describe "Zlib::GzipReader#each_line" do
diff --git a/spec/ruby/library/zlib/gzipreader/each_spec.rb b/spec/ruby/library/zlib/gzipreader/each_spec.rb
index 59aa63e52c..3b98391a87 100644
--- a/spec/ruby/library/zlib/gzipreader/each_spec.rb
+++ b/spec/ruby/library/zlib/gzipreader/each_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
require_relative 'shared/each'
describe "Zlib::GzipReader#each" do
diff --git a/spec/ruby/library/zlib/gzipreader/mtime_spec.rb b/spec/ruby/library/zlib/gzipreader/mtime_spec.rb
new file mode 100644
index 0000000000..e8e71fa72e
--- /dev/null
+++ b/spec/ruby/library/zlib/gzipreader/mtime_spec.rb
@@ -0,0 +1,11 @@
+require_relative '../../../spec_helper'
+require 'zlib'
+require 'stringio'
+
+describe "Zlib::GzipReader#mtime" do
+ it "returns the timestamp from the Gzip header" do
+ io = StringIO.new "\x1f\x8b\x08\x00\x44\x33\x22\x11\x00\xff\x03\x00\x00\x00\x00\x00\x00\x00\x00\x00"
+ gz = Zlib::GzipReader.new(io)
+ gz.mtime.to_i.should == 0x11223344
+ end
+end
diff --git a/spec/ruby/library/zlib/gzipreader/new_spec.rb b/spec/ruby/library/zlib/gzipreader/new_spec.rb
deleted file mode 100644
index e15f14f95f..0000000000
--- a/spec/ruby/library/zlib/gzipreader/new_spec.rb
+++ /dev/null
@@ -1 +0,0 @@
-require_relative '../../../spec_helper'
diff --git a/spec/ruby/library/zlib/inflate/finish_spec.rb b/spec/ruby/library/zlib/inflate/finish_spec.rb
index f6e592fb6b..3e0663e265 100644
--- a/spec/ruby/library/zlib/inflate/finish_spec.rb
+++ b/spec/ruby/library/zlib/inflate/finish_spec.rb
@@ -1,3 +1,4 @@
+require_relative "../../../spec_helper"
require 'zlib'
describe "Zlib::Inflate#finish" do
diff --git a/spec/ruby/library/zlib/inflate/inflate_spec.rb b/spec/ruby/library/zlib/inflate/inflate_spec.rb
index cc33bd4c32..b308a4ba67 100644
--- a/spec/ruby/library/zlib/inflate/inflate_spec.rb
+++ b/spec/ruby/library/zlib/inflate/inflate_spec.rb
@@ -39,6 +39,13 @@ describe "Zlib::Inflate#inflate" do
@inflator.finish.should == 'uncompressed_data'
end
+ it "has a binary encoding" do
+ data = [120, 156, 99, 96, 128, 1, 0, 0, 10, 0, 1].pack('C*')
+ unzipped = @inflator.inflate data
+ @inflator.finish.encoding.should == Encoding::BINARY
+ unzipped.encoding.should == Encoding::BINARY
+ end
+
end
describe "Zlib::Inflate.inflate" do
@@ -65,7 +72,7 @@ describe "Zlib::Inflate.inflate" do
data = [120, 156, 75, 203, 207, 7, 0, 2, 130, 1, 69].pack('C*')
z = Zlib::Inflate.new
# add bytes, one by one
- result = ""
+ result = +""
data.each_byte { |d| result << z.inflate(d.chr)}
result << z.finish
result.should == "foo"
@@ -75,7 +82,7 @@ describe "Zlib::Inflate.inflate" do
data = [120, 156, 75, 203, 207, 7, 0, 2, 130, 1, 69].pack('C*')[0,5]
z = Zlib::Inflate.new
# add bytes, one by one, but not all
- result = ""
+ result = +""
data.each_byte { |d| result << z.inflate(d.chr)}
-> { result << z.finish }.should raise_error(Zlib::BufError)
end
@@ -83,7 +90,7 @@ describe "Zlib::Inflate.inflate" do
it "properly handles excessive data, byte-by-byte" do
main_data = [120, 156, 75, 203, 207, 7, 0, 2, 130, 1, 69].pack('C*')
data = main_data * 2
- result = ""
+ result = +""
z = Zlib::Inflate.new
# add bytes, one by one
@@ -98,7 +105,7 @@ describe "Zlib::Inflate.inflate" do
it "properly handles excessive data, in one go" do
main_data = [120, 156, 75, 203, 207, 7, 0, 2, 130, 1, 69].pack('C*')
data = main_data * 2
- result = ""
+ result = +""
z = Zlib::Inflate.new
result << z.inflate(data)
diff --git a/spec/ruby/library/zlib/inflate/new_spec.rb b/spec/ruby/library/zlib/inflate/new_spec.rb
deleted file mode 100644
index e15f14f95f..0000000000
--- a/spec/ruby/library/zlib/inflate/new_spec.rb
+++ /dev/null
@@ -1 +0,0 @@
-require_relative '../../../spec_helper'
diff --git a/spec/ruby/optional/capi/array_spec.rb b/spec/ruby/optional/capi/array_spec.rb
index 8e90980c6a..9c35017e21 100644
--- a/spec/ruby/optional/capi/array_spec.rb
+++ b/spec/ruby/optional/capi/array_spec.rb
@@ -343,6 +343,40 @@ describe "C-API Array function" do
end
end
+ describe "rb_iterate" do
+ it "calls an callback function as a block passed to an method" do
+ s = [1,2,3,4]
+ s2 = @s.rb_iterate(s)
+
+ s2.should == s
+
+ # Make sure they're different objects
+ s2.equal?(s).should be_false
+ end
+
+ it "calls a function with the other function available as a block" do
+ h = {a: 1, b: 2}
+
+ @s.rb_iterate_each_pair(h).sort.should == [1,2]
+ end
+
+ it "calls a function which can yield into the original block" do
+ s2 = []
+
+ o = Object.new
+ def o.each
+ yield 1
+ yield 2
+ yield 3
+ yield 4
+ end
+
+ @s.rb_iterate_then_yield(o) { |x| s2 << x }
+
+ s2.should == [1,2,3,4]
+ end
+ end
+
describe "rb_block_call" do
it "calls an callback function as a block passed to an method" do
s = [1,2,3,4]
diff --git a/spec/ruby/optional/capi/binding_spec.rb b/spec/ruby/optional/capi/binding_spec.rb
index 966d650c46..2165705457 100644
--- a/spec/ruby/optional/capi/binding_spec.rb
+++ b/spec/ruby/optional/capi/binding_spec.rb
@@ -8,12 +8,21 @@ describe "CApiBindingSpecs" do
end
describe "Kernel#binding" do
- it "gives the top-most Ruby binding when called from C" do
- foo = 14
- b = @b.get_binding
- b.local_variable_get(:foo).should == 14
- b.local_variable_set :foo, 12
- foo.should == 12
+ ruby_version_is '3.2' do
+ it "raises when called from C" do
+ foo = 14
+ -> { @b.get_binding }.should raise_error(RuntimeError)
+ end
+ end
+
+ ruby_version_is ''...'3.2' do
+ it "gives the top-most Ruby binding when called from C" do
+ foo = 14
+ b = @b.get_binding
+ b.local_variable_get(:foo).should == 14
+ b.local_variable_set :foo, 12
+ foo.should == 12
+ end
end
end
end
diff --git a/spec/ruby/optional/capi/class_spec.rb b/spec/ruby/optional/capi/class_spec.rb
index a2d8b3e38a..d0a9913570 100644
--- a/spec/ruby/optional/capi/class_spec.rb
+++ b/spec/ruby/optional/capi/class_spec.rb
@@ -108,17 +108,35 @@ describe "C-API Class function" do
describe "rb_class_new_instance" do
it "allocates and initializes a new object" do
- o = @s.rb_class_new_instance(0, nil, CApiClassSpecs::Alloc)
+ o = @s.rb_class_new_instance([], CApiClassSpecs::Alloc)
o.class.should == CApiClassSpecs::Alloc
o.initialized.should be_true
end
it "passes arguments to the #initialize method" do
- o = @s.rb_class_new_instance(2, [:one, :two], CApiClassSpecs::Alloc)
+ o = @s.rb_class_new_instance([:one, :two], CApiClassSpecs::Alloc)
o.arguments.should == [:one, :two]
end
end
+ describe "rb_class_new_instance_kw" do
+ it "passes arguments and keywords to the #initialize method" do
+ obj = @s.rb_class_new_instance_kw([{pos: 1}, {kw: 2}], CApiClassSpecs::KeywordAlloc)
+ obj.args.should == [{pos: 1}]
+ obj.kwargs.should == {kw: 2}
+
+ obj = @s.rb_class_new_instance_kw([{}], CApiClassSpecs::KeywordAlloc)
+ obj.args.should == []
+ obj.kwargs.should == {}
+ end
+
+ it "raises TypeError if the last argument is not a Hash" do
+ -> {
+ @s.rb_class_new_instance_kw([42], CApiClassSpecs::KeywordAlloc)
+ }.should raise_error(TypeError, 'no implicit conversion of Integer into Hash')
+ end
+ end
+
describe "rb_include_module" do
it "includes a module into a class" do
c = Class.new
@@ -176,16 +194,6 @@ describe "C-API Class function" do
end
end
- describe "rb_define_method" do
- it "defines a method taking variable arguments as a C array if the argument count is -1" do
- @s.rb_method_varargs_1(1, 3, 7, 4).should == [1, 3, 7, 4]
- end
-
- it "defines a method taking variable arguments as a Ruby array if the argument count is -2" do
- @s.rb_method_varargs_2(1, 3, 7, 4).should == [1, 3, 7, 4]
- end
- end
-
describe "rb_class2name" do
it "returns the class name" do
@s.rb_class2name(CApiClassSpecs).should == "CApiClassSpecs"
@@ -194,6 +202,10 @@ describe "C-API Class function" do
it "returns a string for an anonymous class" do
@s.rb_class2name(Class.new).should be_kind_of(String)
end
+
+ it "returns a string beginning with # for an anonymous class" do
+ @s.rb_class2name(Struct.new(:x, :y).new(1, 2).class).should.start_with?('#')
+ end
end
describe "rb_class_path" do
@@ -309,6 +321,15 @@ describe "C-API Class function" do
@s.rb_define_class("ClassSpecDefineClass4", nil)
}.should raise_error(ArgumentError)
end
+
+ it "allows arbitrary names, including constant names not valid in Ruby" do
+ cls = @s.rb_define_class("_INVALID_CLASS", CApiClassSpecs::Super)
+ cls.name.should == "_INVALID_CLASS"
+
+ -> {
+ Object.const_get(cls.name)
+ }.should raise_error(NameError, /wrong constant name/)
+ end
end
describe "rb_define_class_under" do
@@ -353,6 +374,15 @@ describe "C-API Class function" do
it "raises a TypeError if class is defined and its superclass mismatches the given one" do
-> { @s.rb_define_class_under(CApiClassSpecs, "Sub", Object) }.should raise_error(TypeError)
end
+
+ it "allows arbitrary names, including constant names not valid in Ruby" do
+ cls = @s.rb_define_class_under(CApiClassSpecs, "_INVALID_CLASS", CApiClassSpecs::Super)
+ cls.name.should == "CApiClassSpecs::_INVALID_CLASS"
+
+ -> {
+ CApiClassSpecs.const_get(cls.name)
+ }.should raise_error(NameError, /wrong constant name/)
+ end
end
describe "rb_define_class_id_under" do
@@ -380,6 +410,15 @@ describe "C-API Class function" do
it "raises a TypeError if class is defined and its superclass mismatches the given one" do
-> { @s.rb_define_class_id_under(CApiClassSpecs, :Sub, Object) }.should raise_error(TypeError)
end
+
+ it "allows arbitrary names, including constant names not valid in Ruby" do
+ cls = @s.rb_define_class_id_under(CApiClassSpecs, :_INVALID_CLASS2, CApiClassSpecs::Super)
+ cls.name.should == "CApiClassSpecs::_INVALID_CLASS2"
+
+ -> {
+ CApiClassSpecs.const_get(cls.name)
+ }.should raise_error(NameError, /wrong constant name/)
+ end
end
describe "rb_define_class_variable" do
diff --git a/spec/ruby/optional/capi/debug_spec.rb b/spec/ruby/optional/capi/debug_spec.rb
index c8c91417d1..148b8c38fb 100644
--- a/spec/ruby/optional/capi/debug_spec.rb
+++ b/spec/ruby/optional/capi/debug_spec.rb
@@ -17,6 +17,7 @@ describe "C-API Debug function" do
describe "rb_debug_inspector_frame_self_get" do
it "returns self" do
@o.rb_debug_inspector_frame_self_get(0).should == @o
+ @o.rb_debug_inspector_frame_self_get(1).should == self
end
end
@@ -35,10 +36,14 @@ describe "C-API Debug function" do
end
it "matches the locations in rb_debug_inspector_backtrace_locations" do
- frames = @o.rb_debug_inspector_open(42);
+ frames = @o.rb_debug_inspector_open(42)
frames.each do |_s, _klass, binding, _iseq, backtrace_location|
if binding
- "#{backtrace_location.path}:#{backtrace_location.lineno}".should == "#{binding.source_location[0]}:#{binding.source_location[1]}"
+ binding.source_location.should == [backtrace_location.path, backtrace_location.lineno]
+ method_name = binding.eval('__method__')
+ if method_name
+ method_name.should == backtrace_location.base_label.to_sym
+ end
end
end
end
diff --git a/spec/ruby/optional/capi/encoding_spec.rb b/spec/ruby/optional/capi/encoding_spec.rb
index 66c2dd40de..1529e012b0 100644
--- a/spec/ruby/optional/capi/encoding_spec.rb
+++ b/spec/ruby/optional/capi/encoding_spec.rb
@@ -1,8 +1,9 @@
# -*- encoding: utf-8 -*-
+# frozen_string_literal: false
require_relative 'spec_helper'
require_relative 'fixtures/encoding'
-load_extension('encoding')
+extension_path = load_extension('encoding')
describe :rb_enc_get_index, shared: true do
it "returns the index of the encoding of a String" do
@@ -63,6 +64,48 @@ describe "C-API Encoding function" do
end
end
+ describe "rb_enc_strlen" do
+ before :each do
+ @str = 'こにちわ' # Each codepoint in this string is 3 bytes in UTF-8
+ end
+
+ it "returns the correct string length for the encoding" do
+ @s.rb_enc_strlen(@str, @str.bytesize, Encoding::UTF_8).should == 4
+ @s.rb_enc_strlen(@str, @str.bytesize, Encoding::BINARY).should == 12
+ end
+
+ it "returns the string length based on a fixed-width encoding's character length, even if the encoding is incompatible" do
+ @s.rb_enc_strlen(@str, @str.bytesize, Encoding::UTF_16BE).should == 6
+ @s.rb_enc_strlen(@str, @str.bytesize, Encoding::UTF_16LE).should == 6
+ @s.rb_enc_strlen(@str, @str.bytesize, Encoding::UTF_32BE).should == 3
+ @s.rb_enc_strlen(@str, @str.bytesize, Encoding::UTF_32LE).should == 3
+ end
+
+ it "does not consider strings to be NUL-terminated" do
+ s = "abc\0def"
+ @s.rb_enc_strlen(s, s.bytesize, Encoding::US_ASCII).should == 7
+ @s.rb_enc_strlen(s, s.bytesize, Encoding::UTF_8).should == 7
+ end
+
+ describe "handles broken strings" do
+ it "combines valid character and invalid character counts in UTF-8" do
+ # The result is 3 because `rb_enc_strlen` counts the first valid character and then adds
+ # the byte count for the invalid character that follows for 1 + 2.
+ @s.rb_enc_strlen(@str, 5, Encoding::UTF_8).should == 3
+ end
+
+ it "combines valid character and invalid character counts in UTF-16" do
+ @s.rb_enc_strlen(@str, 5, Encoding::UTF_16BE).should == 3
+ end
+
+ it "rounds up for fixed-width encodings" do
+ @s.rb_enc_strlen(@str, 7, Encoding::UTF_32BE).should == 2
+ @s.rb_enc_strlen(@str, 7, Encoding::UTF_32LE).should == 2
+ @s.rb_enc_strlen(@str, 5, Encoding::BINARY).should == 5
+ end
+ end
+ end
+
describe "rb_enc_find" do
it "returns the encoding of an Encoding" do
@s.rb_enc_find("UTF-8").should == "UTF-8"
@@ -128,10 +171,16 @@ describe "C-API Encoding function" do
describe "rb_enc_mbc_to_codepoint" do
it "returns the correct codepoint for the given character and size" do
- @s.rb_enc_mbc_to_codepoint("é", 2).should == 0x00E9
- @s.rb_enc_mbc_to_codepoint("éa", 2).should == 0x00E9
- @s.rb_enc_mbc_to_codepoint("éa", 1).should == 0xC3
- @s.rb_enc_mbc_to_codepoint("éa", 3).should == 0x00E9
+ @s.rb_enc_mbc_to_codepoint("é").should == 0xE9
+ end
+
+ it "returns 0 if p == e" do
+ @s.rb_enc_mbc_to_codepoint("").should == 0
+ end
+
+ it "returns the raw byte if incomplete character in UTF-8" do
+ @s.rb_enc_mbc_to_codepoint("\xC3").should == 0xC3
+ @s.rb_enc_mbc_to_codepoint("\x80").should == 0x80
end
end
@@ -511,19 +560,19 @@ describe "C-API Encoding function" do
describe "rb_ascii8bit_encindex" do
it "returns an index for the ASCII-8BIT encoding" do
- @s.rb_ascii8bit_encindex().should >= 0
+ @s.rb_ascii8bit_encindex().should == 0
end
end
describe "rb_utf8_encindex" do
it "returns an index for the UTF-8 encoding" do
- @s.rb_utf8_encindex().should >= 0
+ @s.rb_utf8_encindex().should == 1
end
end
describe "rb_usascii_encindex" do
it "returns an index for the US-ASCII encoding" do
- @s.rb_usascii_encindex().should >= 0
+ @s.rb_usascii_encindex().should == 2
end
end
@@ -609,27 +658,58 @@ describe "C-API Encoding function" do
end
end
+ describe "rb_enc_raise" do
+ it "forces exception message encoding to the specified one" do
+ utf_8_incompatible_string = "\x81".b
+
+ -> {
+ @s.rb_enc_raise(Encoding::UTF_8, RuntimeError, utf_8_incompatible_string)
+ }.should raise_error { |e|
+ e.message.encoding.should == Encoding::UTF_8
+ e.message.valid_encoding?.should == false
+ e.message.bytes.should == utf_8_incompatible_string.bytes
+ }
+ end
+ end
+
describe "rb_uv_to_utf8" do
it 'converts a Unicode codepoint to a UTF-8 C string' do
str = ' ' * 6
{
- 0 => "\x01",
- 0x7f => "\xC2\x80",
- 0x7ff => "\xE0\xA0\x80",
- 0xffff => "\xF0\x90\x80\x80",
- 0x1fffff => "\xF8\x88\x80\x80\x80",
- 0x3ffffff => "\xFC\x84\x80\x80\x80\x80",
+ 1 => "\x01",
+ 0x80 => "\xC2\x80",
+ 0x800 => "\xE0\xA0\x80",
+ 0x10000 => "\xF0\x90\x80\x80",
+ 0x200000 => "\xF8\x88\x80\x80\x80",
+ 0x4000000 => "\xFC\x84\x80\x80\x80\x80",
}.each do |num, result|
- len = @s.rb_uv_to_utf8(str, num + 1)
- str[0..len-1].should == result
+ len = @s.rb_uv_to_utf8(str, num)
+ str.byteslice(0, len).should == result
end
end
end
+ describe "rb_enc_left_char_head" do
+ it 'returns the head position of a character' do
+ @s.rb_enc_left_char_head("é", 1).should == 0
+ @s.rb_enc_left_char_head("éééé", 7).should == 6
+
+ @s.rb_enc_left_char_head("a", 0).should == 0
+
+ # unclear if this is intended to work
+ @s.rb_enc_left_char_head("a", 1).should == 1
+
+ # Works because for single-byte encodings rb_enc_left_char_head() just returns the pointer
+ @s.rb_enc_left_char_head("a".force_encoding(Encoding::US_ASCII), 88).should == 88
+ @s.rb_enc_left_char_head("a".b, 88).should == 88
+ end
+ end
+
describe "ONIGENC_MBC_CASE_FOLD" do
it "returns the correct case fold for the given string" do
@s.ONIGENC_MBC_CASE_FOLD("lower").should == ["l", 1]
@s.ONIGENC_MBC_CASE_FOLD("Upper").should == ["u", 1]
+ @s.ONIGENC_MBC_CASE_FOLD("ABC"[1..-1]).should == ["b", 1]
end
it "works with other encodings" do
@@ -642,4 +722,27 @@ describe "C-API Encoding function" do
str.bytes.should == [0, 0x24]
end
end
+
+ describe "rb_define_dummy_encoding" do
+ it "defines the dummy encoding" do
+ @s.rb_define_dummy_encoding("FOO")
+ enc = Encoding.find("FOO")
+ enc.should.dummy?
+ end
+
+ it "returns the index of the dummy encoding" do
+ index = @s.rb_define_dummy_encoding("BAR")
+ index.should == Encoding.list.size - 1
+ end
+
+ ruby_version_is "3.2" do
+ it "raises EncodingError if too many encodings" do
+ code = <<-RUBY
+ require #{extension_path.dump}
+ 1_000.times {|i| CApiEncodingSpecs.new.rb_define_dummy_encoding("R_\#{i}") }
+ RUBY
+ ruby_exe(code, args: "2>&1", exit_status: 1).should.include?('too many encoding (> 256) (EncodingError)')
+ end
+ end
+ end
end
diff --git a/spec/ruby/optional/capi/exception_spec.rb b/spec/ruby/optional/capi/exception_spec.rb
index b0a8a2860e..5bb60608b2 100644
--- a/spec/ruby/optional/capi/exception_spec.rb
+++ b/spec/ruby/optional/capi/exception_spec.rb
@@ -100,6 +100,40 @@ describe "C-API Exception function" do
end
end
+ describe "rb_syserr_new" do
+ it "returns system error with default message when passed message is NULL" do
+ exception = @s.rb_syserr_new(Errno::ENOENT::Errno, nil)
+ exception.class.should == Errno::ENOENT
+ exception.message.should include("No such file or directory")
+ exception.should.is_a?(SystemCallError)
+ end
+
+ it "returns system error with custom message" do
+ exception = @s.rb_syserr_new(Errno::ENOENT::Errno, "custom message")
+
+ exception.message.should include("custom message")
+ exception.class.should == Errno::ENOENT
+ exception.should.is_a?(SystemCallError)
+ end
+ end
+
+ describe "rb_syserr_new_str" do
+ it "returns system error with default message when passed message is nil" do
+ exception = @s.rb_syserr_new_str(Errno::ENOENT::Errno, nil)
+
+ exception.message.should include("No such file or directory")
+ exception.class.should == Errno::ENOENT
+ exception.should.is_a?(SystemCallError)
+ end
+
+ it "returns system error with custom message" do
+ exception = @s.rb_syserr_new_str(Errno::ENOENT::Errno, "custom message")
+ exception.message.should include("custom message")
+ exception.class.should == Errno::ENOENT
+ exception.should.is_a?(SystemCallError)
+ end
+ end
+
describe "rb_make_exception" do
it "returns a RuntimeError when given a String argument" do
e = @s.rb_make_exception(["Message"])
diff --git a/spec/ruby/optional/capi/ext/array_spec.c b/spec/ruby/optional/capi/ext/array_spec.c
index 9386239813..2347798bb4 100644
--- a/spec/ruby/optional/capi/ext/array_spec.c
+++ b/spec/ruby/optional/capi/ext/array_spec.c
@@ -196,6 +196,14 @@ static VALUE copy_ary(RB_BLOCK_CALL_FUNC_ARGLIST(el, new_ary)) {
return rb_ary_push(new_ary, el);
}
+static VALUE array_spec_rb_iterate(VALUE self, VALUE ary) {
+ VALUE new_ary = rb_ary_new();
+
+ rb_iterate(rb_each, ary, copy_ary, new_ary);
+
+ return new_ary;
+}
+
static VALUE array_spec_rb_block_call(VALUE self, VALUE ary) {
VALUE new_ary = rb_ary_new();
@@ -208,6 +216,18 @@ static VALUE sub_pair(RB_BLOCK_CALL_FUNC_ARGLIST(el, holder)) {
return rb_ary_push(holder, rb_ary_entry(el, 1));
}
+static VALUE each_pair(VALUE obj) {
+ return rb_funcall(obj, rb_intern("each_pair"), 0);
+}
+
+static VALUE array_spec_rb_iterate_each_pair(VALUE self, VALUE obj) {
+ VALUE new_ary = rb_ary_new();
+
+ rb_iterate(each_pair, obj, sub_pair, new_ary);
+
+ return new_ary;
+}
+
static VALUE array_spec_rb_block_call_each_pair(VALUE self, VALUE obj) {
VALUE new_ary = rb_ary_new();
@@ -221,6 +241,11 @@ static VALUE iter_yield(RB_BLOCK_CALL_FUNC_ARGLIST(el, ary)) {
return Qnil;
}
+static VALUE array_spec_rb_iterate_then_yield(VALUE self, VALUE obj) {
+ rb_iterate(rb_each, obj, iter_yield, obj);
+ return Qnil;
+}
+
static VALUE array_spec_rb_block_call_then_yield(VALUE self, VALUE obj) {
rb_block_call(obj, rb_intern("each"), 0, 0, iter_yield, obj);
return Qnil;
@@ -283,6 +308,9 @@ void Init_array_spec(void) {
rb_define_method(cls, "rb_ary_plus", array_spec_rb_ary_plus, 2);
rb_define_method(cls, "rb_ary_unshift", array_spec_rb_ary_unshift, 2);
rb_define_method(cls, "rb_assoc_new", array_spec_rb_assoc_new, 2);
+ rb_define_method(cls, "rb_iterate", array_spec_rb_iterate, 1);
+ rb_define_method(cls, "rb_iterate_each_pair", array_spec_rb_iterate_each_pair, 1);
+ rb_define_method(cls, "rb_iterate_then_yield", array_spec_rb_iterate_then_yield, 1);
rb_define_method(cls, "rb_block_call", array_spec_rb_block_call, 1);
rb_define_method(cls, "rb_block_call_each_pair", array_spec_rb_block_call_each_pair, 1);
rb_define_method(cls, "rb_block_call_then_yield", array_spec_rb_block_call_then_yield, 1);
diff --git a/spec/ruby/optional/capi/ext/class_spec.c b/spec/ruby/optional/capi/ext/class_spec.c
index 36b8c8f2f3..f376534924 100644
--- a/spec/ruby/optional/capi/ext/class_spec.c
+++ b/spec/ruby/optional/capi/ext/class_spec.c
@@ -61,21 +61,18 @@ static VALUE class_spec_rb_class_new(VALUE self, VALUE super) {
return rb_class_new(super);
}
-static VALUE class_spec_rb_class_new_instance(VALUE self,
- VALUE nargs, VALUE args,
- VALUE klass) {
- int c_nargs = FIX2INT(nargs);
- VALUE *c_args = (VALUE*)alloca(sizeof(VALUE) * c_nargs);
- int i;
-
- for (i = 0; i < c_nargs; i++)
- c_args[i] = rb_ary_entry(args, i);
+static VALUE class_spec_rb_class_new_instance(VALUE self, VALUE args, VALUE klass) {
+ return rb_class_new_instance(RARRAY_LENINT(args), RARRAY_PTR(args), klass);
+}
- return rb_class_new_instance(c_nargs, c_args, klass);
+#ifdef RUBY_VERSION_IS_3_0
+static VALUE class_spec_rb_class_new_instance_kw(VALUE self, VALUE args, VALUE klass) {
+ return rb_class_new_instance_kw(RARRAY_LENINT(args), RARRAY_PTR(args), klass, RB_PASS_KEYWORDS);
}
+#endif
static VALUE class_spec_rb_class_real(VALUE self, VALUE object) {
- if(rb_type_p(object, T_FIXNUM)) {
+ if (rb_type_p(object, T_FIXNUM)) {
return INT2FIX(rb_class_real(FIX2INT(object)));
} else {
return rb_class_real(CLASS_OF(object));
@@ -119,19 +116,19 @@ VALUE class_spec_define_attr(VALUE self, VALUE klass, VALUE sym, VALUE read, VAL
}
static VALUE class_spec_rb_define_class(VALUE self, VALUE name, VALUE super) {
- if(NIL_P(super)) super = 0;
+ if (NIL_P(super)) super = 0;
return rb_define_class(RSTRING_PTR(name), super);
}
static VALUE class_spec_rb_define_class_under(VALUE self, VALUE outer,
VALUE name, VALUE super) {
- if(NIL_P(super)) super = 0;
+ if (NIL_P(super)) super = 0;
return rb_define_class_under(outer, RSTRING_PTR(name), super);
}
static VALUE class_spec_rb_define_class_id_under(VALUE self, VALUE outer,
VALUE name, VALUE super) {
- if(NIL_P(super)) super = 0;
+ if (NIL_P(super)) super = 0;
return rb_define_class_id_under(outer, SYM2ID(name), super);
}
@@ -145,19 +142,6 @@ static VALUE class_spec_include_module(VALUE self, VALUE klass, VALUE module) {
return klass;
}
-static VALUE class_spec_method_var_args_1(int argc, VALUE *argv, VALUE self) {
- VALUE ary = rb_ary_new();
- int i;
- for (i = 0; i < argc; i++) {
- rb_ary_push(ary, argv[i]);
- }
- return ary;
-}
-
-static VALUE class_spec_method_var_args_2(VALUE self, VALUE argv) {
- return argv;
-}
-
void Init_class_spec(void) {
VALUE cls = rb_define_class("CApiClassSpecs", rb_cObject);
rb_define_method(cls, "define_call_super_method", class_spec_define_call_super_method, 2);
@@ -171,7 +155,10 @@ void Init_class_spec(void) {
rb_define_method(cls, "rb_class_protected_instance_methods", class_spec_rb_class_protected_instance_methods, -1);
rb_define_method(cls, "rb_class_private_instance_methods", class_spec_rb_class_private_instance_methods, -1);
rb_define_method(cls, "rb_class_new", class_spec_rb_class_new, 1);
- rb_define_method(cls, "rb_class_new_instance", class_spec_rb_class_new_instance, 3);
+ rb_define_method(cls, "rb_class_new_instance", class_spec_rb_class_new_instance, 2);
+#ifdef RUBY_VERSION_IS_3_0
+ rb_define_method(cls, "rb_class_new_instance_kw", class_spec_rb_class_new_instance_kw, 2);
+#endif
rb_define_method(cls, "rb_class_real", class_spec_rb_class_real, 1);
rb_define_method(cls, "rb_class_superclass", class_spec_rb_class_superclass, 1);
rb_define_method(cls, "rb_cvar_defined", class_spec_cvar_defined, 2);
@@ -185,8 +172,6 @@ void Init_class_spec(void) {
rb_define_method(cls, "rb_define_class_id_under", class_spec_rb_define_class_id_under, 3);
rb_define_method(cls, "rb_define_class_variable", class_spec_define_class_variable, 3);
rb_define_method(cls, "rb_include_module", class_spec_include_module, 2);
- rb_define_method(cls, "rb_method_varargs_1", class_spec_method_var_args_1, -1);
- rb_define_method(cls, "rb_method_varargs_2", class_spec_method_var_args_2, -2);
}
#ifdef __cplusplus
diff --git a/spec/ruby/optional/capi/ext/debug_spec.c b/spec/ruby/optional/capi/ext/debug_spec.c
index 344dfc33fa..9131eda78b 100644
--- a/spec/ruby/optional/capi/ext/debug_spec.c
+++ b/spec/ruby/optional/capi/ext/debug_spec.c
@@ -45,7 +45,7 @@ static VALUE rb_debug_inspector_frame_iseq_get_callback(const rb_debug_inspector
return rb_debug_inspector_frame_iseq_get(dc, NUM2LONG((VALUE) ptr));
}
-static VALUE debug_spec_callback_data(VALUE self){
+static VALUE debug_spec_callback_data(VALUE self) {
return callback_data;
}
diff --git a/spec/ruby/optional/capi/ext/encoding_spec.c b/spec/ruby/optional/capi/ext/encoding_spec.c
index cde4d0c351..aa8662cfbd 100644
--- a/spec/ruby/optional/capi/ext/encoding_spec.c
+++ b/spec/ruby/optional/capi/ext/encoding_spec.c
@@ -12,7 +12,7 @@ static VALUE encoding_spec_MBCLEN_CHARFOUND_P(VALUE self, VALUE obj) {
}
static VALUE encoding_spec_ENC_CODERANGE_ASCIIONLY(VALUE self, VALUE obj) {
- if(ENC_CODERANGE_ASCIIONLY(obj)) {
+ if (ENC_CODERANGE_ASCIIONLY(obj)) {
return Qtrue;
} else {
return Qfalse;
@@ -61,21 +61,19 @@ static VALUE encoding_spec_rb_filesystem_encindex(VALUE self) {
static VALUE encoding_spec_rb_default_internal_encoding(VALUE self) {
rb_encoding* enc = rb_default_internal_encoding();
- if(enc == 0) return Qnil;
+ if (enc == 0) return Qnil;
return rb_str_new2(enc->name);
}
static VALUE encoding_spec_rb_default_external_encoding(VALUE self) {
rb_encoding* enc = rb_default_external_encoding();
- if(enc == 0) return Qnil;
+ if (enc == 0) return Qnil;
return rb_str_new2(enc->name);
}
-#ifdef RUBY_VERSION_IS_2_6
static VALUE encoding_spec_rb_enc_alias(VALUE self, VALUE alias, VALUE orig) {
return INT2NUM(rb_enc_alias(RSTRING_PTR(alias), RSTRING_PTR(orig)));
}
-#endif
static VALUE encoding_spec_rb_enc_associate(VALUE self, VALUE obj, VALUE enc) {
return rb_enc_associate(obj, NIL_P(enc) ? NULL : rb_enc_find(RSTRING_PTR(enc)));
@@ -88,7 +86,7 @@ static VALUE encoding_spec_rb_enc_associate_index(VALUE self, VALUE obj, VALUE i
static VALUE encoding_spec_rb_enc_compatible(VALUE self, VALUE a, VALUE b) {
rb_encoding* enc = rb_enc_compatible(a, b);
- if(!enc) return INT2FIX(0);
+ if (!enc) return INT2FIX(0);
return rb_enc_from_encoding(enc);
}
@@ -120,10 +118,9 @@ static VALUE encoding_spec_rb_enc_from_index(VALUE self, VALUE index) {
return rb_str_new2(rb_enc_from_index(NUM2INT(index))->name);
}
-static VALUE encoding_spec_rb_enc_mbc_to_codepoint(VALUE self, VALUE str, VALUE offset) {
- int o = FIX2INT(offset);
+static VALUE encoding_spec_rb_enc_mbc_to_codepoint(VALUE self, VALUE str) {
char *p = RSTRING_PTR(str);
- char *e = p + o;
+ char *e = RSTRING_END(str);
return INT2FIX(rb_enc_mbc_to_codepoint(p, e, rb_enc_get(str)));
}
@@ -274,8 +271,17 @@ static VALUE encoding_spec_rb_enc_str_asciionly_p(VALUE self, VALUE str) {
}
}
+static VALUE encoding_spec_rb_enc_raise(VALUE self, VALUE encoding, VALUE exception_class, VALUE format) {
+ rb_encoding *e = rb_to_encoding(encoding);
+ const char *f = RSTRING_PTR(format);
+
+ rb_enc_raise(e, exception_class, "%s", f);
+}
+
static VALUE encoding_spec_rb_uv_to_utf8(VALUE self, VALUE buf, VALUE num) {
- return INT2NUM(rb_uv_to_utf8(RSTRING_PTR(buf), NUM2INT(num)));
+ int len = rb_uv_to_utf8(RSTRING_PTR(buf), NUM2INT(num));
+ RB_ENC_CODERANGE_CLEAR(buf);
+ return INT2NUM(len);
}
static VALUE encoding_spec_ONIGENC_MBC_CASE_FOLD(VALUE self, VALUE str) {
@@ -300,6 +306,24 @@ static VALUE encoding_spec_rb_enc_codelen(VALUE self, VALUE code, VALUE encoding
return INT2FIX(rb_enc_codelen(c, enc));
}
+static VALUE encoding_spec_rb_enc_strlen(VALUE self, VALUE str, VALUE length, VALUE encoding) {
+ int l = FIX2INT(length);
+ char *p = RSTRING_PTR(str);
+ char *e = p + l;
+
+ return LONG2FIX(rb_enc_strlen(p, e, rb_to_encoding(encoding)));
+}
+
+static VALUE encoding_spec_rb_enc_left_char_head(VALUE self, VALUE str, VALUE offset) {
+ char *ptr = RSTRING_PTR(str);
+ char *result = rb_enc_left_char_head(ptr, ptr + NUM2INT(offset), RSTRING_END(str), rb_enc_get(str));
+ return LONG2NUM(result - ptr);
+}
+
+static VALUE encoding_spec_rb_define_dummy_encoding(VALUE self, VALUE name) {
+ return INT2NUM(rb_define_dummy_encoding(RSTRING_PTR(name)));
+}
+
void Init_encoding_spec(void) {
VALUE cls;
native_rb_encoding_pointer = (rb_encoding**) malloc(sizeof(rb_encoding*));
@@ -318,28 +342,22 @@ void Init_encoding_spec(void) {
rb_define_method(cls, "rb_locale_encindex", encoding_spec_rb_locale_encindex, 0);
rb_define_method(cls, "rb_filesystem_encoding", encoding_spec_rb_filesystem_encoding, 0);
rb_define_method(cls, "rb_filesystem_encindex", encoding_spec_rb_filesystem_encindex, 0);
- rb_define_method(cls, "rb_default_internal_encoding",
- encoding_spec_rb_default_internal_encoding, 0);
-
- rb_define_method(cls, "rb_default_external_encoding",
- encoding_spec_rb_default_external_encoding, 0);
-
-#ifdef RUBY_VERSION_IS_2_6
+ rb_define_method(cls, "rb_default_internal_encoding", encoding_spec_rb_default_internal_encoding, 0);
+ rb_define_method(cls, "rb_default_external_encoding", encoding_spec_rb_default_external_encoding, 0);
rb_define_method(cls, "rb_enc_alias", encoding_spec_rb_enc_alias, 2);
-#endif
-
rb_define_method(cls, "MBCLEN_CHARFOUND_P", encoding_spec_MBCLEN_CHARFOUND_P, 1);
rb_define_method(cls, "rb_enc_associate", encoding_spec_rb_enc_associate, 2);
rb_define_method(cls, "rb_enc_associate_index", encoding_spec_rb_enc_associate_index, 2);
rb_define_method(cls, "rb_enc_compatible", encoding_spec_rb_enc_compatible, 2);
rb_define_method(cls, "rb_enc_copy", encoding_spec_rb_enc_copy, 2);
rb_define_method(cls, "rb_enc_codelen", encoding_spec_rb_enc_codelen, 2);
+ rb_define_method(cls, "rb_enc_strlen", encoding_spec_rb_enc_strlen, 3);
rb_define_method(cls, "rb_enc_find", encoding_spec_rb_enc_find, 1);
rb_define_method(cls, "rb_enc_find_index", encoding_spec_rb_enc_find_index, 1);
rb_define_method(cls, "rb_enc_isalnum", encoding_spec_rb_enc_isalnum, 2);
rb_define_method(cls, "rb_enc_isspace", encoding_spec_rb_enc_isspace, 2);
rb_define_method(cls, "rb_enc_from_index", encoding_spec_rb_enc_from_index, 1);
- rb_define_method(cls, "rb_enc_mbc_to_codepoint", encoding_spec_rb_enc_mbc_to_codepoint, 2);
+ rb_define_method(cls, "rb_enc_mbc_to_codepoint", encoding_spec_rb_enc_mbc_to_codepoint, 1);
rb_define_method(cls, "rb_enc_mbcput", encoding_spec_rb_enc_mbcput, 2);
rb_define_method(cls, "rb_enc_from_encoding", encoding_spec_rb_enc_from_encoding, 1);
rb_define_method(cls, "rb_enc_get", encoding_spec_rb_enc_get, 1);
@@ -361,8 +379,11 @@ void Init_encoding_spec(void) {
rb_define_method(cls, "rb_enc_nth", encoding_spec_rb_enc_nth, 2);
rb_define_method(cls, "rb_enc_codepoint_len", encoding_spec_rb_enc_codepoint_len, 1);
rb_define_method(cls, "rb_enc_str_asciionly_p", encoding_spec_rb_enc_str_asciionly_p, 1);
+ rb_define_method(cls, "rb_enc_raise", encoding_spec_rb_enc_raise, 3);
rb_define_method(cls, "rb_uv_to_utf8", encoding_spec_rb_uv_to_utf8, 2);
rb_define_method(cls, "ONIGENC_MBC_CASE_FOLD", encoding_spec_ONIGENC_MBC_CASE_FOLD, 1);
+ rb_define_method(cls, "rb_enc_left_char_head", encoding_spec_rb_enc_left_char_head, 2);
+ rb_define_method(cls, "rb_define_dummy_encoding", encoding_spec_rb_define_dummy_encoding, 1);
}
#ifdef __cplusplus
diff --git a/spec/ruby/optional/capi/ext/exception_spec.c b/spec/ruby/optional/capi/ext/exception_spec.c
index e1114aabb8..0e8347ab0d 100644
--- a/spec/ruby/optional/capi/ext/exception_spec.c
+++ b/spec/ruby/optional/capi/ext/exception_spec.c
@@ -27,7 +27,7 @@ VALUE exception_spec_rb_exc_new3(VALUE self, VALUE str) {
}
VALUE exception_spec_rb_exc_raise(VALUE self, VALUE exc) {
- if (self != Qundef) rb_exc_raise(exc);
+ if (self != Qundef) rb_exc_raise(exc);
return Qnil;
}
@@ -36,6 +36,21 @@ VALUE exception_spec_rb_set_errinfo(VALUE self, VALUE exc) {
return Qnil;
}
+VALUE exception_spec_rb_syserr_new(VALUE self, VALUE num, VALUE msg) {
+ int n = NUM2INT(num);
+ char *cstr = NULL;
+
+ if (msg != Qnil) {
+ cstr = StringValuePtr(msg);
+ }
+
+ return rb_syserr_new(n, cstr);
+}
+
+VALUE exception_spec_rb_syserr_new_str(VALUE self, VALUE num, VALUE msg) {
+ int n = NUM2INT(num);
+ return rb_syserr_new_str(n, msg);
+}
VALUE exception_spec_rb_make_exception(VALUE self, VALUE ary) {
int argc = RARRAY_LENINT(ary);
@@ -51,6 +66,8 @@ void Init_exception_spec(void) {
rb_define_method(cls, "rb_exc_new3", exception_spec_rb_exc_new3, 1);
rb_define_method(cls, "rb_exc_raise", exception_spec_rb_exc_raise, 1);
rb_define_method(cls, "rb_set_errinfo", exception_spec_rb_set_errinfo, 1);
+ rb_define_method(cls, "rb_syserr_new", exception_spec_rb_syserr_new, 2);
+ rb_define_method(cls, "rb_syserr_new_str", exception_spec_rb_syserr_new_str, 2);
rb_define_method(cls, "rb_make_exception", exception_spec_rb_make_exception, 1);
}
diff --git a/spec/ruby/optional/capi/ext/gc_spec.c b/spec/ruby/optional/capi/ext/gc_spec.c
index 7dc9c347c7..1392bc6ee6 100644
--- a/spec/ruby/optional/capi/ext/gc_spec.c
+++ b/spec/ruby/optional/capi/ext/gc_spec.c
@@ -7,6 +7,14 @@ extern "C" {
VALUE registered_tagged_value;
VALUE registered_reference_value;
+VALUE registered_before_rb_gc_register_address;
+VALUE registered_before_rb_global_variable_string;
+VALUE registered_before_rb_global_variable_bignum;
+VALUE registered_before_rb_global_variable_float;
+VALUE registered_after_rb_global_variable_string;
+VALUE registered_after_rb_global_variable_bignum;
+VALUE registered_after_rb_global_variable_float;
+VALUE rb_gc_register_address_outside_init;
static VALUE registered_tagged_address(VALUE self) {
return registered_tagged_value;
@@ -16,6 +24,45 @@ static VALUE registered_reference_address(VALUE self) {
return registered_reference_value;
}
+static VALUE get_registered_before_rb_gc_register_address(VALUE self) {
+ return registered_before_rb_gc_register_address;
+}
+
+static VALUE get_registered_before_rb_global_variable_string(VALUE self) {
+ return registered_before_rb_global_variable_string;
+}
+
+static VALUE get_registered_before_rb_global_variable_bignum(VALUE self) {
+ return registered_before_rb_global_variable_bignum;
+}
+
+static VALUE get_registered_before_rb_global_variable_float(VALUE self) {
+ return registered_before_rb_global_variable_float;
+}
+
+static VALUE get_registered_after_rb_global_variable_string(VALUE self) {
+ return registered_after_rb_global_variable_string;
+}
+
+static VALUE get_registered_after_rb_global_variable_bignum(VALUE self) {
+ return registered_after_rb_global_variable_bignum;
+}
+
+static VALUE get_registered_after_rb_global_variable_float(VALUE self) {
+ return registered_after_rb_global_variable_float;
+}
+
+static VALUE gc_spec_rb_gc_register_address(VALUE self) {
+ rb_gc_register_address(&rb_gc_register_address_outside_init);
+ rb_gc_register_address_outside_init = rb_str_new_cstr("rb_gc_register_address() outside Init_");
+ return rb_gc_register_address_outside_init;
+}
+
+static VALUE gc_spec_rb_gc_unregister_address(VALUE self) {
+ rb_gc_unregister_address(&rb_gc_register_address_outside_init);
+ return Qnil;
+}
+
static VALUE gc_spec_rb_gc_enable(VALUE self) {
return rb_gc_enable();
}
@@ -29,7 +76,7 @@ static VALUE gc_spec_rb_gc(VALUE self) {
return Qnil;
}
-static VALUE gc_spec_rb_gc_latest_gc_info(VALUE self, VALUE hash_or_key){
+static VALUE gc_spec_rb_gc_latest_gc_info(VALUE self, VALUE hash_or_key) {
return rb_gc_latest_gc_info(hash_or_key);
}
@@ -45,14 +92,40 @@ static VALUE gc_spec_rb_gc_register_mark_object(VALUE self, VALUE obj) {
void Init_gc_spec(void) {
VALUE cls = rb_define_class("CApiGCSpecs", rb_cObject);
- registered_tagged_value = INT2NUM(10);
- registered_reference_value = rb_str_new2("Globally registered data");
rb_gc_register_address(&registered_tagged_value);
rb_gc_register_address(&registered_reference_value);
+ rb_gc_register_address(&registered_before_rb_gc_register_address);
+ rb_global_variable(&registered_before_rb_global_variable_string);
+ rb_global_variable(&registered_before_rb_global_variable_bignum);
+ rb_global_variable(&registered_before_rb_global_variable_float);
+
+ registered_tagged_value = INT2NUM(10);
+ registered_reference_value = rb_str_new2("Globally registered data");
+ registered_before_rb_gc_register_address = rb_str_new_cstr("registered before rb_gc_register_address()");
+
+ registered_before_rb_global_variable_string = rb_str_new_cstr("registered before rb_global_variable()");
+ registered_before_rb_global_variable_bignum = LL2NUM(INT64_MAX);
+ registered_before_rb_global_variable_float = DBL2NUM(3.14);
+
+ registered_after_rb_global_variable_string = rb_str_new_cstr("registered after rb_global_variable()");
+ rb_global_variable(&registered_after_rb_global_variable_string);
+ registered_after_rb_global_variable_bignum = LL2NUM(INT64_MAX);
+ rb_global_variable(&registered_after_rb_global_variable_bignum);
+ registered_after_rb_global_variable_float = DBL2NUM(6.28);
+ rb_global_variable(&registered_after_rb_global_variable_float);
rb_define_method(cls, "registered_tagged_address", registered_tagged_address, 0);
rb_define_method(cls, "registered_reference_address", registered_reference_address, 0);
+ rb_define_method(cls, "registered_before_rb_gc_register_address", get_registered_before_rb_gc_register_address, 0);
+ rb_define_method(cls, "registered_before_rb_global_variable_string", get_registered_before_rb_global_variable_string, 0);
+ rb_define_method(cls, "registered_before_rb_global_variable_bignum", get_registered_before_rb_global_variable_bignum, 0);
+ rb_define_method(cls, "registered_before_rb_global_variable_float", get_registered_before_rb_global_variable_float, 0);
+ rb_define_method(cls, "registered_after_rb_global_variable_string", get_registered_after_rb_global_variable_string, 0);
+ rb_define_method(cls, "registered_after_rb_global_variable_bignum", get_registered_after_rb_global_variable_bignum, 0);
+ rb_define_method(cls, "registered_after_rb_global_variable_float", get_registered_after_rb_global_variable_float, 0);
+ rb_define_method(cls, "rb_gc_register_address", gc_spec_rb_gc_register_address, 0);
+ rb_define_method(cls, "rb_gc_unregister_address", gc_spec_rb_gc_unregister_address, 0);
rb_define_method(cls, "rb_gc_enable", gc_spec_rb_gc_enable, 0);
rb_define_method(cls, "rb_gc_disable", gc_spec_rb_gc_disable, 0);
rb_define_method(cls, "rb_gc", gc_spec_rb_gc, 0);
diff --git a/spec/ruby/optional/capi/ext/globals_spec.c b/spec/ruby/optional/capi/ext/globals_spec.c
index 28a9633f98..20dea1a05a 100644
--- a/spec/ruby/optional/capi/ext/globals_spec.c
+++ b/spec/ruby/optional/capi/ext/globals_spec.c
@@ -20,6 +20,16 @@ static VALUE sb_define_hooked_variable(VALUE self, VALUE var_name) {
return Qnil;
}
+static VALUE sb_define_hooked_variable_default_accessors(VALUE self, VALUE var_name) {
+ rb_define_hooked_variable(StringValuePtr(var_name), &g_hooked_var, (rb_gvar_getter_t*) NULL, (rb_gvar_setter_t*) NULL);
+ return Qnil;
+}
+
+static VALUE sb_define_hooked_variable_null_var(VALUE self, VALUE var_name) {
+ rb_define_hooked_variable(StringValuePtr(var_name), NULL, (rb_gvar_getter_t*) NULL, (rb_gvar_setter_t*) NULL);
+ return Qnil;
+}
+
VALUE g_ro_var;
static VALUE sb_define_readonly_variable(VALUE self, VALUE var_name, VALUE val) {
@@ -40,6 +50,26 @@ static VALUE sb_define_variable(VALUE self, VALUE var_name, VALUE val) {
return Qnil;
}
+long virtual_var_storage;
+
+VALUE incrementing_getter(ID id, VALUE *data) {
+ return LONG2FIX(virtual_var_storage++);
+}
+
+void incrementing_setter(VALUE val, ID id, VALUE *data) {
+ virtual_var_storage = FIX2LONG(val);
+}
+
+static VALUE sb_define_virtual_variable_default_accessors(VALUE self, VALUE name) {
+ rb_define_virtual_variable(StringValuePtr(name), (rb_gvar_getter_t*) NULL, (rb_gvar_setter_t*) NULL);
+ return Qnil;
+}
+
+static VALUE sb_define_virtual_variable_incrementing_accessors(VALUE self, VALUE name) {
+ rb_define_virtual_variable(StringValuePtr(name), incrementing_getter, incrementing_setter);
+ return Qnil;
+}
+
static VALUE sb_f_global_variables(VALUE self) {
return rb_f_global_variables();
}
@@ -101,10 +131,14 @@ void Init_globals_spec(void) {
VALUE cls = rb_define_class("CApiGlobalSpecs", rb_cObject);
g_hooked_var = Qnil;
rb_define_method(cls, "rb_define_hooked_variable_2x", sb_define_hooked_variable, 1);
+ rb_define_method(cls, "rb_define_hooked_variable_default_accessors", sb_define_hooked_variable_default_accessors, 1);
+ rb_define_method(cls, "rb_define_hooked_variable_null_var", sb_define_hooked_variable_null_var, 1);
g_ro_var = Qnil;
rb_define_method(cls, "rb_define_readonly_variable", sb_define_readonly_variable, 2);
g_var = Qnil;
rb_define_method(cls, "rb_define_variable", sb_define_variable, 2);
+ rb_define_method(cls, "rb_define_virtual_variable_default_accessors", sb_define_virtual_variable_default_accessors, 1);
+ rb_define_method(cls, "rb_define_virtual_variable_incrementing_accessors", sb_define_virtual_variable_incrementing_accessors, 1);
rb_define_method(cls, "sb_get_global_value", sb_get_global_value, 0);
rb_define_method(cls, "rb_f_global_variables", sb_f_global_variables, 0);
rb_define_method(cls, "sb_gv_get", sb_gv_get, 1);
diff --git a/spec/ruby/optional/capi/ext/hash_spec.c b/spec/ruby/optional/capi/ext/hash_spec.c
index 7f38708915..69ef02d5da 100644
--- a/spec/ruby/optional/capi/ext/hash_spec.c
+++ b/spec/ruby/optional/capi/ext/hash_spec.c
@@ -105,6 +105,12 @@ VALUE hash_spec_rb_hash_new(VALUE self) {
return rb_hash_new();
}
+#ifdef RUBY_VERSION_IS_3_2
+VALUE hash_spec_rb_hash_new_capa(VALUE self, VALUE capacity) {
+ return rb_hash_new_capa(NUM2LONG(capacity));
+}
+#endif
+
VALUE rb_ident_hash_new(void); /* internal.h, used in ripper */
VALUE hash_spec_rb_ident_hash_new(VALUE self) {
@@ -149,6 +155,9 @@ void Init_hash_spec(void) {
rb_define_method(cls, "rb_hash_lookup2", hash_spec_rb_hash_lookup2, 3);
rb_define_method(cls, "rb_hash_lookup2_default_undef", hash_spec_rb_hash_lookup2_default_undef, 2);
rb_define_method(cls, "rb_hash_new", hash_spec_rb_hash_new, 0);
+#ifdef RUBY_VERSION_IS_3_2
+ rb_define_method(cls, "rb_hash_new_capa", hash_spec_rb_hash_new_capa, 1);
+#endif
rb_define_method(cls, "rb_ident_hash_new", hash_spec_rb_ident_hash_new, 0);
rb_define_method(cls, "rb_hash_size", hash_spec_rb_hash_size, 1);
rb_define_method(cls, "rb_hash_set_ifnone", hash_spec_rb_hash_set_ifnone, 2);
diff --git a/spec/ruby/optional/capi/ext/integer_spec.c b/spec/ruby/optional/capi/ext/integer_spec.c
index 16cd95f111..792fc0652a 100644
--- a/spec/ruby/optional/capi/ext/integer_spec.c
+++ b/spec/ruby/optional/capi/ext/integer_spec.c
@@ -6,8 +6,7 @@ extern "C" {
#endif
static VALUE integer_spec_rb_integer_pack(VALUE self, VALUE value,
- VALUE words, VALUE numwords, VALUE wordsize, VALUE nails, VALUE flags)
-{
+ VALUE words, VALUE numwords, VALUE wordsize, VALUE nails, VALUE flags) {
int result = rb_integer_pack(value, (void*)RSTRING_PTR(words), FIX2INT(numwords),
FIX2INT(wordsize), FIX2INT(nails), FIX2INT(flags));
return INT2FIX(result);
@@ -15,7 +14,7 @@ static VALUE integer_spec_rb_integer_pack(VALUE self, VALUE value,
RUBY_EXTERN VALUE rb_int_positive_pow(long x, unsigned long y); /* internal.h, used in ripper */
-static VALUE integer_spec_rb_int_positive_pow(VALUE self, VALUE a, VALUE b){
+static VALUE integer_spec_rb_int_positive_pow(VALUE self, VALUE a, VALUE b) {
return rb_int_positive_pow(FIX2INT(a), FIX2INT(b));
}
diff --git a/spec/ruby/optional/capi/ext/io_spec.c b/spec/ruby/optional/capi/ext/io_spec.c
index b4ffe9207a..bcd3940e34 100644
--- a/spec/ruby/optional/capi/ext/io_spec.c
+++ b/spec/ruby/optional/capi/ext/io_spec.c
@@ -28,9 +28,13 @@ static int set_non_blocking(int fd) {
}
static int io_spec_get_fd(VALUE io) {
+#ifdef RUBY_VERSION_IS_3_1
+ return rb_io_descriptor(io);
+#else
rb_io_t* fp;
GetOpenFile(io, fp);
return fp->fd;
+#endif
}
VALUE io_spec_GetOpenFile_fd(VALUE self, VALUE io) {
@@ -130,7 +134,7 @@ VALUE io_spec_rb_io_wait_readable(VALUE self, VALUE io, VALUE read_p) {
rb_sys_fail("set_non_blocking failed");
#ifndef SET_NON_BLOCKING_FAILS_ALWAYS
- if(RTEST(read_p)) {
+ if (RTEST(read_p)) {
if (read(fd, buf, RB_IO_WAIT_READABLE_BUF) != -1) {
return Qnil;
}
@@ -141,7 +145,7 @@ VALUE io_spec_rb_io_wait_readable(VALUE self, VALUE io, VALUE read_p) {
ret = rb_io_wait_readable(fd);
- if(RTEST(read_p)) {
+ if (RTEST(read_p)) {
ssize_t r = read(fd, buf, RB_IO_WAIT_READABLE_BUF);
if (r != RB_IO_WAIT_READABLE_BUF) {
perror("read");
@@ -162,6 +166,60 @@ VALUE io_spec_rb_io_wait_writable(VALUE self, VALUE io) {
return ret ? Qtrue : Qfalse;
}
+#ifdef RUBY_VERSION_IS_3_1
+VALUE io_spec_rb_io_maybe_wait_writable(VALUE self, VALUE error, VALUE io, VALUE timeout) {
+ int ret = rb_io_maybe_wait_writable(NUM2INT(error), io, timeout);
+ return INT2NUM(ret);
+}
+#endif
+
+#ifdef RUBY_VERSION_IS_3_1
+VALUE io_spec_rb_io_maybe_wait_readable(VALUE self, VALUE error, VALUE io, VALUE timeout, VALUE read_p) {
+ int fd = io_spec_get_fd(io);
+#ifndef SET_NON_BLOCKING_FAILS_ALWAYS
+ char buf[RB_IO_WAIT_READABLE_BUF];
+ int ret, saved_errno;
+#endif
+
+ if (set_non_blocking(fd) == -1)
+ rb_sys_fail("set_non_blocking failed");
+
+#ifndef SET_NON_BLOCKING_FAILS_ALWAYS
+ if (RTEST(read_p)) {
+ if (read(fd, buf, RB_IO_WAIT_READABLE_BUF) != -1) {
+ return Qnil;
+ }
+ saved_errno = errno;
+ rb_ivar_set(self, rb_intern("@write_data"), Qtrue);
+ errno = saved_errno;
+ }
+
+ // main part
+ ret = rb_io_maybe_wait_readable(NUM2INT(error), io, timeout);
+
+ if (RTEST(read_p)) {
+ ssize_t r = read(fd, buf, RB_IO_WAIT_READABLE_BUF);
+ if (r != RB_IO_WAIT_READABLE_BUF) {
+ perror("read");
+ return SSIZET2NUM(r);
+ }
+ rb_ivar_set(self, rb_intern("@read_data"),
+ rb_str_new(buf, RB_IO_WAIT_READABLE_BUF));
+ }
+
+ return INT2NUM(ret);
+#else
+ UNREACHABLE;
+#endif
+}
+#endif
+
+#ifdef RUBY_VERSION_IS_3_1
+VALUE io_spec_rb_io_maybe_wait(VALUE self, VALUE error, VALUE io, VALUE events, VALUE timeout) {
+ return rb_io_maybe_wait(NUM2INT(error), io, events, timeout);
+}
+#endif
+
VALUE io_spec_rb_thread_wait_fd(VALUE self, VALUE io) {
rb_thread_wait_fd(io_spec_get_fd(io));
return Qnil;
@@ -182,6 +240,46 @@ VALUE io_spec_rb_thread_fd_writable(VALUE self, VALUE io) {
return Qnil;
}
+VALUE io_spec_rb_thread_fd_select_read(VALUE self, VALUE io) {
+ int fd = io_spec_get_fd(io);
+
+ rb_fdset_t fds;
+ rb_fd_init(&fds);
+ rb_fd_set(fd, &fds);
+
+ int r = rb_thread_fd_select(fd + 1, &fds, NULL, NULL, NULL);
+ rb_fd_term(&fds);
+ return INT2FIX(r);
+}
+
+VALUE io_spec_rb_thread_fd_select_write(VALUE self, VALUE io) {
+ int fd = io_spec_get_fd(io);
+
+ rb_fdset_t fds;
+ rb_fd_init(&fds);
+ rb_fd_set(fd, &fds);
+
+ int r = rb_thread_fd_select(fd + 1, NULL, &fds, NULL, NULL);
+ rb_fd_term(&fds);
+ return INT2FIX(r);
+}
+
+VALUE io_spec_rb_thread_fd_select_timeout(VALUE self, VALUE io) {
+ int fd = io_spec_get_fd(io);
+
+ struct timeval timeout;
+ timeout.tv_sec = 10;
+ timeout.tv_usec = 20;
+
+ rb_fdset_t fds;
+ rb_fd_init(&fds);
+ rb_fd_set(fd, &fds);
+
+ int r = rb_thread_fd_select(fd + 1, NULL, &fds, NULL, &timeout);
+ rb_fd_term(&fds);
+ return INT2FIX(r);
+}
+
VALUE io_spec_rb_io_binmode(VALUE self, VALUE io) {
return rb_io_binmode(io);
}
@@ -209,7 +307,7 @@ VALUE io_spec_rb_io_set_nonblock(VALUE self, VALUE io) {
GetOpenFile(io, fp);
rb_io_set_nonblock(fp);
#ifdef F_GETFL
- flags = fcntl(fp->fd, F_GETFL, 0);
+ flags = fcntl(io_spec_get_fd(io), F_GETFL, 0);
return flags & O_NONBLOCK ? Qtrue : Qfalse;
#else
return Qfalse;
@@ -228,15 +326,29 @@ static VALUE io_spec_errno_set(VALUE self, VALUE val) {
}
VALUE io_spec_mode_sync_flag(VALUE self, VALUE io) {
+#ifdef RUBY_VERSION_IS_3_3
+ if (rb_io_mode(io) & FMODE_SYNC) {
+#else
rb_io_t *fp;
GetOpenFile(io, fp);
if (fp->mode & FMODE_SYNC) {
+#endif
return Qtrue;
} else {
return Qfalse;
}
}
+#if defined(RUBY_VERSION_IS_3_3) || defined(TRUFFLERUBY)
+static VALUE io_spec_rb_io_mode(VALUE self, VALUE io) {
+ return INT2FIX(rb_io_mode(io));
+}
+
+static VALUE io_spec_rb_io_path(VALUE self, VALUE io) {
+ return rb_io_path(io);
+}
+#endif
+
void Init_io_spec(void) {
VALUE cls = rb_define_class("CApiIOSpecs", rb_cObject);
rb_define_method(cls, "GetOpenFile_fd", io_spec_GetOpenFile_fd, 1);
@@ -254,14 +366,26 @@ void Init_io_spec(void) {
rb_define_method(cls, "rb_io_taint_check", io_spec_rb_io_taint_check, 1);
rb_define_method(cls, "rb_io_wait_readable", io_spec_rb_io_wait_readable, 2);
rb_define_method(cls, "rb_io_wait_writable", io_spec_rb_io_wait_writable, 1);
+#ifdef RUBY_VERSION_IS_3_1
+ rb_define_method(cls, "rb_io_maybe_wait_writable", io_spec_rb_io_maybe_wait_writable, 3);
+ rb_define_method(cls, "rb_io_maybe_wait_readable", io_spec_rb_io_maybe_wait_readable, 4);
+ rb_define_method(cls, "rb_io_maybe_wait", io_spec_rb_io_maybe_wait, 4);
+#endif
rb_define_method(cls, "rb_thread_wait_fd", io_spec_rb_thread_wait_fd, 1);
rb_define_method(cls, "rb_thread_fd_writable", io_spec_rb_thread_fd_writable, 1);
+ rb_define_method(cls, "rb_thread_fd_select_read", io_spec_rb_thread_fd_select_read, 1);
+ rb_define_method(cls, "rb_thread_fd_select_write", io_spec_rb_thread_fd_select_write, 1);
+ rb_define_method(cls, "rb_thread_fd_select_timeout", io_spec_rb_thread_fd_select_timeout, 1);
rb_define_method(cls, "rb_wait_for_single_fd", io_spec_rb_wait_for_single_fd, 4);
rb_define_method(cls, "rb_io_binmode", io_spec_rb_io_binmode, 1);
rb_define_method(cls, "rb_fd_fix_cloexec", io_spec_rb_fd_fix_cloexec, 1);
rb_define_method(cls, "rb_cloexec_open", io_spec_rb_cloexec_open, 3);
rb_define_method(cls, "errno=", io_spec_errno_set, 1);
rb_define_method(cls, "rb_io_mode_sync_flag", io_spec_mode_sync_flag, 1);
+#if defined(RUBY_VERSION_IS_3_3) || defined(TRUFFLERUBY)
+ rb_define_method(cls, "rb_io_mode", io_spec_rb_io_mode, 1);
+ rb_define_method(cls, "rb_io_path", io_spec_rb_io_path, 1);
+#endif
}
#ifdef __cplusplus
diff --git a/spec/ruby/optional/capi/ext/kernel_spec.c b/spec/ruby/optional/capi/ext/kernel_spec.c
index bbfeb198b7..1761599081 100644
--- a/spec/ruby/optional/capi/ext/kernel_spec.c
+++ b/spec/ruby/optional/capi/ext/kernel_spec.c
@@ -112,6 +112,10 @@ VALUE kernel_spec_rb_eval_string(VALUE self, VALUE str) {
return rb_eval_string(RSTRING_PTR(str));
}
+VALUE kernel_spec_rb_eval_cmd_kw(VALUE self, VALUE cmd, VALUE args, VALUE kw_splat) {
+ return rb_eval_cmd_kw(cmd, args, NUM2INT(kw_splat));
+}
+
VALUE kernel_spec_rb_raise(VALUE self, VALUE hash) {
rb_hash_aset(hash, ID2SYM(rb_intern("stage")), ID2SYM(rb_intern("before")));
if (self != Qundef)
@@ -142,7 +146,7 @@ VALUE kernel_spec_call_proc_with_raised_exc(VALUE arg_array, VALUE raised_exc) {
argc = 2;
- return rb_funcall2(proc, rb_intern("call"), argc, argv);
+ return rb_funcallv(proc, rb_intern("call"), argc, argv);
}
VALUE kernel_spec_rb_rescue(VALUE self, VALUE main_proc, VALUE arg,
@@ -216,7 +220,7 @@ static VALUE kernel_spec_rb_eval_string_protect(VALUE self, VALUE str, VALUE ary
VALUE kernel_spec_rb_sys_fail(VALUE self, VALUE msg) {
errno = 1;
- if(msg == Qnil) {
+ if (msg == Qnil) {
rb_sys_fail(0);
} else if (self != Qundef) {
rb_sys_fail(StringValuePtr(msg));
@@ -225,7 +229,7 @@ VALUE kernel_spec_rb_sys_fail(VALUE self, VALUE msg) {
}
VALUE kernel_spec_rb_syserr_fail(VALUE self, VALUE err, VALUE msg) {
- if(msg == Qnil) {
+ if (msg == Qnil) {
rb_syserr_fail(NUM2INT(err), NULL);
} else if (self != Qundef) {
rb_syserr_fail(NUM2INT(err), StringValuePtr(msg));
@@ -288,9 +292,9 @@ static VALUE kernel_spec_rb_yield_values2(VALUE self, VALUE ary) {
}
static VALUE do_rec(VALUE obj, VALUE arg, int is_rec) {
- if(is_rec) {
+ if (is_rec) {
return obj;
- } else if(arg == Qtrue) {
+ } else if (arg == Qtrue) {
return rb_exec_recursive(do_rec, obj, Qnil);
} else {
return Qnil;
@@ -318,12 +322,30 @@ static VALUE kernel_spec_rb_make_backtrace(VALUE self) {
return rb_make_backtrace();
}
-static VALUE kernel_spec_rb_funcall3(VALUE self, VALUE obj, VALUE method) {
- return rb_funcall3(obj, SYM2ID(method), 0, NULL);
+static VALUE kernel_spec_rb_funcallv(VALUE self, VALUE obj, VALUE method, VALUE args) {
+ return rb_funcallv(obj, SYM2ID(method), RARRAY_LENINT(args), RARRAY_PTR(args));
+}
+
+#ifdef RUBY_VERSION_IS_3_0
+static VALUE kernel_spec_rb_funcallv_kw(VALUE self, VALUE obj, VALUE method, VALUE args) {
+ return rb_funcallv_kw(obj, SYM2ID(method), RARRAY_LENINT(args), RARRAY_PTR(args), RB_PASS_KEYWORDS);
+}
+
+static VALUE kernel_spec_rb_keyword_given_p(int argc, VALUE *args, VALUE self) {
+ return rb_keyword_given_p() ? Qtrue : Qfalse;
+}
+#endif
+
+static VALUE kernel_spec_rb_funcallv_public(VALUE self, VALUE obj, VALUE method) {
+ return rb_funcallv_public(obj, SYM2ID(method), 0, NULL);
+}
+
+static VALUE kernel_spec_rb_funcall_with_block(VALUE self, VALUE obj, VALUE method, VALUE args, VALUE block) {
+ return rb_funcall_with_block(obj, SYM2ID(method), RARRAY_LENINT(args), RARRAY_PTR(args), block);
}
-static VALUE kernel_spec_rb_funcall_with_block(VALUE self, VALUE obj, VALUE method, VALUE block) {
- return rb_funcall_with_block(obj, SYM2ID(method), 0, NULL, block);
+static VALUE kernel_spec_rb_funcall_with_block_kw(VALUE self, VALUE obj, VALUE method, VALUE args, VALUE block) {
+ return rb_funcall_with_block_kw(obj, SYM2ID(method), RARRAY_LENINT(args), RARRAY_PTR(args), block, RB_PASS_KEYWORDS);
}
static VALUE kernel_spec_rb_funcall_many_args(VALUE self, VALUE obj, VALUE method) {
@@ -333,6 +355,15 @@ static VALUE kernel_spec_rb_funcall_many_args(VALUE self, VALUE obj, VALUE metho
INT2FIX(5), INT2FIX(4), INT2FIX(3), INT2FIX(2), INT2FIX(1));
}
+static VALUE kernel_spec_rb_check_funcall(VALUE self, VALUE receiver, VALUE method, VALUE args) {
+ VALUE ret = rb_check_funcall(receiver, SYM2ID(method), RARRAY_LENINT(args), RARRAY_PTR(args));
+ if (ret == Qundef) {
+ return ID2SYM(rb_intern("Qundef"));
+ } else {
+ return ret;
+ }
+}
+
void Init_kernel_spec(void) {
VALUE cls = rb_define_class("CApiKernelSpecs", rb_cObject);
rb_define_method(cls, "rb_block_given_p", kernel_spec_rb_block_given_p, 0);
@@ -347,6 +378,7 @@ void Init_kernel_spec(void) {
rb_define_method(cls, "rb_frame_this_func_test_again", kernel_spec_rb_frame_this_func, 0);
rb_define_method(cls, "rb_ensure", kernel_spec_rb_ensure, 4);
rb_define_method(cls, "rb_eval_string", kernel_spec_rb_eval_string, 1);
+ rb_define_method(cls, "rb_eval_cmd_kw", kernel_spec_rb_eval_cmd_kw, 3);
rb_define_method(cls, "rb_raise", kernel_spec_rb_raise, 1);
rb_define_method(cls, "rb_throw", kernel_spec_rb_throw, 1);
rb_define_method(cls, "rb_throw_obj", kernel_spec_rb_throw_obj, 2);
@@ -371,9 +403,16 @@ void Init_kernel_spec(void) {
rb_define_method(cls, "rb_set_end_proc", kernel_spec_rb_set_end_proc, 1);
rb_define_method(cls, "rb_f_sprintf", kernel_spec_rb_f_sprintf, 1);
rb_define_method(cls, "rb_make_backtrace", kernel_spec_rb_make_backtrace, 0);
- rb_define_method(cls, "rb_funcall3", kernel_spec_rb_funcall3, 2);
+ rb_define_method(cls, "rb_funcallv", kernel_spec_rb_funcallv, 3);
+#ifdef RUBY_VERSION_IS_3_0
+ rb_define_method(cls, "rb_funcallv_kw", kernel_spec_rb_funcallv_kw, 3);
+ rb_define_method(cls, "rb_keyword_given_p", kernel_spec_rb_keyword_given_p, -1);
+#endif
+ rb_define_method(cls, "rb_funcallv_public", kernel_spec_rb_funcallv_public, 2);
rb_define_method(cls, "rb_funcall_many_args", kernel_spec_rb_funcall_many_args, 2);
- rb_define_method(cls, "rb_funcall_with_block", kernel_spec_rb_funcall_with_block, 3);
+ rb_define_method(cls, "rb_funcall_with_block", kernel_spec_rb_funcall_with_block, 4);
+ rb_define_method(cls, "rb_funcall_with_block_kw", kernel_spec_rb_funcall_with_block_kw, 4);
+ rb_define_method(cls, "rb_check_funcall", kernel_spec_rb_check_funcall, 3);
}
#ifdef __cplusplus
diff --git a/spec/ruby/optional/capi/ext/module_spec.c b/spec/ruby/optional/capi/ext/module_spec.c
index 7475994fa1..12bcf99983 100644
--- a/spec/ruby/optional/capi/ext/module_spec.c
+++ b/spec/ruby/optional/capi/ext/module_spec.c
@@ -9,18 +9,6 @@ static VALUE module_specs_test_method(VALUE self) {
return ID2SYM(rb_intern("test_method"));
}
-static VALUE module_specs_test_method_2required(VALUE self, VALUE arg1, VALUE arg2) {
- return ID2SYM(rb_intern("test_method_2required"));
-}
-
-static VALUE module_specs_test_method_c_array(int argc, VALUE *argv, VALUE self) {
- return ID2SYM(rb_intern("test_method_c_array"));
-}
-
-static VALUE module_specs_test_method_ruby_array(VALUE self, VALUE args) {
- return ID2SYM(rb_intern("test_method_ruby_array"));
-}
-
static VALUE module_specs_const_defined(VALUE self, VALUE klass, VALUE id) {
return rb_const_defined(klass, SYM2ID(id)) ? Qtrue : Qfalse;
}
@@ -88,19 +76,25 @@ static VALUE module_specs_rb_define_method(VALUE self, VALUE cls, VALUE str_name
return Qnil;
}
-static VALUE module_specs_rb_define_method_2required(VALUE self, VALUE cls, VALUE str_name) {
- rb_define_method(cls, RSTRING_PTR(str_name), module_specs_test_method_2required, 2);
- return Qnil;
+static VALUE module_specs_method_var_args_1(int argc, VALUE *argv, VALUE self) {
+ VALUE ary = rb_ary_new();
+ int i;
+ for (i = 0; i < argc; i++) {
+ rb_ary_push(ary, argv[i]);
+ }
+ return ary;
}
-static VALUE module_specs_rb_define_method_c_array(VALUE self, VALUE cls, VALUE str_name) {
- rb_define_method(cls, RSTRING_PTR(str_name), module_specs_test_method_c_array, -1);
- return Qnil;
+static VALUE module_specs_method_var_args_2(VALUE self, VALUE argv) {
+ return argv;
}
-static VALUE module_specs_rb_define_method_ruby_array(VALUE self, VALUE cls, VALUE str_name) {
- rb_define_method(cls, RSTRING_PTR(str_name), module_specs_test_method_ruby_array, -2);
- return Qnil;
+static VALUE module_specs_rb_define_method_1required(VALUE self, VALUE arg1) {
+ return arg1;
+}
+
+static VALUE module_specs_rb_define_method_2required(VALUE self, VALUE arg1, VALUE arg2) {
+ return arg2;
}
static VALUE module_specs_rb_define_module_function(VALUE self, VALUE cls, VALUE str_name) {
@@ -155,25 +149,21 @@ void Init_module_spec(void) {
rb_define_method(cls, "rb_define_module_under", module_specs_rb_define_module_under, 2);
rb_define_method(cls, "rb_define_const", module_specs_define_const, 3);
rb_define_method(cls, "rb_define_global_const", module_specs_define_global_const, 2);
- rb_define_method(cls, "rb_define_global_function",
- module_specs_rb_define_global_function, 1);
+ rb_define_method(cls, "rb_define_global_function", module_specs_rb_define_global_function, 1);
rb_define_method(cls, "rb_define_method", module_specs_rb_define_method, 2);
+ rb_define_method(cls, "rb_define_method_varargs_1", module_specs_method_var_args_1, -1);
+ rb_define_method(cls, "rb_define_method_varargs_2", module_specs_method_var_args_2, -2);
+ rb_define_method(cls, "rb_define_method_1required", module_specs_rb_define_method_1required, 1);
rb_define_method(cls, "rb_define_method_2required", module_specs_rb_define_method_2required, 2);
- rb_define_method(cls, "rb_define_method_c_array", module_specs_rb_define_method_c_array, 2);
- rb_define_method(cls, "rb_define_method_ruby_array", module_specs_rb_define_method_ruby_array, 2);
- rb_define_method(cls, "rb_define_module_function",
- module_specs_rb_define_module_function, 2);
+ rb_define_method(cls, "rb_define_module_function", module_specs_rb_define_module_function, 2);
- rb_define_method(cls, "rb_define_private_method",
- module_specs_rb_define_private_method, 2);
+ rb_define_method(cls, "rb_define_private_method", module_specs_rb_define_private_method, 2);
- rb_define_method(cls, "rb_define_protected_method",
- module_specs_rb_define_protected_method, 2);
+ rb_define_method(cls, "rb_define_protected_method", module_specs_rb_define_protected_method, 2);
- rb_define_method(cls, "rb_define_singleton_method",
- module_specs_rb_define_singleton_method, 2);
+ rb_define_method(cls, "rb_define_singleton_method", module_specs_rb_define_singleton_method, 2);
rb_define_method(cls, "rb_undef_method", module_specs_rb_undef_method, 2);
rb_define_method(cls, "rb_undef", module_specs_rb_undef, 2);
diff --git a/spec/ruby/optional/capi/ext/object_spec.c b/spec/ruby/optional/capi/ext/object_spec.c
index 6c4b66fc06..8aa98cc5ce 100644
--- a/spec/ruby/optional/capi/ext/object_spec.c
+++ b/spec/ruby/optional/capi/ext/object_spec.c
@@ -118,11 +118,14 @@ static VALUE so_rb_obj_call_init(VALUE self, VALUE object,
return Qnil;
}
+static VALUE so_rb_obj_class(VALUE self, VALUE obj) {
+ return rb_obj_class(obj);
+}
+
static VALUE so_rbobjclassname(VALUE self, VALUE obj) {
return rb_str_new2(rb_obj_classname(obj));
}
-
static VALUE object_spec_rb_obj_freeze(VALUE self, VALUE obj) {
return rb_obj_freeze(obj);
}
@@ -151,30 +154,12 @@ static VALUE object_specs_rb_obj_method(VALUE self, VALUE obj, VALUE method) {
return rb_obj_method(obj, method);
}
-#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
-# pragma GCC diagnostic push
-# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-#elif defined(__clang__) && defined(__has_warning)
-# if __has_warning("-Wdeprecated-declarations")
-# pragma clang diagnostic push
-# pragma clang diagnostic ignored "-Wdeprecated-declarations"
-# endif
-#endif
-
#ifndef RUBY_VERSION_IS_3_2
static VALUE object_spec_rb_obj_taint(VALUE self, VALUE obj) {
return rb_obj_taint(obj);
}
#endif
-#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
-# pragma GCC diagnostic pop
-#elif defined(__clang__) && defined(__has_warning)
-# if __has_warning("-Wdeprecated-declarations")
-# pragma clang diagnostic pop
-# endif
-#endif
-
static VALUE so_require(VALUE self) {
rb_require("fixtures/foo");
return Qnil;
@@ -194,11 +179,7 @@ static VALUE object_spec_rb_method_boundp(VALUE self, VALUE obj, VALUE method, V
}
static VALUE object_spec_rb_special_const_p(VALUE self, VALUE value) {
- if (rb_special_const_p(value)) {
- return Qtrue;
- } else {
- return Qfalse;
- }
+ return rb_special_const_p(value);
}
static VALUE so_to_id(VALUE self, VALUE obj) {
@@ -215,119 +196,126 @@ static VALUE so_check_type(VALUE self, VALUE obj, VALUE other) {
}
static VALUE so_is_type_nil(VALUE self, VALUE obj) {
- if(TYPE(obj) == T_NIL) {
+ if (TYPE(obj) == T_NIL) {
return Qtrue;
}
return Qfalse;
}
static VALUE so_is_type_object(VALUE self, VALUE obj) {
- if(TYPE(obj) == T_OBJECT) {
+ if (TYPE(obj) == T_OBJECT) {
return Qtrue;
}
return Qfalse;
}
static VALUE so_is_type_array(VALUE self, VALUE obj) {
- if(TYPE(obj) == T_ARRAY) {
+ if (TYPE(obj) == T_ARRAY) {
return Qtrue;
}
return Qfalse;
}
static VALUE so_is_type_module(VALUE self, VALUE obj) {
- if(TYPE(obj) == T_MODULE) {
+ if (TYPE(obj) == T_MODULE) {
return Qtrue;
}
return Qfalse;
}
static VALUE so_is_type_class(VALUE self, VALUE obj) {
- if(TYPE(obj) == T_CLASS) {
+ if (TYPE(obj) == T_CLASS) {
return Qtrue;
}
return Qfalse;
}
static VALUE so_is_type_data(VALUE self, VALUE obj) {
- if(TYPE(obj) == T_DATA) {
+ if (TYPE(obj) == T_DATA) {
return Qtrue;
}
return Qfalse;
}
static VALUE so_is_rb_type_p_nil(VALUE self, VALUE obj) {
- if(rb_type_p(obj, T_NIL)) {
+ if (rb_type_p(obj, T_NIL)) {
return Qtrue;
}
return Qfalse;
}
static VALUE so_is_rb_type_p_object(VALUE self, VALUE obj) {
- if(rb_type_p(obj, T_OBJECT)) {
+ if (rb_type_p(obj, T_OBJECT)) {
return Qtrue;
}
return Qfalse;
}
static VALUE so_is_rb_type_p_array(VALUE self, VALUE obj) {
- if(rb_type_p(obj, T_ARRAY)) {
+ if (rb_type_p(obj, T_ARRAY)) {
return Qtrue;
}
return Qfalse;
}
static VALUE so_is_rb_type_p_module(VALUE self, VALUE obj) {
- if(rb_type_p(obj, T_MODULE)) {
+ if (rb_type_p(obj, T_MODULE)) {
return Qtrue;
}
return Qfalse;
}
static VALUE so_is_rb_type_p_class(VALUE self, VALUE obj) {
- if(rb_type_p(obj, T_CLASS)) {
+ if (rb_type_p(obj, T_CLASS)) {
return Qtrue;
}
return Qfalse;
}
static VALUE so_is_rb_type_p_data(VALUE self, VALUE obj) {
- if(rb_type_p(obj, T_DATA)) {
+ if (rb_type_p(obj, T_DATA)) {
+ return Qtrue;
+ }
+ return Qfalse;
+}
+
+static VALUE so_is_rb_type_p_file(VALUE self, VALUE obj) {
+ if (rb_type_p(obj, T_FILE)) {
return Qtrue;
}
return Qfalse;
}
static VALUE so_is_builtin_type_object(VALUE self, VALUE obj) {
- if(BUILTIN_TYPE(obj) == T_OBJECT) {
+ if (BUILTIN_TYPE(obj) == T_OBJECT) {
return Qtrue;
}
return Qfalse;
}
static VALUE so_is_builtin_type_array(VALUE self, VALUE obj) {
- if(BUILTIN_TYPE(obj) == T_ARRAY) {
+ if (BUILTIN_TYPE(obj) == T_ARRAY) {
return Qtrue;
}
return Qfalse;
}
static VALUE so_is_builtin_type_module(VALUE self, VALUE obj) {
- if(BUILTIN_TYPE(obj) == T_MODULE) {
+ if (BUILTIN_TYPE(obj) == T_MODULE) {
return Qtrue;
}
return Qfalse;
}
static VALUE so_is_builtin_type_class(VALUE self, VALUE obj) {
- if(BUILTIN_TYPE(obj) == T_CLASS) {
+ if (BUILTIN_TYPE(obj) == T_CLASS) {
return Qtrue;
}
return Qfalse;
}
static VALUE so_is_builtin_type_data(VALUE self, VALUE obj) {
- if(BUILTIN_TYPE(obj) == T_DATA) {
+ if (BUILTIN_TYPE(obj) == T_DATA) {
return Qtrue;
}
return Qfalse;
@@ -383,17 +371,21 @@ static VALUE object_spec_rb_class_inherited_p(VALUE self, VALUE mod, VALUE arg)
return rb_class_inherited_p(mod, arg);
}
+static int foreach_f(ID key, VALUE val, VALUE ary) {
+ rb_ary_push(ary, ID2SYM(key));
+ rb_ary_push(ary, val);
+ return ST_CONTINUE;
+}
+
+static VALUE object_spec_rb_ivar_foreach(VALUE self, VALUE obj) {
+ VALUE ary = rb_ary_new();
+ rb_ivar_foreach(obj, foreach_f, ary);
+ return ary;
+}
+
static VALUE speced_allocator(VALUE klass) {
- VALUE flags = 0;
- VALUE instance;
- if (RTEST(rb_class_inherited_p(klass, rb_cString))) {
- flags = T_STRING;
- } else if (RTEST(rb_class_inherited_p(klass, rb_cArray))) {
- flags = T_ARRAY;
- } else {
- flags = T_OBJECT;
- }
- instance = rb_newobj_of(klass, flags);
+ VALUE super = rb_class_get_superclass(klass);
+ VALUE instance = rb_get_alloc_func(super)(klass);
rb_iv_set(instance, "@from_custom_allocator", Qtrue);
return instance;
}
@@ -442,6 +434,7 @@ void Init_object_spec(void) {
rb_define_method(cls, "rb_obj_alloc", so_rb_obj_alloc, 1);
rb_define_method(cls, "rb_obj_dup", so_rb_obj_dup, 1);
rb_define_method(cls, "rb_obj_call_init", so_rb_obj_call_init, 3);
+ rb_define_method(cls, "rb_obj_class", so_rb_obj_class, 1);
rb_define_method(cls, "rb_obj_classname", so_rbobjclassname, 1);
rb_define_method(cls, "rb_obj_freeze", object_spec_rb_obj_freeze, 1);
rb_define_method(cls, "rb_obj_frozen_p", object_spec_rb_obj_frozen_p, 1);
@@ -474,6 +467,7 @@ void Init_object_spec(void) {
rb_define_method(cls, "rb_is_rb_type_p_module", so_is_rb_type_p_module, 1);
rb_define_method(cls, "rb_is_rb_type_p_class", so_is_rb_type_p_class, 1);
rb_define_method(cls, "rb_is_rb_type_p_data", so_is_rb_type_p_data, 1);
+ rb_define_method(cls, "rb_is_rb_type_p_file", so_is_rb_type_p_file, 1);
rb_define_method(cls, "rb_is_builtin_type_object", so_is_builtin_type_object, 1);
rb_define_method(cls, "rb_is_builtin_type_array", so_is_builtin_type_array, 1);
rb_define_method(cls, "rb_is_builtin_type_module", so_is_builtin_type_module, 1);
@@ -496,6 +490,7 @@ void Init_object_spec(void) {
rb_define_method(cls, "speced_allocator?", speced_allocator_p, 1);
rb_define_method(cls, "custom_alloc_func?", custom_alloc_func_p, 1);
rb_define_method(cls, "not_implemented_method", rb_f_notimplement, -1);
+ rb_define_method(cls, "rb_ivar_foreach", object_spec_rb_ivar_foreach, 1);
}
#ifdef __cplusplus
diff --git a/spec/ruby/optional/capi/ext/proc_spec.c b/spec/ruby/optional/capi/ext/proc_spec.c
index 1137f4156b..b7cd5d6262 100644
--- a/spec/ruby/optional/capi/ext/proc_spec.c
+++ b/spec/ruby/optional/capi/ext/proc_spec.c
@@ -76,6 +76,18 @@ VALUE proc_spec_rb_proc_call(VALUE self, VALUE prc, VALUE args) {
return rb_proc_call(prc, args);
}
+VALUE proc_spec_rb_proc_call_kw(VALUE self, VALUE prc, VALUE args) {
+ return rb_proc_call_kw(prc, args, RB_PASS_KEYWORDS);
+}
+
+VALUE proc_spec_rb_proc_call_with_block(VALUE self, VALUE prc, VALUE args, VALUE block) {
+ return rb_proc_call_with_block(prc, RARRAY_LENINT(args), RARRAY_PTR(args), block);
+}
+
+static VALUE proc_spec_rb_proc_call_with_block_kw(VALUE self, VALUE prc, VALUE args, VALUE block) {
+ return rb_proc_call_with_block_kw(prc, RARRAY_LENINT(args), RARRAY_PTR(args), block, RB_PASS_KEYWORDS);
+}
+
VALUE proc_spec_rb_obj_is_proc(VALUE self, VALUE prc) {
return rb_obj_is_proc(prc);
}
@@ -123,6 +135,9 @@ void Init_proc_spec(void) {
rb_define_method(cls, "rb_proc_new_block_given_p", proc_spec_rb_proc_new_block_given_p, 0);
rb_define_method(cls, "rb_proc_arity", proc_spec_rb_proc_arity, 1);
rb_define_method(cls, "rb_proc_call", proc_spec_rb_proc_call, 2);
+ rb_define_method(cls, "rb_proc_call_kw", proc_spec_rb_proc_call_kw, 2);
+ rb_define_method(cls, "rb_proc_call_with_block", proc_spec_rb_proc_call_with_block, 3);
+ rb_define_method(cls, "rb_proc_call_with_block_kw", proc_spec_rb_proc_call_with_block_kw, 3);
rb_define_method(cls, "rb_Proc_new", proc_spec_rb_Proc_new, 1);
rb_define_method(cls, "rb_obj_is_proc", proc_spec_rb_obj_is_proc, 1);
}
diff --git a/spec/ruby/optional/capi/ext/range_spec.c b/spec/ruby/optional/capi/ext/range_spec.c
index 7a475ec695..b0cf1a8662 100644
--- a/spec/ruby/optional/capi/ext/range_spec.c
+++ b/spec/ruby/optional/capi/ext/range_spec.c
@@ -7,7 +7,7 @@ extern "C" {
VALUE range_spec_rb_range_new(int argc, VALUE* argv, VALUE self) {
int exclude_end = 0;
- if(argc == 3) {
+ if (argc == 3) {
exclude_end = RTEST(argv[2]);
}
return rb_range_new(argv[0], argv[1], exclude_end);
diff --git a/spec/ruby/optional/capi/ext/rbasic_spec.c b/spec/ruby/optional/capi/ext/rbasic_spec.c
index 9178e5f639..26be2fed6d 100644
--- a/spec/ruby/optional/capi/ext/rbasic_spec.c
+++ b/spec/ruby/optional/capi/ext/rbasic_spec.c
@@ -5,6 +5,14 @@
extern "C" {
#endif
+#ifndef RBASIC_FLAGS
+#define RBASIC_FLAGS(obj) (RBASIC(obj)->flags)
+#endif
+
+#ifndef RBASIC_SET_FLAGS
+#define RBASIC_SET_FLAGS(obj, flags_to_set) (RBASIC(obj)->flags = flags_to_set)
+#endif
+
#ifndef FL_SHAREABLE
static const VALUE VISIBLE_BITS = FL_TAINT | FL_FREEZE;
static const VALUE DATA_VISIBLE_BITS = FL_TAINT | FL_FREEZE | ~(FL_USER0 - 1);
@@ -34,47 +42,53 @@ VALUE rbasic_spec_freeze_flag(VALUE self) {
return VALUE2NUM(RUBY_FL_FREEZE);
}
- static VALUE spec_get_flags(const struct RBasic *b, VALUE visible_bits) {
- VALUE flags = b->flags & visible_bits;
+static VALUE spec_get_flags(VALUE obj, VALUE visible_bits) {
+ VALUE flags = RB_FL_TEST(obj, visible_bits);
return VALUE2NUM(flags);
}
-static VALUE spec_set_flags(struct RBasic *b, VALUE flags, VALUE visible_bits) {
+static VALUE spec_set_flags(VALUE obj, VALUE flags, VALUE visible_bits) {
flags &= visible_bits;
- b->flags = (b->flags & ~visible_bits) | flags;
+
+ // Could also be done like:
+ // RB_FL_UNSET(obj, visible_bits);
+ // RB_FL_SET(obj, flags);
+ // But that seems rather indirect
+ RBASIC_SET_FLAGS(obj, (RBASIC_FLAGS(obj) & ~visible_bits) | flags);
+
return VALUE2NUM(flags);
}
-VALUE rbasic_spec_get_flags(VALUE self, VALUE val) {
- return spec_get_flags(RBASIC(val), VISIBLE_BITS);
+static VALUE rbasic_spec_get_flags(VALUE self, VALUE obj) {
+ return spec_get_flags(obj, VISIBLE_BITS);
}
-VALUE rbasic_spec_set_flags(VALUE self, VALUE val, VALUE flags) {
- return spec_set_flags(RBASIC(val), NUM2VALUE(flags), VISIBLE_BITS);
+static VALUE rbasic_spec_set_flags(VALUE self, VALUE obj, VALUE flags) {
+ return spec_set_flags(obj, NUM2VALUE(flags), VISIBLE_BITS);
}
-VALUE rbasic_spec_copy_flags(VALUE self, VALUE to, VALUE from) {
- return spec_set_flags(RBASIC(to), RBASIC(from)->flags, VISIBLE_BITS);
+static VALUE rbasic_spec_copy_flags(VALUE self, VALUE to, VALUE from) {
+ return spec_set_flags(to, RBASIC_FLAGS(from), VISIBLE_BITS);
}
-VALUE rbasic_spec_get_klass(VALUE self, VALUE val) {
- return RBASIC(val)->klass;
+static VALUE rbasic_spec_get_klass(VALUE self, VALUE obj) {
+ return RBASIC_CLASS(obj);
}
-VALUE rbasic_rdata_spec_get_flags(VALUE self, VALUE structure) {
- return spec_get_flags(&RDATA(structure)->basic, DATA_VISIBLE_BITS);
+static VALUE rbasic_rdata_spec_get_flags(VALUE self, VALUE structure) {
+ return spec_get_flags(structure, DATA_VISIBLE_BITS);
}
-VALUE rbasic_rdata_spec_set_flags(VALUE self, VALUE structure, VALUE flags) {
- return spec_set_flags(&RDATA(structure)->basic, NUM2VALUE(flags), DATA_VISIBLE_BITS);
+static VALUE rbasic_rdata_spec_set_flags(VALUE self, VALUE structure, VALUE flags) {
+ return spec_set_flags(structure, NUM2VALUE(flags), DATA_VISIBLE_BITS);
}
-VALUE rbasic_rdata_spec_copy_flags(VALUE self, VALUE to, VALUE from) {
- return spec_set_flags(&RDATA(to)->basic, RDATA(from)->basic.flags, DATA_VISIBLE_BITS);
+static VALUE rbasic_rdata_spec_copy_flags(VALUE self, VALUE to, VALUE from) {
+ return spec_set_flags(to, RBASIC_FLAGS(from), DATA_VISIBLE_BITS);
}
-VALUE rbasic_rdata_spec_get_klass(VALUE self, VALUE structure) {
- return RDATA(structure)->basic.klass;
+static VALUE rbasic_rdata_spec_get_klass(VALUE self, VALUE structure) {
+ return RBASIC_CLASS(structure);
}
void Init_rbasic_spec(void) {
diff --git a/spec/ruby/optional/capi/ext/regexp_spec.c b/spec/ruby/optional/capi/ext/regexp_spec.c
index 0a62616f33..9de7982b50 100644
--- a/spec/ruby/optional/capi/ext/regexp_spec.c
+++ b/spec/ruby/optional/capi/ext/regexp_spec.c
@@ -49,6 +49,12 @@ VALUE regexp_spec_match(VALUE self, VALUE regexp, VALUE str) {
return rb_funcall(regexp, rb_intern("match"), 1, str);
}
+VALUE regexp_spec_memcicmp(VALUE self, VALUE str1, VALUE str2) {
+ long l1 = RSTRING_LEN(str1);
+ long l2 = RSTRING_LEN(str2);
+ return INT2FIX(rb_memcicmp(RSTRING_PTR(str1), RSTRING_PTR(str2), l1 < l2 ? l1 : l2));
+}
+
void Init_regexp_spec(void) {
VALUE cls = rb_define_class("CApiRegexpSpecs", rb_cObject);
rb_define_method(cls, "match", regexp_spec_match, 2);
@@ -60,6 +66,7 @@ void Init_regexp_spec(void) {
rb_define_method(cls, "rb_reg_match_backref_get", regexp_spec_reg_match_backref_get, 2);
rb_define_method(cls, "rb_reg_options", regexp_spec_rb_reg_options, 1);
rb_define_method(cls, "rb_reg_regcomp", regexp_spec_rb_reg_regcomp, 1);
+ rb_define_method(cls, "rb_memcicmp", regexp_spec_memcicmp, 2);
}
#ifdef __cplusplus
diff --git a/spec/ruby/optional/capi/ext/rubyspec.h b/spec/ruby/optional/capi/ext/rubyspec.h
index 426b1ddc04..09135774af 100644
--- a/spec/ruby/optional/capi/ext/rubyspec.h
+++ b/spec/ruby/optional/capi/ext/rubyspec.h
@@ -11,6 +11,29 @@
# include <version.h>
#endif
+/* copied from ext/-test-/cxxanyargs/cxxanyargs.cpp */
+#if 0 /* Ignore deprecation warnings */
+
+#elif defined(_MSC_VER)
+#pragma warning(disable : 4996)
+
+#elif defined(__INTEL_COMPILER)
+#pragma warning(disable : 1786)
+
+#elif defined(__clang__)
+#pragma clang diagnostic ignored "-Wdeprecated-declarations"
+
+#elif defined(__GNUC__)
+#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
+
+#elif defined(__SUNPRO_CC)
+#pragma error_messages (off,symdeprecated)
+
+#else
+// :FIXME: improve here for your compiler.
+
+#endif
+
#ifndef RUBY_VERSION_MAJOR
#define RUBY_VERSION_MAJOR RUBY_API_VERSION_MAJOR
#define RUBY_VERSION_MINOR RUBY_API_VERSION_MINOR
@@ -21,47 +44,22 @@
((RUBY_VERSION_MAJOR < (major)) || \
(RUBY_VERSION_MAJOR == (major) && RUBY_VERSION_MINOR < (minor)) || \
(RUBY_VERSION_MAJOR == (major) && RUBY_VERSION_MINOR == (minor) && RUBY_VERSION_TEENY < (teeny)))
+#define RUBY_VERSION_SINCE(major,minor,teeny) (!RUBY_VERSION_BEFORE(major, minor, teeny))
+
+#if RUBY_VERSION_SINCE(3, 3, 0)
+#define RUBY_VERSION_IS_3_3
+#endif
-#if RUBY_VERSION_MAJOR > 3 || (RUBY_VERSION_MAJOR == 3 && RUBY_VERSION_MINOR >= 2)
+#if RUBY_VERSION_SINCE(3, 2, 0)
#define RUBY_VERSION_IS_3_2
#endif
-#if RUBY_VERSION_MAJOR > 3 || (RUBY_VERSION_MAJOR == 3 && RUBY_VERSION_MINOR >= 1)
+#if RUBY_VERSION_SINCE(3, 1, 0)
#define RUBY_VERSION_IS_3_1
#endif
-#if RUBY_VERSION_MAJOR > 3 || (RUBY_VERSION_MAJOR == 3 && RUBY_VERSION_MINOR >= 0)
+#if RUBY_VERSION_SINCE(3, 0, 0)
#define RUBY_VERSION_IS_3_0
#endif
-#if RUBY_VERSION_MAJOR > 2 || (RUBY_VERSION_MAJOR == 2 && RUBY_VERSION_MINOR >= 7)
-#define RUBY_VERSION_IS_2_7
-#endif
-
-#if RUBY_VERSION_MAJOR > 2 || (RUBY_VERSION_MAJOR == 2 && RUBY_VERSION_MINOR >= 6)
-#define RUBY_VERSION_IS_2_6
-#endif
-
-#if defined(__cplusplus) && !defined(RUBY_VERSION_IS_2_7)
-/* Ruby < 2.7 needs this to let these function with callbacks and compile in C++ code */
-#define rb_define_method(mod, name, func, argc) rb_define_method(mod, name, RUBY_METHOD_FUNC(func), argc)
-#define rb_define_protected_method(mod, name, func, argc) rb_define_protected_method(mod, name, RUBY_METHOD_FUNC(func), argc)
-#define rb_define_private_method(mod, name, func, argc) rb_define_private_method(mod, name, RUBY_METHOD_FUNC(func), argc)
-#define rb_define_singleton_method(mod, name, func, argc) rb_define_singleton_method(mod, name, RUBY_METHOD_FUNC(func), argc)
-#define rb_define_module_function(mod, name, func, argc) rb_define_module_function(mod, name, RUBY_METHOD_FUNC(func), argc)
-#define rb_define_global_function(name, func, argc) rb_define_global_function(name, RUBY_METHOD_FUNC(func), argc)
-#define rb_hash_foreach(hash, func, farg) rb_hash_foreach(hash, (int (*)(...))func, farg)
-#define st_foreach(tab, func, arg) st_foreach(tab, (int (*)(...))func, arg)
-#define rb_block_call(object, name, args_count, args, block_call_func, data) rb_block_call(object, name, args_count, args, RUBY_METHOD_FUNC(block_call_func), data)
-#define rb_ensure(b_proc, data1, e_proc, data2) rb_ensure(RUBY_METHOD_FUNC(b_proc), data1, RUBY_METHOD_FUNC(e_proc), data2)
-#define rb_rescue(b_proc, data1, e_proc, data2) rb_rescue(RUBY_METHOD_FUNC(b_proc), data1, RUBY_METHOD_FUNC(e_proc), data2)
-#define rb_rescue2(b_proc, data1, e_proc, data2, ...) rb_rescue2(RUBY_METHOD_FUNC(b_proc), data1, RUBY_METHOD_FUNC(e_proc), data2, __VA_ARGS__)
-#define rb_catch(tag, func, data) rb_catch(tag, RUBY_METHOD_FUNC(func), data)
-#define rb_catch_obj(tag, func, data) rb_catch_obj(tag, RUBY_METHOD_FUNC(func), data)
-#define rb_proc_new(fn, arg) rb_proc_new(RUBY_METHOD_FUNC(fn), arg)
-#define rb_fiber_new(fn, arg) rb_fiber_new(RUBY_METHOD_FUNC(fn), arg)
-#define rb_thread_create(fn, arg) rb_thread_create(RUBY_METHOD_FUNC(fn), arg)
-#define rb_define_hooked_variable(name, var, getter, setter) rb_define_hooked_variable(name, var, RUBY_METHOD_FUNC(getter), (void (*)(...))setter)
-#endif
-
#endif
diff --git a/spec/ruby/optional/capi/ext/string_spec.c b/spec/ruby/optional/capi/ext/string_spec.c
index 2bcd3be243..cec3f65f45 100644
--- a/spec/ruby/optional/capi/ext/string_spec.c
+++ b/spec/ruby/optional/capi/ext/string_spec.c
@@ -51,18 +51,12 @@ VALUE string_spec_rb_str_set_len_RSTRING_LEN(VALUE self, VALUE str, VALUE len) {
return INT2FIX(RSTRING_LEN(str));
}
-VALUE rb_fstring(VALUE str); /* internal.h, used in ripper */
-
-VALUE string_spec_rb_str_fstring(VALUE self, VALUE str) {
- return rb_fstring(str);
-}
-
VALUE string_spec_rb_str_buf_new(VALUE self, VALUE len, VALUE str) {
VALUE buf;
buf = rb_str_buf_new(NUM2LONG(len));
- if(RTEST(str)) {
+ if (RTEST(str)) {
snprintf(RSTRING_PTR(buf), NUM2LONG(len), "%s", RSTRING_PTR(str));
}
@@ -87,6 +81,10 @@ VALUE string_spec_rb_str_tmp_new_klass(VALUE self, VALUE len) {
return RBASIC_CLASS(rb_str_tmp_new(NUM2LONG(len)));
}
+VALUE string_spec_rb_str_buf_append(VALUE self, VALUE str, VALUE two) {
+ return rb_str_buf_append(str, two);
+}
+
VALUE string_spec_rb_str_buf_cat(VALUE self, VALUE str) {
const char *question_mark = "?";
rb_str_buf_cat(str, question_mark, strlen(question_mark));
@@ -125,7 +123,7 @@ VALUE string_spec_rb_str_conv_enc(VALUE self, VALUE str, VALUE from, VALUE to) {
from_enc = rb_to_encoding(from);
- if(NIL_P(to)) {
+ if (NIL_P(to)) {
to_enc = 0;
} else {
to_enc = rb_to_encoding(to);
@@ -135,14 +133,13 @@ VALUE string_spec_rb_str_conv_enc(VALUE self, VALUE str, VALUE from, VALUE to) {
}
VALUE string_spec_rb_str_conv_enc_opts(VALUE self, VALUE str, VALUE from, VALUE to,
- VALUE ecflags, VALUE ecopts)
-{
+ VALUE ecflags, VALUE ecopts) {
rb_encoding* from_enc;
rb_encoding* to_enc;
from_enc = rb_to_encoding(from);
- if(NIL_P(to)) {
+ if (NIL_P(to)) {
to_enc = 0;
} else {
to_enc = rb_to_encoding(to);
@@ -196,7 +193,7 @@ VALUE string_spec_rb_str_new_offset(VALUE self, VALUE str, VALUE offset, VALUE l
}
VALUE string_spec_rb_str_new2(VALUE self, VALUE str) {
- if(NIL_P(str)) {
+ if (NIL_P(str)) {
return rb_str_new2("");
} else {
return rb_str_new2(RSTRING_PTR(str));
@@ -212,7 +209,7 @@ VALUE string_spec_rb_str_export_to_enc(VALUE self, VALUE str, VALUE enc) {
}
VALUE string_spec_rb_str_new_cstr(VALUE self, VALUE str) {
- if(NIL_P(str)) {
+ if (NIL_P(str)) {
return rb_str_new_cstr("");
} else {
return rb_str_new_cstr(RSTRING_PTR(str));
@@ -251,16 +248,6 @@ VALUE string_spec_rb_str_new5(VALUE self, VALUE str, VALUE ptr, VALUE len) {
return rb_str_new5(str, RSTRING_PTR(ptr), FIX2INT(len));
}
-#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
-# pragma GCC diagnostic push
-# pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-#elif defined(__clang__) && defined(__has_warning)
-# if __has_warning("-Wdeprecated-declarations")
-# pragma clang diagnostic push
-# pragma clang diagnostic ignored "-Wdeprecated-declarations"
-# endif
-#endif
-
#ifndef RUBY_VERSION_IS_3_2
VALUE string_spec_rb_tainted_str_new(VALUE self, VALUE str, VALUE len) {
return rb_tainted_str_new(RSTRING_PTR(str), FIX2INT(len));
@@ -271,14 +258,6 @@ VALUE string_spec_rb_tainted_str_new2(VALUE self, VALUE str) {
}
#endif
-#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6))
-# pragma GCC diagnostic pop
-#elif defined(__clang__) && defined(__has_warning)
-# if __has_warning("-Wdeprecated-declarations")
-# pragma clang diagnostic pop
-# endif
-#endif
-
VALUE string_spec_rb_str_plus(VALUE self, VALUE str1, VALUE str2) {
return rb_str_plus(str1, str2);
}
@@ -386,7 +365,7 @@ VALUE string_spec_RSTRING_PTR_set(VALUE self, VALUE str, VALUE i, VALUE chr) {
VALUE string_spec_RSTRING_PTR_after_funcall(VALUE self, VALUE str, VALUE cb) {
/* Silence gcc 4.3.2 warning about computed value not used */
- if(RSTRING_PTR(str)) { /* force it out */
+ if (RSTRING_PTR(str)) { /* force it out */
rb_funcall(cb, rb_intern("call"), 1, str);
}
@@ -433,6 +412,12 @@ VALUE string_spec_RSTRING_PTR_read(VALUE self, VALUE str, VALUE path) {
return capacities;
}
+VALUE string_spec_RSTRING_PTR_null_terminate(VALUE self, VALUE str, VALUE min_length) {
+ char* ptr = RSTRING_PTR(str);
+ char* end = ptr + RSTRING_LEN(str);
+ return rb_str_new(end, FIX2LONG(min_length));
+}
+
VALUE string_spec_StringValue(VALUE self, VALUE str) {
return StringValue(str);
}
@@ -563,7 +548,7 @@ static VALUE string_spec_rb_utf8_str_new_cstr(VALUE self) {
}
PRINTF_ARGS(static VALUE call_rb_str_vcatf(VALUE mesg, const char *fmt, ...), 2, 3);
-static VALUE call_rb_str_vcatf(VALUE mesg, const char *fmt, ...){
+static VALUE call_rb_str_vcatf(VALUE mesg, const char *fmt, ...) {
va_list ap;
va_start(ap, fmt);
VALUE result = rb_str_vcatf(mesg, fmt, ap);
@@ -587,11 +572,19 @@ static VALUE string_spec_rb_str_unlocktmp(VALUE self, VALUE str) {
return rb_str_unlocktmp(str);
}
+static VALUE string_spec_rb_enc_interned_str_cstr(VALUE self, VALUE str, VALUE enc) {
+ rb_encoding *e = NIL_P(enc) ? 0 : rb_to_encoding(enc);
+ return rb_enc_interned_str_cstr(RSTRING_PTR(str), e);
+}
+
+static VALUE string_spec_rb_str_to_interned_str(VALUE self, VALUE str) {
+ return rb_str_to_interned_str(str);
+}
+
void Init_string_spec(void) {
VALUE cls = rb_define_class("CApiStringSpecs", rb_cObject);
rb_define_method(cls, "rb_cstr2inum", string_spec_rb_cstr2inum, 2);
rb_define_method(cls, "rb_cstr_to_inum", string_spec_rb_cstr_to_inum, 3);
- rb_define_method(cls, "rb_fstring", string_spec_rb_str_fstring, 1);
rb_define_method(cls, "rb_str2inum", string_spec_rb_str2inum, 2);
rb_define_method(cls, "rb_str_append", string_spec_rb_str_append, 2);
rb_define_method(cls, "rb_str_buf_new", string_spec_rb_str_buf_new, 2);
@@ -599,6 +592,7 @@ void Init_string_spec(void) {
rb_define_method(cls, "rb_str_buf_new2", string_spec_rb_str_buf_new2, 0);
rb_define_method(cls, "rb_str_tmp_new", string_spec_rb_str_tmp_new, 1);
rb_define_method(cls, "rb_str_tmp_new_klass", string_spec_rb_str_tmp_new_klass, 1);
+ rb_define_method(cls, "rb_str_buf_append", string_spec_rb_str_buf_append, 2);
rb_define_method(cls, "rb_str_buf_cat", string_spec_rb_str_buf_cat, 1);
rb_define_method(cls, "rb_enc_str_buf_cat", string_spec_rb_enc_str_buf_cat, 3);
rb_define_method(cls, "rb_str_cat", string_spec_rb_str_cat, 1);
@@ -657,6 +651,7 @@ void Init_string_spec(void) {
rb_define_method(cls, "RSTRING_PTR_after_funcall", string_spec_RSTRING_PTR_after_funcall, 2);
rb_define_method(cls, "RSTRING_PTR_after_yield", string_spec_RSTRING_PTR_after_yield, 1);
rb_define_method(cls, "RSTRING_PTR_read", string_spec_RSTRING_PTR_read, 2);
+ rb_define_method(cls, "RSTRING_PTR_null_terminate", string_spec_RSTRING_PTR_null_terminate, 2);
rb_define_method(cls, "StringValue", string_spec_StringValue, 1);
rb_define_method(cls, "SafeStringValue", string_spec_SafeStringValue, 1);
rb_define_method(cls, "rb_str_hash", string_spec_rb_str_hash, 1);
@@ -686,6 +681,8 @@ void Init_string_spec(void) {
rb_define_method(cls, "rb_str_catf", string_spec_rb_str_catf, 1);
rb_define_method(cls, "rb_str_locktmp", string_spec_rb_str_locktmp, 1);
rb_define_method(cls, "rb_str_unlocktmp", string_spec_rb_str_unlocktmp, 1);
+ rb_define_method(cls, "rb_enc_interned_str_cstr", string_spec_rb_enc_interned_str_cstr, 2);
+ rb_define_method(cls, "rb_str_to_interned_str", string_spec_rb_str_to_interned_str, 1);
}
#ifdef __cplusplus
diff --git a/spec/ruby/optional/capi/ext/struct_spec.c b/spec/ruby/optional/capi/ext/struct_spec.c
index 0393d6937d..9c45bd5672 100644
--- a/spec/ruby/optional/capi/ext/struct_spec.c
+++ b/spec/ruby/optional/capi/ext/struct_spec.c
@@ -15,13 +15,11 @@ static VALUE struct_spec_rb_struct_getmember(VALUE self, VALUE st, VALUE key) {
return rb_struct_getmember(st, SYM2ID(key));
}
-static VALUE struct_spec_rb_struct_s_members(VALUE self, VALUE klass)
-{
+static VALUE struct_spec_rb_struct_s_members(VALUE self, VALUE klass) {
return rb_ary_dup(rb_struct_s_members(klass));
}
-static VALUE struct_spec_rb_struct_members(VALUE self, VALUE st)
-{
+static VALUE struct_spec_rb_struct_members(VALUE self, VALUE st) {
return rb_ary_dup(rb_struct_members(st));
}
@@ -56,14 +54,11 @@ static VALUE struct_spec_struct_define_under(VALUE self, VALUE outer,
}
static VALUE struct_spec_rb_struct_new(VALUE self, VALUE klass,
- VALUE a, VALUE b, VALUE c)
-{
-
+ VALUE a, VALUE b, VALUE c) {
return rb_struct_new(klass, a, b, c);
}
-static VALUE struct_spec_rb_struct_size(VALUE self, VALUE st)
-{
+static VALUE struct_spec_rb_struct_size(VALUE self, VALUE st) {
return rb_struct_size(st);
}
diff --git a/spec/ruby/optional/capi/ext/symbol_spec.c b/spec/ruby/optional/capi/ext/symbol_spec.c
index 7d9a7b4379..ba88635faa 100644
--- a/spec/ruby/optional/capi/ext/symbol_spec.c
+++ b/spec/ruby/optional/capi/ext/symbol_spec.c
@@ -47,10 +47,19 @@ VALUE symbol_spec_rb_id2name(VALUE self, VALUE symbol) {
return rb_str_new(c_str, strlen(c_str));
}
+VALUE symbol_spec_rb_id2name_id_zero(VALUE self) {
+ const char* c_str = rb_id2name((ID) 0);
+ return c_str ? rb_str_new(c_str, strlen(c_str)) : Qnil;
+}
+
VALUE symbol_spec_rb_id2str(VALUE self, VALUE symbol) {
return rb_id2str(SYM2ID(symbol));
}
+VALUE symbol_spec_rb_id2str_id_zero(VALUE self) {
+ return rb_id2str((ID) 0);
+}
+
VALUE symbol_spec_rb_intern_str(VALUE self, VALUE str) {
return ID2SYM(rb_intern_str(str));
}
@@ -90,7 +99,9 @@ void Init_symbol_spec(void) {
rb_define_method(cls, "rb_intern3", symbol_spec_rb_intern3, 3);
rb_define_method(cls, "rb_intern3_c_compare", symbol_spec_rb_intern3_c_compare, 4);
rb_define_method(cls, "rb_id2name", symbol_spec_rb_id2name, 1);
+ rb_define_method(cls, "rb_id2name_id_zero", symbol_spec_rb_id2name_id_zero, 0);
rb_define_method(cls, "rb_id2str", symbol_spec_rb_id2str, 1);
+ rb_define_method(cls, "rb_id2str_id_zero", symbol_spec_rb_id2str_id_zero, 0);
rb_define_method(cls, "rb_intern_str", symbol_spec_rb_intern_str, 1);
rb_define_method(cls, "rb_check_symbol_cstr", symbol_spec_rb_check_symbol_cstr, 1);
rb_define_method(cls, "rb_is_class_id", symbol_spec_rb_is_class_id, 1);
diff --git a/spec/ruby/optional/capi/ext/thread_spec.c b/spec/ruby/optional/capi/ext/thread_spec.c
index bab5fcc211..3511c2fbcf 100644
--- a/spec/ruby/optional/capi/ext/thread_spec.c
+++ b/spec/ruby/optional/capi/ext/thread_spec.c
@@ -8,7 +8,10 @@
#include <unistd.h>
#endif
#if defined(_WIN32)
-#define pipe(p) rb_w32_pipe(p)
+#include "ruby/win32.h"
+#define read rb_w32_read
+#define write rb_w32_write
+#define pipe rb_w32_pipe
#endif
#ifndef _WIN32
@@ -23,10 +26,6 @@ static VALUE thread_spec_rb_thread_alone(VALUE self) {
return rb_thread_alone() ? Qtrue : Qfalse;
}
-#if defined(__GNUC__)
-#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
-#endif
-
/* This is unblocked by unblock_func(). */
static void* blocking_gvl_func(void* data) {
int rfd = *(int *)data;
@@ -68,7 +67,7 @@ static VALUE thread_spec_rb_thread_call_without_gvl(VALUE self) {
}
/* This is unblocked by a signal. */
-static void* blocking_gvl_func_for_udf_io(void *data) {
+static void* blocking_gvl_func_for_ubf_io(void *data) {
int rfd = (int)(size_t)data;
char dummy;
@@ -88,7 +87,7 @@ static VALUE thread_spec_rb_thread_call_without_gvl_with_ubf_io(VALUE self) {
rb_raise(rb_eRuntimeError, "could not create pipe");
}
- ret = rb_thread_call_without_gvl(blocking_gvl_func_for_udf_io,
+ ret = rb_thread_call_without_gvl(blocking_gvl_func_for_ubf_io,
(void*)(size_t)fds[0], RUBY_UBF_IO, 0);
close(fds[0]);
close(fds[1]);
@@ -143,6 +142,7 @@ static VALUE thread_spec_ruby_native_thread_p(VALUE self) {
}
}
+#ifndef _WIN32
static VALUE false_result = Qfalse;
static VALUE true_result = Qtrue;
@@ -153,14 +153,15 @@ static void *new_thread_check(void *args) {
return &false_result;
}
}
+#endif
static VALUE thread_spec_ruby_native_thread_p_new_thread(VALUE self) {
#ifndef _WIN32
pthread_t t;
- VALUE *result = &true_result;
+ void *result = &true_result;
pthread_create(&t, NULL, new_thread_check, NULL);
- pthread_join(t, (void **)&result);
- return *result;
+ pthread_join(t, &result);
+ return *(VALUE *)result;
#else
return Qfalse;
#endif
diff --git a/spec/ruby/optional/capi/ext/tracepoint_spec.c b/spec/ruby/optional/capi/ext/tracepoint_spec.c
index 78c459d6cb..6666c8f85c 100644
--- a/spec/ruby/optional/capi/ext/tracepoint_spec.c
+++ b/spec/ruby/optional/capi/ext/tracepoint_spec.c
@@ -17,7 +17,7 @@ static VALUE tracepoint_spec_rb_tracepoint_new(VALUE self, VALUE data) {
return rb_tracepoint_new(Qnil, RUBY_EVENT_LINE, callback, (void*) data);
}
-static VALUE tracepoint_spec_callback_called(VALUE self){
+static VALUE tracepoint_spec_callback_called(VALUE self) {
return callback_called;
}
diff --git a/spec/ruby/optional/capi/ext/typed_data_spec.c b/spec/ruby/optional/capi/ext/typed_data_spec.c
index eca2b667cc..38889ecf5c 100644
--- a/spec/ruby/optional/capi/ext/typed_data_spec.c
+++ b/spec/ruby/optional/capi/ext/typed_data_spec.c
@@ -106,6 +106,12 @@ VALUE sws_typed_wrap_struct(VALUE self, VALUE val) {
return TypedData_Wrap_Struct(rb_cObject, &sample_typed_wrapped_struct_data_type, bar);
}
+VALUE sws_untyped_wrap_struct(VALUE self, VALUE val) {
+ int* data = (int*) malloc(sizeof(int));
+ *data = FIX2INT(val);
+ return Data_Wrap_Struct(rb_cObject, NULL, free, data);
+}
+
VALUE sws_typed_get_struct(VALUE self, VALUE obj) {
struct sample_typed_wrapped_struct* bar;
TypedData_Get_Struct(obj, struct sample_typed_wrapped_struct, &sample_typed_wrapped_struct_data_type, bar);
@@ -165,12 +171,17 @@ VALUE sws_typed_rb_check_typeddata_different_type(VALUE self, VALUE obj) {
return rb_check_typeddata(obj, &sample_typed_wrapped_struct_other_data_type) == DATA_PTR(obj) ? Qtrue : Qfalse;
}
+VALUE sws_typed_RTYPEDDATA_P(VALUE self, VALUE obj) {
+ return RTYPEDDATA_P(obj) ? Qtrue : Qfalse;
+}
+
void Init_typed_data_spec(void) {
VALUE cls = rb_define_class("CApiAllocTypedSpecs", rb_cObject);
rb_define_alloc_func(cls, sdaf_alloc_typed_func);
rb_define_method(cls, "typed_wrapped_data", sdaf_typed_get_struct, 0);
cls = rb_define_class("CApiWrappedTypedStructSpecs", rb_cObject);
rb_define_method(cls, "typed_wrap_struct", sws_typed_wrap_struct, 1);
+ rb_define_method(cls, "untyped_wrap_struct", sws_untyped_wrap_struct, 1);
rb_define_method(cls, "typed_get_struct", sws_typed_get_struct, 1);
rb_define_method(cls, "typed_get_struct_other", sws_typed_get_struct_different_type, 1);
rb_define_method(cls, "typed_get_struct_parent", sws_typed_get_struct_parent_type, 1);
@@ -181,6 +192,7 @@ void Init_typed_data_spec(void) {
rb_define_method(cls, "rb_check_typeddata_same_type", sws_typed_rb_check_typeddata_same_type, 1);
rb_define_method(cls, "rb_check_typeddata_same_type_parent", sws_typed_rb_check_typeddata_same_type_parent, 1);
rb_define_method(cls, "rb_check_typeddata_different_type", sws_typed_rb_check_typeddata_different_type, 1);
+ rb_define_method(cls, "RTYPEDDATA_P", sws_typed_RTYPEDDATA_P, 1);
}
#ifdef __cplusplus
diff --git a/spec/ruby/optional/capi/ext/util_spec.c b/spec/ruby/optional/capi/ext/util_spec.c
index a7269353c2..b5bde420d2 100644
--- a/spec/ruby/optional/capi/ext/util_spec.c
+++ b/spec/ruby/optional/capi/ext/util_spec.c
@@ -7,15 +7,18 @@ extern "C" {
#endif
VALUE util_spec_rb_scan_args(VALUE self, VALUE argv, VALUE fmt, VALUE expected, VALUE acc) {
- int i, result, argc = (int)RARRAY_LEN(argv);
- VALUE args[6], failed, a1, a2, a3, a4, a5, a6;
+ int result, argc;
+ VALUE a1, a2, a3, a4, a5, a6;
- failed = rb_intern("failed");
- a1 = a2 = a3 = a4 = a5 = a6 = failed;
+ argc = (int) RARRAY_LEN(argv);
+ VALUE* args = RARRAY_PTR(argv);
+ /* the line above can be replaced with this for Ruby implementations which do not support RARRAY_PTR() yet
+ VALUE args[6];
+ for(int i = 0; i < argc; i++) {
+ args[i] = rb_ary_entry(argv, i);
+ } */
- for(i = 0; i < argc; i++) {
- args[i] = rb_ary_entry(argv, i);
- }
+ a1 = a2 = a3 = a4 = a5 = a6 = INT2FIX(-1);
#ifdef RB_SCAN_ARGS_KEYWORDS
if (*RSTRING_PTR(fmt) == 'k') {
@@ -59,22 +62,17 @@ static VALUE util_spec_rb_get_kwargs(VALUE self, VALUE keyword_hash, VALUE keys,
int len = RARRAY_LENINT(keys);
int values_len = req + (opt < 0 ? -1 - opt : opt);
- int i = 0;
- ID *ids = (ID*) malloc(sizeof(VALUE) * len);
- VALUE *results = (VALUE*) malloc(sizeof(VALUE) * values_len);
- int extracted = 0;
- VALUE ary = Qundef;
+ ID *ids = (ID *)alloca(sizeof(VALUE) * len);
+ VALUE *results = (VALUE *)alloca(sizeof(VALUE) * values_len);
- for (i = 0; i < len; i++) {
+ for (int i = 0; i < len; i++) {
ids[i] = SYM2ID(rb_ary_entry(keys, i));
}
- extracted = rb_get_kwargs(keyword_hash, ids, req, opt, results);
- ary = rb_ary_new_from_values(extracted, results);
- free(results);
- free(ids);
- return ary;
+ int extracted = rb_get_kwargs(keyword_hash, ids, req, opt, results);
+
+ return rb_ary_new_from_values(extracted, results);
}
static VALUE util_spec_rb_long2int(VALUE self, VALUE n) {
diff --git a/spec/ruby/optional/capi/file_spec.rb b/spec/ruby/optional/capi/file_spec.rb
index 96d731e4fa..12449b4e34 100644
--- a/spec/ruby/optional/capi/file_spec.rb
+++ b/spec/ruby/optional/capi/file_spec.rb
@@ -69,7 +69,7 @@ describe "C-API File function" do
end
it "does not call #to_str on a String" do
- obj = "path"
+ obj = +"path"
obj.should_not_receive(:to_str)
@s.FilePathValue(obj).should eql(obj)
end
diff --git a/spec/ruby/optional/capi/fixtures/class.rb b/spec/ruby/optional/capi/fixtures/class.rb
index 193c7174e0..b463e3b4c3 100644
--- a/spec/ruby/optional/capi/fixtures/class.rb
+++ b/spec/ruby/optional/capi/fixtures/class.rb
@@ -15,6 +15,16 @@ class CApiClassSpecs
end
end
+ class KeywordAlloc
+ attr_reader :initialized, :args, :kwargs
+
+ def initialize(*args, **kwargs)
+ @initialized = true
+ @args = args
+ @kwargs = kwargs
+ end
+ end
+
class Attr
def initialize
@foo, @bar, @baz = 1, 2, 3
diff --git a/spec/ruby/optional/capi/fixtures/kernel.rb b/spec/ruby/optional/capi/fixtures/kernel.rb
new file mode 100644
index 0000000000..d3fc7c57e8
--- /dev/null
+++ b/spec/ruby/optional/capi/fixtures/kernel.rb
@@ -0,0 +1,19 @@
+class CApiKernelSpecs
+ class ClassWithPublicMethod
+ def public_method(*, **)
+ :public
+ end
+ end
+
+ class ClassWithPrivateMethod
+ private def private_method(*, **)
+ :private
+ end
+ end
+
+ class ClassWithProtectedMethod
+ protected def protected_method(*, **)
+ :protected
+ end
+ end
+end
diff --git a/spec/ruby/optional/capi/fixtures/object.rb b/spec/ruby/optional/capi/fixtures/object.rb
new file mode 100644
index 0000000000..a59f2309d8
--- /dev/null
+++ b/spec/ruby/optional/capi/fixtures/object.rb
@@ -0,0 +1,29 @@
+class CApiObjectSpecs
+ class IVars
+ def initialize
+ @a = 3
+ @b = 7
+ @c = 4
+ end
+
+ def self.set_class_variables
+ @@foo = :a
+ @@bar = :b
+ @@baz = :c
+ end
+ end
+
+ module MVars
+ @@mvar = :foo
+ @@mvar2 = :bar
+
+ @ivar = :baz
+ end
+
+ module CVars
+ @@cvar = :foo
+ @@cvar2 = :bar
+
+ @ivar = :baz
+ end
+end
diff --git a/spec/ruby/optional/capi/gc_spec.rb b/spec/ruby/optional/capi/gc_spec.rb
index 23e2b7c9ab..aaced56483 100644
--- a/spec/ruby/optional/capi/gc_spec.rb
+++ b/spec/ruby/optional/capi/gc_spec.rb
@@ -7,15 +7,60 @@ describe "CApiGCSpecs" do
@f = CApiGCSpecs.new
end
- it "correctly gets the value from a registered address" do
- @f.registered_tagged_address.should == 10
- @f.registered_tagged_address.should equal(@f.registered_tagged_address)
- @f.registered_reference_address.should == "Globally registered data"
- @f.registered_reference_address.should equal(@f.registered_reference_address)
+ describe "rb_gc_register_address" do
+ it "correctly gets the value from a registered address" do
+ @f.registered_tagged_address.should == 10
+ @f.registered_tagged_address.should equal(@f.registered_tagged_address)
+ @f.registered_reference_address.should == "Globally registered data"
+ @f.registered_reference_address.should equal(@f.registered_reference_address)
+ end
+
+ it "keeps the value alive even if the value is assigned after rb_gc_register_address() is called" do
+ GC.start
+ @f.registered_before_rb_gc_register_address.should == "registered before rb_gc_register_address()"
+ end
+
+ it "can be called outside Init_" do
+ @f.rb_gc_register_address.should == "rb_gc_register_address() outside Init_"
+ @f.rb_gc_unregister_address
+ end
end
- describe "rb_gc_enable" do
+ describe "rb_global_variable" do
+ before :all do
+ GC.start
+ end
+
+ describe "keeps the value alive even if the value is assigned after rb_global_variable() is called" do
+ it "for a string" do
+ @f.registered_before_rb_global_variable_string.should == "registered before rb_global_variable()"
+ end
+
+ it "for a bignum" do
+ @f.registered_before_rb_global_variable_bignum.should == 2**63 - 1
+ end
+ it "for a Float" do
+ @f.registered_before_rb_global_variable_float.should == 3.14
+ end
+ end
+
+ describe "keeps the value alive when the value is assigned before rb_global_variable() is called" do
+ it "for a string" do
+ @f.registered_after_rb_global_variable_string.should == "registered after rb_global_variable()"
+ end
+
+ it "for a bignum" do
+ @f.registered_after_rb_global_variable_bignum.should == 2**63 - 1
+ end
+
+ it "for a Float" do
+ @f.registered_after_rb_global_variable_float.should == 6.28
+ end
+ end
+ end
+
+ describe "rb_gc_enable" do
after do
GC.enable
end
diff --git a/spec/ruby/optional/capi/globals_spec.rb b/spec/ruby/optional/capi/globals_spec.rb
index cc6f6ef3a8..48677620bc 100644
--- a/spec/ruby/optional/capi/globals_spec.rb
+++ b/spec/ruby/optional/capi/globals_spec.rb
@@ -9,7 +9,7 @@ describe "CApiGlobalSpecs" do
end
it "correctly gets global values" do
- @f.sb_gv_get("$BLAH").should == nil
+ suppress_warning { @f.sb_gv_get("$BLAH") }.should == nil
@f.sb_gv_get("$\\").should == nil
@f.sb_gv_get("\\").should == nil # rb_gv_get should change \ to $\
end
@@ -21,7 +21,7 @@ describe "CApiGlobalSpecs" do
end
it "correctly sets global values" do
- @f.sb_gv_get("$BLAH").should == nil
+ suppress_warning { @f.sb_gv_get("$BLAH") }.should == nil
@f.sb_gv_set("$BLAH", 10)
begin
@f.sb_gv_get("$BLAH").should == 10
@@ -42,6 +42,10 @@ describe "CApiGlobalSpecs" do
end
it "rb_define_readonly_variable should define a new readonly global variable" do
+ # Check the gvar doesn't exist and ensure rb_gv_get doesn't implicitly declare the gvar,
+ # otherwise the rb_define_readonly_variable call will conflict.
+ suppress_warning { @f.sb_gv_get("ro_gvar") } .should == nil
+
@f.rb_define_readonly_variable("ro_gvar", 15)
$ro_gvar.should == 15
-> { $ro_gvar = 10 }.should raise_error(NameError)
@@ -53,6 +57,52 @@ describe "CApiGlobalSpecs" do
$hooked_gvar.should == 4
end
+ it "rb_define_hooked_variable should use default accessors if NULL ones are supplied" do
+ @f.rb_define_hooked_variable_default_accessors("$hooked_gvar_default_accessors")
+ $hooked_gvar_default_accessors = 10
+ $hooked_gvar_default_accessors.should == 10
+ end
+
+ it "rb_define_hooked_variable with default accessors should return nil for NULL variables" do
+ @f.rb_define_hooked_variable_null_var("$hooked_gvar_null_value")
+ $hooked_gvar_null_value.should == nil
+ end
+
+ describe "rb_define_virtual_variable" do
+ describe "with default accessors" do
+ before :all do
+ @f.rb_define_virtual_variable_default_accessors("$virtual_variable_default_accessors")
+ end
+
+ it "is read-only" do
+ -> { $virtual_variable_default_accessors = 10 }.should raise_error(NameError, /read-only/)
+ end
+
+ it "returns false with the default getter" do
+ $virtual_variable_default_accessors.should == false
+ $virtual_variable_default_accessors.should == false
+ end
+ end
+
+ describe "with supplied accessors" do
+ before :all do
+ @f.rb_define_virtual_variable_incrementing_accessors("$virtual_variable_incrementing_accessors")
+ end
+
+ it "returns a dynamically changing value" do
+ $virtual_variable_incrementing_accessors = 20
+ $virtual_variable_incrementing_accessors.should == 20
+ $virtual_variable_incrementing_accessors.should == 21
+ $virtual_variable_incrementing_accessors.should == 22
+
+ $virtual_variable_incrementing_accessors = 100
+ $virtual_variable_incrementing_accessors.should == 100
+ $virtual_variable_incrementing_accessors.should == 101
+ $virtual_variable_incrementing_accessors.should == 102
+ end
+ end
+ end
+
describe "rb_fs" do
before :each do
@field_separator = $;
diff --git a/spec/ruby/optional/capi/hash_spec.rb b/spec/ruby/optional/capi/hash_spec.rb
index a60467a66b..a0e49ffc4c 100644
--- a/spec/ruby/optional/capi/hash_spec.rb
+++ b/spec/ruby/optional/capi/hash_spec.rb
@@ -50,6 +50,22 @@ describe "C-API Hash function" do
end
end
+ ruby_version_is '3.2' do
+ describe "rb_hash_new_capa" do
+ it "returns a new hash" do
+ @s.rb_hash_new_capa(3).should == {}
+ end
+
+ it "creates a hash with no default proc" do
+ @s.rb_hash_new_capa(3) {}.default_proc.should be_nil
+ end
+
+ it "raises RuntimeError when negative index is provided" do
+ -> { @s.rb_hash_new_capa(-1) }.should raise_error(RuntimeError, "st_table too big")
+ end
+ end
+ end
+
describe "rb_ident_hash_new" do
it "returns a new compare by identity hash" do
result = @s.rb_ident_hash_new
diff --git a/spec/ruby/optional/capi/integer_spec.rb b/spec/ruby/optional/capi/integer_spec.rb
index e26735824e..089872381c 100644
--- a/spec/ruby/optional/capi/integer_spec.rb
+++ b/spec/ruby/optional/capi/integer_spec.rb
@@ -140,6 +140,23 @@ describe "CApiIntegerSpecs" do
result.should == -1
@words.should == "\x11\x32\x54\x76\x98\xBA\xDC\xFE"
end
+
+ it "converts numbers near the fixnum limit successfully" do
+ result = @s.rb_integer_pack(0x7123_4567_89ab_cdef, @words, 1, 8, 0,
+ CApiIntegerSpecs::NATIVE|CApiIntegerSpecs::PACK_2COMP)
+ result.should == 1
+ @words.should == "\xEF\xCD\xAB\x89\x67\x45\x23\x71"
+
+ result = @s.rb_integer_pack(2**62-1, @words, 1, 8, 0,
+ CApiIntegerSpecs::NATIVE|CApiIntegerSpecs::PACK_2COMP)
+ result.should == 1
+ @words.should == "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x3F"
+
+ result = @s.rb_integer_pack(2**63-1, @words, 1, 8, 0,
+ CApiIntegerSpecs::NATIVE|CApiIntegerSpecs::PACK_2COMP)
+ result.should == 1
+ @words.should == "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F"
+ end
end
end
end
diff --git a/spec/ruby/optional/capi/io_spec.rb b/spec/ruby/optional/capi/io_spec.rb
index 489a01c515..870abef3ea 100644
--- a/spec/ruby/optional/capi/io_spec.rb
+++ b/spec/ruby/optional/capi/io_spec.rb
@@ -175,13 +175,18 @@ describe "C-API IO function" do
end
end
- describe "GetOpenFile" do
+ describe "rb_io_descriptor or GetOpenFile" do
it "allows access to the system fileno" do
@o.GetOpenFile_fd($stdin).should == 0
@o.GetOpenFile_fd($stdout).should == 1
@o.GetOpenFile_fd($stderr).should == 2
@o.GetOpenFile_fd(@io).should == @io.fileno
end
+
+ it "raises IOError if the IO is closed" do
+ @io.close
+ -> { @o.GetOpenFile_fd(@io) }.should raise_error(IOError, "closed stream")
+ end
end
describe "rb_io_binmode" do
@@ -256,12 +261,48 @@ describe "C-API IO function" do
end
end
+ ruby_version_is "3.1" do
+ describe "rb_io_maybe_wait_writable" do
+ it "returns mask for events if operation was interrupted" do
+ @o.rb_io_maybe_wait_writable(Errno::EINTR::Errno, @w_io, nil).should == IO::WRITABLE
+ end
+
+ it "returns 0 if there is no error condition" do
+ @o.rb_io_maybe_wait_writable(0, @w_io, nil).should == 0
+ end
+
+ it "raises an IOError if the IO is closed" do
+ @w_io.close
+ -> { @o.rb_io_maybe_wait_writable(0, @w_io, nil) }.should raise_error(IOError, "closed stream")
+ end
+
+ it "raises an IOError if the IO is not initialized" do
+ -> { @o.rb_io_maybe_wait_writable(0, IO.allocate, nil) }.should raise_error(IOError, "uninitialized stream")
+ end
+ end
+ end
+
describe "rb_thread_fd_writable" do
it "waits til an fd is ready for writing" do
@o.rb_thread_fd_writable(@w_io).should be_nil
end
end
+ describe "rb_thread_fd_select" do
+ it "waits until an fd is ready for reading" do
+ @w_io.write "rb_thread_fd_select"
+ @o.rb_thread_fd_select_read(@r_io).should == 1
+ end
+
+ it "waits until an fd is ready for writing" do
+ @o.rb_thread_fd_select_write(@w_io).should == 1
+ end
+
+ it "waits until an fd is ready for writing with timeout" do
+ @o.rb_thread_fd_select_timeout(@w_io).should == 1
+ end
+ end
+
platform_is_not :windows do
describe "rb_io_wait_readable" do
it "returns false if there is no error condition" do
@@ -290,6 +331,40 @@ describe "C-API IO function" do
thr.join
end
end
+
+ ruby_version_is "3.1" do
+ describe "rb_io_maybe_wait_readable" do
+ it "returns mask for events if operation was interrupted" do
+ @o.rb_io_maybe_wait_readable(Errno::EINTR::Errno, @r_io, nil, false).should == IO::READABLE
+ end
+
+ it "returns 0 if there is no error condition" do
+ @o.rb_io_maybe_wait_readable(0, @r_io, nil, false).should == 0
+ end
+
+ it "blocks until the io is readable and returns events that actually occurred" do
+ @o.instance_variable_set :@write_data, false
+ thr = Thread.new do
+ Thread.pass until @o.instance_variable_get(:@write_data)
+ @w_io.write "rb_io_wait_readable"
+ end
+
+ @o.rb_io_maybe_wait_readable(Errno::EAGAIN::Errno, @r_io, IO::READABLE, true).should == IO::READABLE
+ @o.instance_variable_get(:@read_data).should == "rb_io_wait_re"
+
+ thr.join
+ end
+
+ it "raises an IOError if the IO is closed" do
+ @r_io.close
+ -> { @o.rb_io_maybe_wait_readable(0, @r_io, nil, false) }.should raise_error(IOError, "closed stream")
+ end
+
+ it "raises an IOError if the IO is not initialized" do
+ -> { @o.rb_io_maybe_wait_readable(0, IO.allocate, nil, false) }.should raise_error(IOError, "uninitialized stream")
+ end
+ end
+ end
end
describe "rb_thread_wait_fd" do
@@ -329,10 +404,63 @@ describe "C-API IO function" do
@o.rb_wait_for_single_fd(@r_io, 1, 0, 0).should == 0
end
end
+
+ ruby_version_is "3.1" do
+ describe "rb_io_maybe_wait" do
+ it "waits til an fd is ready for reading" do
+ start = false
+ thr = Thread.new do
+ start = true
+ sleep 0.05
+ @w_io.write "rb_io_maybe_wait"
+ end
+
+ Thread.pass until start
+
+ @o.rb_io_maybe_wait(Errno::EAGAIN::Errno, @r_io, IO::READABLE, nil).should == IO::READABLE
+
+ thr.join
+ end
+
+ it "returns mask for events if operation was interrupted" do
+ @o.rb_io_maybe_wait(Errno::EINTR::Errno, @w_io, IO::WRITABLE, nil).should == IO::WRITABLE
+ end
+
+ it "returns false if there is no error condition" do
+ @o.rb_io_maybe_wait(0, @w_io, IO::WRITABLE, nil).should == false
+ end
+
+ it "raises an IOError if the IO is closed" do
+ @w_io.close
+ -> { @o.rb_io_maybe_wait(0, @w_io, IO::WRITABLE, nil) }.should raise_error(IOError, "closed stream")
+ end
+
+ it "raises an IOError if the IO is not initialized" do
+ -> { @o.rb_io_maybe_wait(0, IO.allocate, IO::WRITABLE, nil) }.should raise_error(IOError, "uninitialized stream")
+ end
+ end
+ end
+
+ ruby_version_is "3.3" do
+ describe "rb_io_mode" do
+ it "returns the mode" do
+ (@o.rb_io_mode(@r_io) & 0b11).should == 0b01
+ (@o.rb_io_mode(@w_io) & 0b11).should == 0b10
+ (@o.rb_io_mode(@rw_io) & 0b11).should == 0b11
+ end
+ end
+
+ describe "rb_io_path" do
+ it "returns the IO#path" do
+ @o.rb_io_path(@r_io).should == @r_io.path
+ @o.rb_io_path(@rw_io).should == @rw_io.path
+ @o.rb_io_path(@rw_io).should == @name
+ end
+ end
+ end
end
describe "rb_fd_fix_cloexec" do
-
before :each do
@o = CApiIOSpecs.new
diff --git a/spec/ruby/optional/capi/kernel_spec.rb b/spec/ruby/optional/capi/kernel_spec.rb
index 758d944da9..3b61d4f0f1 100644
--- a/spec/ruby/optional/capi/kernel_spec.rb
+++ b/spec/ruby/optional/capi/kernel_spec.rb
@@ -1,4 +1,5 @@
require_relative 'spec_helper'
+require_relative 'fixtures/kernel'
kernel_path = load_extension("kernel")
@@ -412,12 +413,10 @@ describe "C-API Kernel function" do
}.should raise_error(Exception, 'custom error')
end
- ruby_bug "#17305", ""..."2.7" do
- it "raises TypeError if one of the passed exceptions is not a Module" do
- -> {
- @s.rb_rescue2(-> *_ { raise RuntimeError, "foo" }, :no_exc, -> x { x }, :exc, Object.new, 42)
- }.should raise_error(TypeError, /class or module required/)
- end
+ it "raises TypeError if one of the passed exceptions is not a Module" do
+ -> {
+ @s.rb_rescue2(-> *_ { raise RuntimeError, "foo" }, :no_exc, -> x { x }, :exc, Object.new, 42)
+ }.should raise_error(TypeError, /class or module required/)
end
end
@@ -504,6 +503,30 @@ describe "C-API Kernel function" do
it "evaluates a string of ruby code" do
@s.rb_eval_string("1+1").should == 2
end
+
+ it "captures local variables when called within a method" do
+ a = 2
+ @s.rb_eval_string("a+1").should == 3
+ end
+ end
+
+ describe "rb_eval_cmd_kw" do
+ it "evaluates a string of ruby code" do
+ @s.rb_eval_cmd_kw("1+1", [], 0).should == 2
+ end
+
+ it "calls a proc with the supplied arguments" do
+ @s.rb_eval_cmd_kw(-> *x { x.map { |i| i + 1 } }, [1, 3, 7], 0).should == [2, 4, 8]
+ end
+
+ it "calls a proc with keyword arguments if kw_splat is non zero" do
+ a_proc = -> *x, **y {
+ res = x.map { |i| i + 1 }
+ y.each { |k, v| res << k; res << v }
+ res
+ }
+ @s.rb_eval_cmd_kw(a_proc, [1, 3, 7, {a: 1, b: 2, c: 3}], 1).should == [2, 4, 8, :a, 1, :b, 2, :c, 3]
+ end
end
describe "rb_block_proc" do
@@ -567,7 +590,82 @@ describe "C-API Kernel function" do
end
end
- describe "rb_funcall3" do
+ describe "rb_funcallv" do
+ def empty
+ 42
+ end
+
+ def sum(a, b)
+ a + b
+ end
+
+ it "calls a method" do
+ @s.rb_funcallv(self, :empty, []).should == 42
+ @s.rb_funcallv(self, :sum, [1, 2]).should == 3
+ end
+
+ it "calls a private method" do
+ object = CApiKernelSpecs::ClassWithPrivateMethod.new
+ @s.rb_funcallv(object, :private_method, []).should == :private
+ end
+
+ it "calls a protected method" do
+ object = CApiKernelSpecs::ClassWithProtectedMethod.new
+ @s.rb_funcallv(object, :protected_method, []).should == :protected
+ end
+ end
+
+ describe "rb_funcallv_kw" do
+ it "passes keyword arguments to the callee" do
+ def m(*args, **kwargs)
+ [args, kwargs]
+ end
+
+ @s.rb_funcallv_kw(self, :m, [{}]).should == [[], {}]
+ @s.rb_funcallv_kw(self, :m, [{a: 1}]).should == [[], {a: 1}]
+ @s.rb_funcallv_kw(self, :m, [{b: 2}, {a: 1}]).should == [[{b: 2}], {a: 1}]
+ @s.rb_funcallv_kw(self, :m, [{b: 2}, {}]).should == [[{b: 2}], {}]
+ end
+
+ it "calls a private method" do
+ object = CApiKernelSpecs::ClassWithPrivateMethod.new
+ @s.rb_funcallv_kw(object, :private_method, [{}]).should == :private
+ end
+
+ it "calls a protected method" do
+ object = CApiKernelSpecs::ClassWithProtectedMethod.new
+ @s.rb_funcallv_kw(object, :protected_method, [{}]).should == :protected
+ end
+
+ it "raises TypeError if the last argument is not a Hash" do
+ def m(*args, **kwargs)
+ [args, kwargs]
+ end
+
+ -> {
+ @s.rb_funcallv_kw(self, :m, [42])
+ }.should raise_error(TypeError, 'no implicit conversion of Integer into Hash')
+ end
+ end
+
+ describe "rb_keyword_given_p" do
+ it "returns whether keywords were given to the C extension method" do
+ h = {a: 1}
+ empty = {}
+ @s.rb_keyword_given_p(a: 1).should == true
+ @s.rb_keyword_given_p("foo" => "bar").should == true
+ @s.rb_keyword_given_p(**h).should == true
+
+ @s.rb_keyword_given_p(h).should == false
+ @s.rb_keyword_given_p().should == false
+ @s.rb_keyword_given_p(**empty).should == false
+
+ @s.rb_funcallv_kw(@s, :rb_keyword_given_p, [{a: 1}]).should == true
+ @s.rb_funcallv_kw(@s, :rb_keyword_given_p, [{}]).should == false
+ end
+ end
+
+ describe "rb_funcallv_public" do
before :each do
@obj = Object.new
class << @obj
@@ -578,10 +676,11 @@ describe "C-API Kernel function" do
end
it "calls a public method" do
- @s.rb_funcall3(@obj, :method_public).should == :method_public
+ @s.rb_funcallv_public(@obj, :method_public).should == :method_public
end
+
it "does not call a private method" do
- -> { @s.rb_funcall3(@obj, :method_private) }.should raise_error(NoMethodError, /private/)
+ -> { @s.rb_funcallv_public(@obj, :method_private) }.should raise_error(NoMethodError, /private/)
end
end
@@ -599,22 +698,93 @@ describe "C-API Kernel function" do
@s.rb_funcall_many_args(@obj, :many_args).should == 15.downto(1).to_a
end
end
+
describe 'rb_funcall_with_block' do
- before :each do
+ it "calls a method with block" do
@obj = Object.new
class << @obj
- def method_public; yield end
- def method_private; yield end
- private :method_private
+ def method_public(*args); [args, yield] end
end
+
+ @s.rb_funcall_with_block(@obj, :method_public, [1, 2], proc { :result }).should == [[1, 2], :result]
end
- it "calls a method with block" do
- @s.rb_funcall_with_block(@obj, :method_public, proc { :result }).should == :result
+ it "does not call a private method" do
+ object = CApiKernelSpecs::ClassWithPrivateMethod.new
+
+ -> {
+ @s.rb_funcall_with_block(object, :private_method, [], proc { })
+ }.should raise_error(NoMethodError, /private/)
+ end
+
+ it "does not call a protected method" do
+ object = CApiKernelSpecs::ClassWithProtectedMethod.new
+
+ -> {
+ @s.rb_funcall_with_block(object, :protected_method, [], proc { })
+ }.should raise_error(NoMethodError, /protected/)
+ end
+ end
+
+ describe 'rb_funcall_with_block_kw' do
+ it "calls a method with keyword arguments and a block" do
+ @obj = Object.new
+ class << @obj
+ def method_public(*args, **kw, &block); [args, kw, block.call] end
+ end
+
+ @s.rb_funcall_with_block_kw(@obj, :method_public, [1, 2, {a: 2}], proc { :result }).should == [[1, 2], {a: 2}, :result]
end
it "does not call a private method" do
- -> { @s.rb_funcall_with_block(@obj, :method_private, proc { :result }) }.should raise_error(NoMethodError, /private/)
+ object = CApiKernelSpecs::ClassWithPrivateMethod.new
+
+ -> {
+ @s.rb_funcall_with_block_kw(object, :private_method, [{}], proc { })
+ }.should raise_error(NoMethodError, /private/)
+ end
+
+ it "does not call a protected method" do
+ object = CApiKernelSpecs::ClassWithProtectedMethod.new
+
+ -> {
+ @s.rb_funcall_with_block_kw(object, :protected_method, [{}], proc { })
+ }.should raise_error(NoMethodError, /protected/)
+ end
+ end
+
+ describe "rb_check_funcall" do
+ it "calls a method" do
+ @s.rb_check_funcall(1, :+, [2]).should == 3
+ end
+
+ it "returns Qundef if the method is not defined" do
+ obj = Object.new
+ @s.rb_check_funcall(obj, :foo, []).should == :Qundef
+ end
+
+ it "uses #respond_to? to check if the method is defined" do
+ ScratchPad.record []
+ obj = Object.new
+ def obj.respond_to?(name, priv)
+ ScratchPad << name
+ name == :foo || super
+ end
+ def obj.method_missing(name, *args)
+ name == :foo ? [name, 42] : super
+ end
+ @s.rb_check_funcall(obj, :foo, []).should == [:foo, 42]
+ ScratchPad.recorded.should == [:foo]
+ end
+
+ it "calls a private method" do
+ object = CApiKernelSpecs::ClassWithPrivateMethod.new
+ @s.rb_check_funcall(object, :private_method, []).should == :private
+ end
+
+ it "calls a protected method" do
+ object = CApiKernelSpecs::ClassWithProtectedMethod.new
+ @s.rb_check_funcall(object, :protected_method, []).should == :protected
end
end
end
diff --git a/spec/ruby/optional/capi/module_spec.rb b/spec/ruby/optional/capi/module_spec.rb
index acf4d1fe48..d7c0ab9c52 100644
--- a/spec/ruby/optional/capi/module_spec.rb
+++ b/spec/ruby/optional/capi/module_spec.rb
@@ -252,22 +252,30 @@ describe "CApiModule" do
cls.new.method(:test_method).arity.should == 0
end
+ it "returns the correct arity when argc of the method in class is 1" do
+ @m.rb_define_method_1required(42).should == 42
+ @m.method(:rb_define_method_1required).arity.should == 1
+ end
+
+ it "returns the correct arity when argc of the method in class is 2" do
+ @m.rb_define_method_2required(1, 2).should == 2
+ @m.method(:rb_define_method_2required).arity.should == 2
+ end
+
+ it "defines a method taking variable arguments as a C array if the argument count is -1" do
+ @m.rb_define_method_varargs_1(1, 3, 7, 4).should == [1, 3, 7, 4]
+ end
+
it "returns the correct arity when argc of the method in class is -1" do
- cls = Class.new
- @m.rb_define_method_c_array(cls, "test_method_c_array")
- cls.new.method(:test_method_c_array).arity.should == -1
+ @m.method(:rb_define_method_varargs_1).arity.should == -1
end
- it "returns the correct arity when argc of the method in class is -2" do
- cls = Class.new
- @m.rb_define_method_ruby_array(cls, "test_method_ruby_array")
- cls.new.method(:test_method_ruby_array).arity.should == -1
+ it "defines a method taking variable arguments as a Ruby array if the argument count is -2" do
+ @m.rb_define_method_varargs_2(1, 3, 7, 4).should == [1, 3, 7, 4]
end
- it "returns the correct arity when argc of the method in class is 2" do
- cls = Class.new
- @m.rb_define_method_2required(cls, "test_method_2required")
- cls.new.method(:test_method_2required).arity.should == 2
+ it "returns the correct arity when argc of the method in class is -2" do
+ @m.method(:rb_define_method_varargs_2).arity.should == -1
end
it "defines a method on a module" do
diff --git a/spec/ruby/optional/capi/object_spec.rb b/spec/ruby/optional/capi/object_spec.rb
index ab11367060..7bc7bd992a 100644
--- a/spec/ruby/optional/capi/object_spec.rb
+++ b/spec/ruby/optional/capi/object_spec.rb
@@ -1,4 +1,5 @@
require_relative 'spec_helper'
+require_relative 'fixtures/object'
load_extension("object")
@@ -30,6 +31,7 @@ describe "CApiObject" do
class ObjectTest
def initialize
@foo = 7
+ yield if block_given?
end
def foo
@@ -88,6 +90,15 @@ describe "CApiObject" do
o.initialized.should be_true
o.arguments.should == [:one, :two]
end
+
+ it "passes the block to #initialize" do
+ v = nil
+ o = @o.rb_obj_alloc(ObjectTest)
+ @o.rb_obj_call_init(o, 0, []) do
+ v = :foo
+ end
+ v.should == :foo
+ end
end
describe "rb_is_instance_of" do
@@ -208,7 +219,7 @@ describe "CApiObject" do
end
it "requires a ruby file" do
- $:.unshift File.dirname(__FILE__)
+ $:.unshift __dir__
@o.rb_require()
$foo.should == 7
end
@@ -438,15 +449,6 @@ describe "CApiObject" do
end
describe "FL_TEST" do
- ruby_version_is ''...'2.7' do
- it "returns correct status for FL_TAINT" do
- obj = Object.new
- @o.FL_TEST(obj, "FL_TAINT").should == 0
- obj.taint
- @o.FL_TEST(obj, "FL_TAINT").should_not == 0
- end
- end
-
it "returns correct status for FL_FREEZE" do
obj = Object.new
@o.FL_TEST(obj, "FL_FREEZE").should == 0
@@ -480,12 +482,31 @@ describe "CApiObject" do
end
end
+ describe "rb_obj_class" do
+ it "returns the class of an object" do
+ @o.rb_obj_class(nil).should == NilClass
+ @o.rb_obj_class(0).should == Integer
+ @o.rb_obj_class(0.1).should == Float
+ @o.rb_obj_class(ObjectTest.new).should == ObjectTest
+ end
+
+ it "does not return the singleton class if it exists" do
+ o = ObjectTest.new
+ o.singleton_class
+ @o.rb_obj_class(o).should equal ObjectTest
+ end
+ end
+
describe "rb_obj_classname" do
it "returns the class name of an object" do
@o.rb_obj_classname(nil).should == 'NilClass'
@o.rb_obj_classname(0).should == 'Integer'
@o.rb_obj_classname(0.1).should == 'Float'
@o.rb_obj_classname(ObjectTest.new).should == 'ObjectTest'
+
+ o = ObjectTest.new
+ o.singleton_class
+ @o.rb_obj_classname(o).should == 'ObjectTest'
end
end
@@ -503,6 +524,21 @@ describe "CApiObject" do
@o.rb_is_type_class(ObjectTest).should == true
@o.rb_is_type_data(Time.now).should == true
end
+
+ it "returns T_FILE for instances of IO and subclasses" do
+ STDERR.class.should == IO
+ @o.rb_is_rb_type_p_file(STDERR).should == true
+
+ File.open(__FILE__) do |f|
+ f.class.should == File
+ @o.rb_is_rb_type_p_file(f).should == true
+ end
+
+ require 'socket'
+ TCPServer.open(0) do |s|
+ @o.rb_is_rb_type_p_file(s).should == true
+ end
+ end
end
describe "rb_check_type" do
@@ -617,68 +653,12 @@ describe "CApiObject" do
end
describe "OBJ_TAINT" do
- ruby_version_is ''...'2.7' do
- it "taints the object" do
- obj = mock("tainted")
- @o.OBJ_TAINT(obj)
- obj.tainted?.should be_true
- end
- end
end
describe "OBJ_TAINTED" do
- ruby_version_is ''...'2.7' do
- it "returns C true if the object is tainted" do
- obj = mock("tainted")
- obj.taint
- @o.OBJ_TAINTED(obj).should be_true
- end
-
- it "returns C false if the object is not tainted" do
- obj = mock("untainted")
- @o.OBJ_TAINTED(obj).should be_false
- end
- end
end
describe "OBJ_INFECT" do
- ruby_version_is ''...'2.7' do
- it "does not taint the first argument if the second argument is not tainted" do
- host = mock("host")
- source = mock("source")
- @o.OBJ_INFECT(host, source)
- host.tainted?.should be_false
- end
-
- it "taints the first argument if the second argument is tainted" do
- host = mock("host")
- source = mock("source").taint
- @o.OBJ_INFECT(host, source)
- host.tainted?.should be_true
- end
-
- it "does not untrust the first argument if the second argument is trusted" do
- host = mock("host")
- source = mock("source")
- @o.OBJ_INFECT(host, source)
- host.untrusted?.should be_false
- end
-
- it "untrusts the first argument if the second argument is untrusted" do
- host = mock("host")
- source = mock("source").untrust
- @o.OBJ_INFECT(host, source)
- host.untrusted?.should be_true
- end
-
- it "propagates both taint and distrust" do
- host = mock("host")
- source = mock("source").taint.untrust
- @o.OBJ_INFECT(host, source)
- host.tainted?.should be_true
- host.untrusted?.should be_true
- end
- end
end
describe "rb_obj_freeze" do
@@ -706,24 +686,12 @@ describe "CApiObject" do
end
it "returns false if object passed to it is not frozen" do
- obj = ""
+ obj = +""
@o.rb_obj_frozen_p(obj).should == false
end
end
describe "rb_obj_taint" do
- ruby_version_is ''...'2.7' do
- it "marks the object passed as tainted" do
- obj = ""
- obj.should_not.tainted?
- @o.rb_obj_taint(obj)
- obj.should.tainted?
- end
-
- it "raises a FrozenError if the object passed is frozen" do
- -> { @o.rb_obj_taint("".freeze) }.should raise_error(FrozenError)
- end
- end
end
describe "rb_check_frozen" do
@@ -732,7 +700,7 @@ describe "CApiObject" do
end
it "does nothing when object isn't frozen" do
- obj = ""
+ obj = +""
-> { @o.rb_check_frozen(obj) }.should_not raise_error(TypeError)
end
end
@@ -926,9 +894,9 @@ describe "CApiObject" do
describe "rb_copy_generic_ivar for objects which do not store ivars directly" do
it "copies the instance variables from one object to another" do
- original = "abc"
+ original = +"abc"
original.instance_variable_set(:@foo, :bar)
- clone = "def"
+ clone = +"def"
@o.rb_copy_generic_ivar(clone, original)
clone.instance_variable_get(:@foo).should == :bar
end
@@ -936,7 +904,7 @@ describe "CApiObject" do
describe "rb_free_generic_ivar for objects which do not store ivars directly" do
it "removes the instance variables from an object" do
- o = "abc"
+ o = +"abc"
o.instance_variable_set(:@baz, :flibble)
@o.rb_free_generic_ivar(o)
o.instance_variables.should == []
@@ -1016,5 +984,30 @@ describe "CApiObject" do
@o.speced_allocator?(parent).should == true
end
end
+
+ describe "rb_ivar_foreach" do
+ it "calls the callback function for each instance variable on an object" do
+ o = CApiObjectSpecs::IVars.new
+ ary = @o.rb_ivar_foreach(o)
+ ary.should == [:@a, 3, :@b, 7, :@c, 4]
+ end
+
+ it "calls the callback function for each cvar and ivar on a class" do
+ exp = [:@@cvar, :foo, :@@cvar2, :bar, :@ivar, :baz]
+ exp.unshift(:__classpath__, 'CApiObjectSpecs::CVars') if RUBY_VERSION < "3.3"
+
+ ary = @o.rb_ivar_foreach(CApiObjectSpecs::CVars)
+ ary.should == exp
+ end
+
+ it "calls the callback function for each cvar and ivar on a module" do
+ exp = [:@@mvar, :foo, :@@mvar2, :bar, :@ivar, :baz]
+ exp.unshift(:__classpath__, 'CApiObjectSpecs::MVars') if RUBY_VERSION < "3.3"
+
+ ary = @o.rb_ivar_foreach(CApiObjectSpecs::MVars)
+ ary.should == exp
+ end
+
+ end
end
end
diff --git a/spec/ruby/optional/capi/proc_spec.rb b/spec/ruby/optional/capi/proc_spec.rb
index dab143fbe7..8b94432f3e 100644
--- a/spec/ruby/optional/capi/proc_spec.rb
+++ b/spec/ruby/optional/capi/proc_spec.rb
@@ -82,6 +82,59 @@ describe "C-API Proc function" do
end
end
+ describe "rb_proc_call_kw" do
+ it "passes keyword arguments to the proc" do
+ prc = proc { |*args, **kw| [args, kw] }
+
+ @p.rb_proc_call_kw(prc, [{}]).should == [[], {}]
+ @p.rb_proc_call_kw(prc, [{a: 1}]).should == [[], {a: 1}]
+ @p.rb_proc_call_kw(prc, [{b: 2}, {a: 1}]).should == [[{b: 2}], {a: 1}]
+ @p.rb_proc_call_kw(prc, [{b: 2}, {}]).should == [[{b: 2}], {}]
+ end
+
+ it "raises TypeError if the last argument is not a Hash" do
+ -> {
+ @p.rb_proc_call_kw(proc {}, [42])
+ }.should raise_error(TypeError, 'no implicit conversion of Integer into Hash')
+ end
+ end
+
+ describe "rb_proc_call_with_block" do
+ it "calls the Proc and passes arguments and a block" do
+ prc = Proc.new { |a, b, &block| block.call(a * b) }
+ @p.rb_proc_call_with_block(prc, [6, 7], proc { |n| n * 2 }).should == 6 * 7 * 2
+ end
+
+ it "calls the Proc and passes arguments when a block is nil" do
+ prc = Proc.new { |a, b| a * b }
+ @p.rb_proc_call_with_block(prc, [6, 7], nil).should == 6 * 7
+ end
+ end
+
+ describe "rb_proc_call_with_block_kw" do
+ it "passes keyword arguments and a block to the proc" do
+ prc = proc { |*args, **kw, &block| [args, kw, block.call(42)] }
+ block = proc { |n| n }
+
+ @p.rb_proc_call_with_block_kw(prc, [{}], block).should == [[], {}, 42]
+ @p.rb_proc_call_with_block_kw(prc, [{a: 1}], block).should == [[], {a: 1}, 42]
+ @p.rb_proc_call_with_block_kw(prc, [{b: 2}, {a: 1}], block).should == [[{b: 2}], {a: 1}, 42]
+ @p.rb_proc_call_with_block_kw(prc, [{b: 2}, {}], block).should == [[{b: 2}], {}, 42]
+ end
+
+ it "raises TypeError if the last argument is not a Hash" do
+ -> {
+ @p.rb_proc_call_with_block_kw(proc {}, [42], proc {})
+ }.should raise_error(TypeError, 'no implicit conversion of Integer into Hash')
+ end
+
+ it "passes keyword arguments to the proc when a block is nil" do
+ prc = proc { |*args, **kw| [args, kw] }
+
+ @p.rb_proc_call_with_block_kw(prc, [{}], nil).should == [[], {}]
+ end
+ end
+
describe "rb_obj_is_proc" do
it "returns true for Proc" do
prc = Proc.new {|a,b| a * b }
@@ -115,20 +168,6 @@ describe "C-API when calling Proc.new from a C function" do
# For example: C -> Ruby <- C -> Ruby means a C function called into Ruby
# code which returned to C, then C called into Ruby code again.
- ruby_version_is ""..."2.7" do
- # Ruby -> C -> rb_funcall(Proc.new)
- it "returns the Proc passed by the Ruby code calling the C function" do
- prc = @p.rb_Proc_new(0) { :called }
- prc.call.should == :called
- end
-
- # Ruby -> C -> Ruby <- C -> rb_funcall(Proc.new)
- it "returns the Proc passed to the Ruby method when the C function calls other Ruby methods before calling Proc.new" do
- prc = @p.rb_Proc_new(1) { :called }
- prc.call.should == :called
- end
- end
-
# Ruby -> C -> Ruby -> Proc.new
it "raises an ArgumentError when the C function calls a Ruby method that calls Proc.new" do
-> {
@@ -142,20 +181,6 @@ describe "C-API when calling Proc.new from a C function" do
-> { @p.rb_Proc_new(3) { :called } }.should raise_error(ArgumentError)
end
- ruby_version_is ""..."2.7" do
- # Ruby -> C -> Ruby -> C (with new block) -> rb_funcall(Proc.new)
- it "returns the most recent Proc passed when the Ruby method called the C function" do
- prc = @p.rb_Proc_new(4) { :called }
- prc.call.should == :calling_with_block
- end
-
- # Ruby -> C -> Ruby -> C (with new block) <- Ruby <- C -> # rb_funcall(Proc.new)
- it "returns the Proc passed from the original Ruby call to the C function" do
- prc = @p.rb_Proc_new(5) { :called }
- prc.call.should == :called
- end
- end
-
# Ruby -> C -> Ruby -> block_given?
it "returns false from block_given? in a Ruby method called by the C function" do
@p.rb_Proc_new(6).should be_false
diff --git a/spec/ruby/optional/capi/rbasic_spec.rb b/spec/ruby/optional/capi/rbasic_spec.rb
index 6300680d99..f3367e05ff 100644
--- a/spec/ruby/optional/capi/rbasic_spec.rb
+++ b/spec/ruby/optional/capi/rbasic_spec.rb
@@ -1,7 +1,6 @@
require_relative 'spec_helper'
require_relative 'shared/rbasic'
load_extension("rbasic")
-return if /mswin/ =~ RUBY_PLATFORM && ENV.key?('GITHUB_ACTIONS') # not working from the beginning
load_extension("data")
load_extension("array")
@@ -34,6 +33,8 @@ describe "RBasic support for RData" do
initial = @specs.get_flags(obj1)
@specs.get_flags(obj2).should == initial
@specs.set_flags(obj1, 1 << 14 | 1 << 16 | initial)
+ @specs.get_flags(obj1).should == 1 << 14 | 1 << 16 | initial
+
@specs.copy_flags(obj2, obj1)
@specs.get_flags(obj2).should == 1 << 14 | 1 << 16 | initial
@specs.set_flags(obj1, initial)
diff --git a/spec/ruby/optional/capi/regexp_spec.rb b/spec/ruby/optional/capi/regexp_spec.rb
index 81844e2a6e..af366e17a2 100644
--- a/spec/ruby/optional/capi/regexp_spec.rb
+++ b/spec/ruby/optional/capi/regexp_spec.rb
@@ -109,4 +109,20 @@ describe "C-API Regexp function" do
thr.join
end
end
+
+ describe "rb_memicmp" do
+ it "returns 0 for identical strings" do
+ @p.rb_memcicmp('Hello', 'Hello').should == 0
+ end
+
+ it "returns 0 for strings which only differ in case" do
+ @p.rb_memcicmp('Hello', 'HELLO').should == 0
+ @p.rb_memcicmp('HELLO', 'Hello').should == 0
+ end
+
+ it "returns the difference between the first non matching characters" do
+ @p.rb_memcicmp('Hello', 'HELLP').should == -1
+ @p.rb_memcicmp('HELLp', 'Hello').should == 1
+ end
+ end
end
diff --git a/spec/ruby/optional/capi/shared/rbasic.rb b/spec/ruby/optional/capi/shared/rbasic.rb
index 5ef63e81e3..9d80a93e1d 100644
--- a/spec/ruby/optional/capi/shared/rbasic.rb
+++ b/spec/ruby/optional/capi/shared/rbasic.rb
@@ -1,5 +1,4 @@
describe :rbasic, shared: true do
-
before :all do
specs = CApiRBasicSpecs.new
@taint = ruby_version_is(''...'3.1') ? specs.taint_flag : 0
@@ -10,7 +9,7 @@ describe :rbasic, shared: true do
obj, _ = @data.call
initial = @specs.get_flags(obj)
obj.freeze
- @specs.get_flags(obj).should == @freeze | initial
+ (@specs.get_flags(obj) & 0xFFFF).should == (@freeze | initial) & 0xFFFF
end
it "supports setting the FREEZE flag" do
@@ -20,40 +19,6 @@ describe :rbasic, shared: true do
obj.should.frozen?
end
- ruby_version_is ""..."2.7" do
- it "reports the appropriate FREEZE and TAINT flags for the object when reading" do
- obj, _ = @data.call
- initial = @specs.get_flags(obj)
- obj.taint
- @specs.get_flags(obj).should == @taint | initial
- obj.untaint
- @specs.get_flags(obj).should == initial
- obj.freeze
- @specs.get_flags(obj).should == @freeze | initial
-
- obj, _ = @data.call
- obj.taint
- obj.freeze
- @specs.get_flags(obj).should == @freeze | @taint | initial
- end
-
- it "supports setting the FREEZE and TAINT flags" do
- obj, _ = @data.call
- initial = @specs.get_flags(obj)
- @specs.set_flags(obj, @taint | initial).should == @taint | initial
- obj.should.tainted?
- @specs.set_flags(obj, initial).should == initial
- obj.should_not.tainted?
- @specs.set_flags(obj, @freeze | initial).should == @freeze | initial
- obj.should.frozen?
-
- obj, _ = @data.call
- @specs.set_flags(obj, @freeze | @taint | initial).should == @freeze | @taint | initial
- obj.should.tainted?
- obj.should.frozen?
- end
- end
-
it "supports retrieving the (meta)class" do
obj, _ = @data.call
@specs.get_klass(obj).should == obj.class
diff --git a/spec/ruby/optional/capi/spec_helper.rb b/spec/ruby/optional/capi/spec_helper.rb
index 9bd2d9791c..2691aa1332 100644
--- a/spec/ruby/optional/capi/spec_helper.rb
+++ b/spec/ruby/optional/capi/spec_helper.rb
@@ -29,10 +29,13 @@ def compile_extension(name)
ext = "#{name}_spec"
lib = "#{object_path}/#{ext}.#{RbConfig::CONFIG['DLEXT']}"
- ruby_header = "#{RbConfig::CONFIG['rubyhdrdir']}/ruby.h"
+ rubyhdrdir = RbConfig::CONFIG['rubyhdrdir']
+ ruby_header = "#{rubyhdrdir}/ruby.h"
+ abi_header = "#{rubyhdrdir}/ruby/internal/abi.h"
if RbConfig::CONFIG["ENABLE_SHARED"] == "yes"
- libdirname = RbConfig::CONFIG['libdirname'] # defined since 2.1
+ # below is defined since 2.1, except for mswin, and maybe other platforms
+ libdirname = RbConfig::CONFIG.fetch 'libdirname', 'libdir'
libruby = "#{RbConfig::CONFIG[libdirname]}/#{RbConfig::CONFIG['LIBRUBY']}"
end
@@ -45,6 +48,7 @@ def compile_extension(name)
when mtime <= File.mtime("#{core_ext_dir}/rubyspec.h")
when mtime <= File.mtime("#{spec_ext_dir}/#{ext}.c")
when mtime <= File.mtime(ruby_header)
+ when (mtime <= File.mtime(abi_header) rescue nil)
when libruby && mtime <= File.mtime(libruby)
else
return lib # up-to-date
diff --git a/spec/ruby/optional/capi/string_spec.rb b/spec/ruby/optional/capi/string_spec.rb
index ce387ffa49..a8edf998b5 100644
--- a/spec/ruby/optional/capi/string_spec.rb
+++ b/spec/ruby/optional/capi/string_spec.rb
@@ -1,4 +1,5 @@
# encoding: utf-8
+# frozen_string_literal: false
require_relative 'spec_helper'
require_relative '../../shared/string/times'
@@ -47,7 +48,7 @@ describe "C-API String function" do
[Encoding::BINARY, Encoding::UTF_8].each do |enc|
describe "rb_str_set_len on a #{enc.name} String" do
before :each do
- @str = "abcdefghij".force_encoding(enc)
+ @str = "abcdefghij".dup.force_encoding(enc)
# Make sure to unshare the string
@s.rb_str_modify(@str)
end
@@ -97,6 +98,32 @@ describe "C-API String function" do
end
end
+ describe "rb_str_set_len on a UTF-16 String" do
+ before :each do
+ @str = "abcdefghij".dup.force_encoding(Encoding::UTF_16BE)
+ # Make sure to unshare the string
+ @s.rb_str_modify(@str)
+ end
+
+ it "inserts two NULL bytes at the length" do
+ @s.rb_str_set_len(@str, 4).b.should == "abcd".b
+ @s.rb_str_set_len(@str, 8).b.should == "abcd\x00\x00gh".b
+ end
+ end
+
+ describe "rb_str_set_len on a UTF-32 String" do
+ before :each do
+ @str = "abcdefghijkl".dup.force_encoding(Encoding::UTF_32BE)
+ # Make sure to unshare the string
+ @s.rb_str_modify(@str)
+ end
+
+ it "inserts four NULL bytes at the length" do
+ @s.rb_str_set_len(@str, 4).b.should == "abcd".b
+ @s.rb_str_set_len(@str, 12).b.should == "abcd\x00\x00\x00\x00ijkl".b
+ end
+ end
+
describe "rb_str_buf_new" do
it "returns the equivalent of an empty string" do
buf = @s.rb_str_buf_new(10, nil)
@@ -181,12 +208,6 @@ describe "C-API String function" do
@s.rb_str_new("hello", 3).should == "hel"
end
- ruby_version_is ''...'2.7' do
- it "returns a non-tainted string" do
- @s.rb_str_new("hello", 5).should_not.tainted?
- end
- end
-
it "returns an empty string if len is 0" do
@s.rb_str_new("hello", 0).should == ""
end
@@ -211,7 +232,7 @@ describe "C-API String function" do
describe "rb_usascii_str_new" do
it "creates a new String with US-ASCII Encoding from a char buffer of len characters" do
- str = "abc".force_encoding("us-ascii")
+ str = "abc".dup.force_encoding("us-ascii")
result = @s.rb_usascii_str_new("abcdef", 3)
result.should == str
result.encoding.should == Encoding::US_ASCII
@@ -227,14 +248,14 @@ describe "C-API String function" do
it "returns US-ASCII string for non-US-ASCII string literal" do
str = @s.rb_usascii_str_new_lit_non_ascii
- str.should == "r\xC3\xA9sum\xC3\xA9".force_encoding(Encoding::US_ASCII)
+ str.should == "r\xC3\xA9sum\xC3\xA9".dup.force_encoding(Encoding::US_ASCII)
str.encoding.should == Encoding::US_ASCII
end
end
describe "rb_usascii_str_new_cstr" do
it "creates a new String with US-ASCII Encoding" do
- str = "abc".force_encoding("us-ascii")
+ str = "abc".dup.force_encoding("us-ascii")
result = @s.rb_usascii_str_new_cstr("abc")
result.should == str
result.encoding.should == Encoding::US_ASCII
@@ -335,24 +356,6 @@ describe "C-API String function" do
end
end
- ruby_version_is ''...'2.7' do
- describe "rb_tainted_str_new" do
- it "creates a new tainted String" do
- newstring = @s.rb_tainted_str_new("test", 4)
- newstring.should == "test"
- newstring.tainted?.should be_true
- end
- end
-
- describe "rb_tainted_str_new2" do
- it "creates a new tainted String" do
- newstring = @s.rb_tainted_str_new2("test")
- newstring.should == "test"
- newstring.tainted?.should be_true
- end
- end
- end
-
describe "rb_str_append" do
it "appends a string to another string" do
@s.rb_str_append("Hello", " Goodbye").should == "Hello Goodbye"
@@ -378,6 +381,14 @@ describe "C-API String function" do
it_behaves_like :string_times, :rb_str_times, -> str, times { @s.rb_str_times(str, times) }
end
+ describe "rb_str_buf_append" do
+ it "concatenates a string to another string" do
+ str = "Your house "
+ @s.rb_str_buf_append(str, "is on fire?").should.equal?(str)
+ str.should == "Your house is on fire?"
+ end
+ end
+
describe "rb_str_buf_cat" do
it "concatenates a C string to a ruby string" do
@s.rb_str_buf_cat("Your house is on fire").should == "Your house is on fire?"
@@ -408,7 +419,7 @@ describe "C-API String function" do
describe "rb_enc_str_buf_cat" do
it "concatenates a C string literal to a ruby string with the given encoding" do
- input = "hello ".force_encoding(Encoding::US_ASCII)
+ input = "hello ".dup.force_encoding(Encoding::US_ASCII)
result = @s.rb_enc_str_buf_cat(input, "résumé", Encoding::UTF_8)
result.should == "hello résumé"
result.encoding.should == Encoding::UTF_8
@@ -488,29 +499,10 @@ describe "C-API String function" do
end
end
- describe "rb_fstring" do
- it 'returns self if the String is frozen' do
- input = 'foo'.freeze
- output = @s.rb_fstring(input)
-
- output.should equal(input)
- output.should.frozen?
- end
-
- it 'returns a frozen copy if the String is not frozen' do
- input = 'foo'
- output = @s.rb_fstring(input)
-
- output.should.frozen?
- output.should_not equal(input)
- output.should == 'foo'
- end
- end
-
describe "rb_str_subseq" do
it "returns a byte-indexed substring" do
- str = "\x00\x01\x02\x03\x04".force_encoding("binary")
- @s.rb_str_subseq(str, 1, 2).should == "\x01\x02".force_encoding("binary")
+ str = "\x00\x01\x02\x03\x04".dup.force_encoding("binary")
+ @s.rb_str_subseq(str, 1, 2).should == "\x01\x02".dup.force_encoding("binary")
end
end
@@ -603,9 +595,17 @@ describe "C-API String function" do
filename = fixture(__FILE__, "read.txt")
str = ""
capacities = @s.RSTRING_PTR_read(str, filename)
- capacities.should == [30, 53]
+ capacities[0].should >= 30
+ capacities[1].should >= 53
+ capacities[0].should < capacities[1]
str.should == "fixture file contents to test read() with RSTRING_PTR"
end
+
+ it "terminates the string with at least (encoding min length) \\0 bytes" do
+ @s.RSTRING_PTR_null_terminate("abc", 1).should == "\x00"
+ @s.RSTRING_PTR_null_terminate("abc".encode("UTF-16BE"), 2).should == "\x00\x00"
+ @s.RSTRING_PTR_null_terminate("abc".encode("UTF-32BE"), 4).should == "\x00\x00\x00\x00"
+ end
end
describe "RSTRING_LEN" do
@@ -655,22 +655,6 @@ describe "C-API String function" do
end
describe "SafeStringValue" do
- ruby_version_is ''...'2.7' do
- it "raises for tained string when $SAFE is 1" do
- begin
- Thread.new {
- $SAFE = 1
- -> {
- @s.SafeStringValue("str".taint)
- }.should raise_error(SecurityError)
- }.join
- ensure
- $SAFE = 0
- end
- end
-
- it_behaves_like :string_value_macro, :SafeStringValue
- end
end
describe "rb_str_modify" do
@@ -729,7 +713,7 @@ describe "C-API String function" do
end
it "increases the size of the string" do
- expected = "test".force_encoding("US-ASCII")
+ expected = "test".dup.force_encoding("US-ASCII")
str = @s.rb_str_resize(expected.dup, 12)
str.size.should == 12
str.bytesize.should == 12
@@ -800,12 +784,6 @@ describe :rb_external_str_new, shared: true do
x80 = [0x80].pack('C')
@s.send(@method, "#{x80}abc").encoding.should == Encoding::BINARY
end
-
- ruby_version_is ''...'2.7' do
- it "returns a tainted String" do
- @s.send(@method, "abc").tainted?.should be_true
- end
- end
end
describe "C-API String function" do
@@ -866,11 +844,11 @@ describe "C-API String function" do
# it "transcodes a String to Encoding.default_internal if it is set" do
# Encoding.default_internal = Encoding::EUC_JP
#
-# - a = "\xE3\x81\x82\xe3\x82\x8c".force_encoding("utf-8")
+# - a = "\xE3\x81\x82\xe3\x82\x8c".dup.force_encoding("utf-8")
# + a = [0xE3, 0x81, 0x82, 0xe3, 0x82, 0x8c].pack('C6').force_encoding("utf-8")
# s = @s.rb_external_str_new_with_enc(a, a.bytesize, Encoding::UTF_8)
# -
-# - s.should == "\xA4\xA2\xA4\xEC".force_encoding("euc-jp")
+# - s.should == "\xA4\xA2\xA4\xEC".dup.force_encoding("euc-jp")
# + x = [0xA4, 0xA2, 0xA4, 0xEC].pack('C4')#.force_encoding('binary')
# + s.should == x
# s.encoding.should equal(Encoding::EUC_JP)
@@ -885,19 +863,12 @@ describe "C-API String function" do
s.should == x
s.encoding.should equal(Encoding::EUC_JP)
end
-
- ruby_version_is ''...'2.7' do
- it "returns a tainted String" do
- s = @s.rb_external_str_new_with_enc("abc", 3, Encoding::US_ASCII)
- s.tainted?.should be_true
- end
- end
end
describe "rb_locale_str_new" do
it "returns a String with 'locale' encoding" do
s = @s.rb_locale_str_new("abc", 3)
- s.should == "abc".force_encoding(Encoding.find("locale"))
+ s.should == "abc".dup.force_encoding(Encoding.find("locale"))
s.encoding.should equal(Encoding.find("locale"))
end
end
@@ -905,14 +876,14 @@ describe "C-API String function" do
describe "rb_locale_str_new_cstr" do
it "returns a String with 'locale' encoding" do
s = @s.rb_locale_str_new_cstr("abc")
- s.should == "abc".force_encoding(Encoding.find("locale"))
+ s.should == "abc".dup.force_encoding(Encoding.find("locale"))
s.encoding.should equal(Encoding.find("locale"))
end
end
describe "rb_str_conv_enc" do
it "returns the original String when to encoding is not specified" do
- a = "abc".force_encoding("us-ascii")
+ a = "abc".dup.force_encoding("us-ascii")
@s.rb_str_conv_enc(a, Encoding::US_ASCII, nil).should equal(a)
end
@@ -922,7 +893,7 @@ describe "C-API String function" do
end
it "returns a transcoded String" do
- a = "\xE3\x81\x82\xE3\x82\x8C".force_encoding("utf-8")
+ a = "\xE3\x81\x82\xE3\x82\x8C".dup.force_encoding("utf-8")
result = @s.rb_str_conv_enc(a, Encoding::UTF_8, Encoding::EUC_JP)
x = [0xA4, 0xA2, 0xA4, 0xEC].pack('C4').force_encoding('utf-8')
result.should == x.force_encoding("euc-jp")
@@ -931,7 +902,7 @@ describe "C-API String function" do
describe "when the String encoding is equal to the destination encoding" do
it "returns the original String" do
- a = "abc".force_encoding("us-ascii")
+ a = "abc".dup.force_encoding("us-ascii")
@s.rb_str_conv_enc(a, Encoding::US_ASCII, Encoding::US_ASCII).should equal(a)
end
@@ -941,7 +912,7 @@ describe "C-API String function" do
end
it "returns the origin String if the destination encoding is BINARY" do
- a = "abc".force_encoding("binary")
+ a = "abc".dup.force_encoding("binary")
@s.rb_str_conv_enc(a, Encoding::US_ASCII, Encoding::BINARY).should equal(a)
end
end
@@ -949,7 +920,7 @@ describe "C-API String function" do
describe "rb_str_conv_enc_opts" do
it "returns the original String when to encoding is not specified" do
- a = "abc".force_encoding("us-ascii")
+ a = "abc".dup.force_encoding("us-ascii")
@s.rb_str_conv_enc_opts(a, Encoding::US_ASCII, nil, 0, nil).should equal(a)
end
@@ -960,7 +931,7 @@ describe "C-API String function" do
end
it "returns a transcoded String" do
- a = "\xE3\x81\x82\xE3\x82\x8C".force_encoding("utf-8")
+ a = "\xE3\x81\x82\xE3\x82\x8C".dup.force_encoding("utf-8")
result = @s.rb_str_conv_enc_opts(a, Encoding::UTF_8, Encoding::EUC_JP, 0, nil)
x = [0xA4, 0xA2, 0xA4, 0xEC].pack('C4').force_encoding('utf-8')
result.should == x.force_encoding("euc-jp")
@@ -969,7 +940,7 @@ describe "C-API String function" do
describe "when the String encoding is equal to the destination encoding" do
it "returns the original String" do
- a = "abc".force_encoding("us-ascii")
+ a = "abc".dup.force_encoding("us-ascii")
@s.rb_str_conv_enc_opts(a, Encoding::US_ASCII,
Encoding::US_ASCII, 0, nil).should equal(a)
end
@@ -981,7 +952,7 @@ describe "C-API String function" do
end
it "returns the origin String if the destination encoding is BINARY" do
- a = "abc".force_encoding("binary")
+ a = "abc".dup.force_encoding("binary")
@s.rb_str_conv_enc_opts(a, Encoding::US_ASCII,
Encoding::BINARY, 0, nil).should equal(a)
end
@@ -999,7 +970,7 @@ describe "C-API String function" do
describe "rb_str_export_locale" do
it "returns the original String with the locale encoding" do
s = @s.rb_str_export_locale("abc")
- s.should == "abc".force_encoding(Encoding.find("locale"))
+ s.should == "abc".dup.force_encoding(Encoding.find("locale"))
s.encoding.should equal(Encoding.find("locale"))
end
end
@@ -1051,9 +1022,11 @@ end
@s.rb_sprintf3(true.class).should == s
end
- it "formats a TrueClass VALUE as 'true' if sign specified in format" do
- s = 'Result: true.'
- @s.rb_sprintf4(true.class).should == s
+ ruby_bug "#19167", ""..."3.2" do
+ it "formats a TrueClass VALUE as 'true' if sign specified in format" do
+ s = 'Result: TrueClass.'
+ @s.rb_sprintf4(true.class).should == s
+ end
end
it "truncates a string to a supplied precision if that is shorter than the string" do
@@ -1236,4 +1209,67 @@ end
-> { @s.rb_str_unlocktmp("test") }.should raise_error(RuntimeError, 'temporal unlocking already unlocked string')
end
end
+
+ describe "rb_enc_interned_str_cstr" do
+ it "returns a frozen string" do
+ str = "hello"
+ val = @s.rb_enc_interned_str_cstr(str, Encoding::US_ASCII)
+
+ val.should.is_a?(String)
+ val.encoding.should == Encoding::US_ASCII
+ val.should.frozen?
+ end
+
+ it "returns the same frozen string" do
+ str = "hello"
+ result1 = @s.rb_enc_interned_str_cstr(str, Encoding::US_ASCII)
+ result2 = @s.rb_enc_interned_str_cstr(str, Encoding::US_ASCII)
+ result1.should.equal?(result2)
+ end
+
+ it "returns different frozen strings for different encodings" do
+ str = "hello"
+ result1 = @s.rb_enc_interned_str_cstr(str, Encoding::US_ASCII)
+ result2 = @s.rb_enc_interned_str_cstr(str, Encoding::UTF_8)
+ result1.should_not.equal?(result2)
+ end
+
+ it "returns the same string as String#-@" do
+ @s.rb_enc_interned_str_cstr("hello", Encoding::UTF_8).should.equal?(-"hello")
+ end
+
+ ruby_bug "#20322", ""..."3.4" do
+ it "uses the default encoding if encoding is null" do
+ str = "hello"
+ val = @s.rb_enc_interned_str_cstr(str, nil)
+ val.encoding.should == Encoding::ASCII_8BIT
+ end
+ end
+ end
+
+ describe "rb_str_to_interned_str" do
+ it "returns a frozen string" do
+ str = "hello"
+ result = @s.rb_str_to_interned_str(str)
+ result.should.is_a?(String)
+ result.should.frozen?
+ end
+
+ it "returns the same frozen string" do
+ str = "hello"
+ result1 = @s.rb_str_to_interned_str(str)
+ result2 = @s.rb_str_to_interned_str(str)
+ result1.should.equal?(result2)
+ end
+
+ it "returns different frozen strings for different encodings" do
+ result1 = @s.rb_str_to_interned_str("hello".dup.force_encoding(Encoding::US_ASCII))
+ result2 = @s.rb_str_to_interned_str("hello".dup.force_encoding(Encoding::UTF_8))
+ result1.should_not.equal?(result2)
+ end
+
+ it "returns the same string as String#-@" do
+ @s.rb_str_to_interned_str("hello").should.equal?(-"hello")
+ end
+ end
end
diff --git a/spec/ruby/optional/capi/symbol_spec.rb b/spec/ruby/optional/capi/symbol_spec.rb
index b8fda34c0e..12c93c9f27 100644
--- a/spec/ruby/optional/capi/symbol_spec.rb
+++ b/spec/ruby/optional/capi/symbol_spec.rb
@@ -61,6 +61,10 @@ describe "C-API Symbol function" do
it "converts a symbol to a C char array" do
@s.rb_id2name(:test_symbol).should == "test_symbol"
end
+
+ it "returns (char*) NULL for (ID) 0" do
+ @s.rb_id2name_id_zero.should == nil
+ end
end
describe "rb_id2str" do
@@ -72,6 +76,10 @@ describe "C-API Symbol function" do
str = "test_symbol".encode(Encoding::UTF_16LE)
@s.rb_id2str(str.to_sym).encoding.should == Encoding::UTF_16LE
end
+
+ it "returns (VALUE) 0 = Qfalse for (ID) 0" do
+ @s.rb_id2str_id_zero.should == false
+ end
end
describe "rb_intern_str" do
diff --git a/spec/ruby/optional/capi/thread_spec.rb b/spec/ruby/optional/capi/thread_spec.rb
index 5cb46bbb7c..af641f0564 100644
--- a/spec/ruby/optional/capi/thread_spec.rb
+++ b/spec/ruby/optional/capi/thread_spec.rb
@@ -165,25 +165,23 @@ describe "C-API Thread function" do
end
end
- platform_is_not :mingw do
- it "runs a C function with the global lock unlocked and unlocks IO with the generic RUBY_UBF_IO" do
- thr = Thread.new do
- @t.rb_thread_call_without_gvl_with_ubf_io
- end
+ it "runs a C function with the global lock unlocked and unlocks IO with the generic RUBY_UBF_IO" do
+ thr = Thread.new do
+ @t.rb_thread_call_without_gvl_with_ubf_io
+ end
- # Wait until it's blocking...
- Thread.pass until thr.stop?
+ # Wait until it's blocking...
+ Thread.pass until thr.stop?
- # The thread status is set to sleep by rb_thread_call_without_gvl(),
- # but the thread might not be in the blocking read(2) yet, so wait a bit.
- sleep 0.1
+ # The thread status is set to sleep by rb_thread_call_without_gvl(),
+ # but the thread might not be in the blocking read(2) yet, so wait a bit.
+ sleep 0.1
- # Wake it up, causing the unblock function to be run.
- thr.wakeup
+ # Wake it up, causing the unblock function to be run.
+ thr.wakeup
- # Make sure it stopped and we got a proper value
- thr.value.should be_true
- end
+ # Make sure it stopped and we got a proper value
+ thr.value.should be_true
end
end
end
diff --git a/spec/ruby/optional/capi/time_spec.rb b/spec/ruby/optional/capi/time_spec.rb
index 579e81fc19..ca5fc5952a 100644
--- a/spec/ruby/optional/capi/time_spec.rb
+++ b/spec/ruby/optional/capi/time_spec.rb
@@ -283,6 +283,11 @@ describe "CApiTimeSpecs" do
-> { @s.rb_time_timespec_new(1447087832, 476451125, 86400) }.should raise_error(ArgumentError)
-> { @s.rb_time_timespec_new(1447087832, 476451125, -86400) }.should raise_error(ArgumentError)
end
+
+ it "doesn't call Time.at directly" do
+ Time.should_not_receive(:at)
+ @s.rb_time_timespec_new(1447087832, 476451125, 32400).should be_kind_of(Time)
+ end
end
describe "rb_timespec_now" do
diff --git a/spec/ruby/optional/capi/typed_data_spec.rb b/spec/ruby/optional/capi/typed_data_spec.rb
index 23b7c157ef..6d1398a1a0 100644
--- a/spec/ruby/optional/capi/typed_data_spec.rb
+++ b/spec/ruby/optional/capi/typed_data_spec.rb
@@ -85,4 +85,16 @@ describe "CApiWrappedTypedStruct" do
-> { @s.rb_check_typeddata_different_type(a) }.should raise_error(TypeError)
end
end
+
+ describe "RTYPEDDATA_P" do
+ it "returns true for a typed data" do
+ a = @s.typed_wrap_struct(1024)
+ @s.RTYPEDDATA_P(a).should == true
+ end
+
+ it "returns false for an untyped data object" do
+ a = @s.untyped_wrap_struct(1024)
+ @s.RTYPEDDATA_P(a).should == false
+ end
+ end
end
diff --git a/spec/ruby/optional/capi/util_spec.rb b/spec/ruby/optional/capi/util_spec.rb
index a90c28a78e..9ff8b4760a 100644
--- a/spec/ruby/optional/capi/util_spec.rb
+++ b/spec/ruby/optional/capi/util_spec.rb
@@ -11,13 +11,13 @@ describe "C-API Util function" do
before :each do
@prc = -> { 1 }
@acc = []
- @keyword_prefix = 'k' if RUBY_VERSION >= '2.7'
ScratchPad.record @acc
end
it "assigns the required arguments scanned" do
- @o.rb_scan_args([1, 2], "2", 2, @acc).should == 2
- ScratchPad.recorded.should == [1, 2]
+ obj = Object.new
+ @o.rb_scan_args([obj, 2], "2", 2, @acc).should == 2
+ ScratchPad.recorded.should == [obj, 2]
end
it "raises an ArgumentError if there are insufficient arguments" do
@@ -48,7 +48,7 @@ describe "C-API Util function" do
ScratchPad.recorded.should == [1, 2, [3, 4]]
end
- it "assigns the required and optional arguments and and empty Array when there are no arguments to splat" do
+ it "assigns the required and optional arguments and empty Array when there are no arguments to splat" do
@o.rb_scan_args([1, 2], "11*", 3, @acc).should == 2
ScratchPad.recorded.should == [1, 2, []]
end
@@ -100,13 +100,13 @@ describe "C-API Util function" do
it "assigns Hash arguments" do
h = {a: 1, b: 2}
- @o.rb_scan_args([h], "#{@keyword_prefix}0:", 1, @acc).should == 0
+ @o.rb_scan_args([h], "k0:", 1, @acc).should == 0
ScratchPad.recorded.should == [h]
end
it "assigns required and Hash arguments" do
h = {a: 1, b: 2}
- @o.rb_scan_args([1, h], "#{@keyword_prefix}1:", 2, @acc).should == 1
+ @o.rb_scan_args([1, h], "k1:", 2, @acc).should == 1
ScratchPad.recorded.should == [1, h]
end
@@ -115,22 +115,11 @@ describe "C-API Util function" do
ScratchPad.recorded.should == [1, nil]
end
- ruby_version_is ''...'3.0' do
- it "assigns required and Hash arguments with nil Hash" do
- suppress_warning do
- @o.rb_scan_args([1, nil], "1:", 2, @acc).should == 1
- end
- ScratchPad.recorded.should == [1, nil]
- end
- end
-
- ruby_version_is '3.0' do
- it "rejects the use of nil as a hash" do
- -> {
- @o.rb_scan_args([1, nil], "1:", 2, @acc).should == 1
- }.should raise_error(ArgumentError)
- ScratchPad.recorded.should == []
- end
+ it "rejects the use of nil as a hash" do
+ -> {
+ @o.rb_scan_args([1, nil], "1:", 2, @acc).should == 1
+ }.should raise_error(ArgumentError)
+ ScratchPad.recorded.should == []
end
it "assigns required and optional arguments with no hash argument given" do
@@ -138,61 +127,41 @@ describe "C-API Util function" do
ScratchPad.recorded.should == [1, 7, 4]
end
- it "assigns required, optional, splat, post-splat, Hash and block arguments" do
- h = {a: 1, b: 2}
- @o.rb_scan_args([1, 2, 3, 4, 5, h], "#{@keyword_prefix}11*1:&", 6, @acc, &@prc).should == 5
- ScratchPad.recorded.should == [1, 2, [3, 4], 5, h, @prc]
+ it "assigns optional arguments with no hash argument given" do
+ @o.rb_scan_args([1, 7], "02:", 3, @acc).should == 2
+ ScratchPad.recorded.should == [1, 7, nil]
end
- ruby_version_is ''...'3.0' do
- # r43934
- it "rejects non-keyword arguments" do
- h = {1 => 2, 3 => 4}
- -> {
- suppress_warning do
- @o.rb_scan_args([h], "#{@keyword_prefix}0:", 1, @acc)
- end
- }.should raise_error(ArgumentError)
- ScratchPad.recorded.should == []
- end
+ it "assigns optional arguments with no hash argument given and rejects the use of optional nil argument as a hash" do
+ -> {
+ @o.rb_scan_args([1, nil], "02:", 3, @acc).should == 2
+ }.should_not complain
- it "rejects required and non-keyword arguments" do
- h = {1 => 2, 3 => 4}
- -> {
- suppress_warning do
- @o.rb_scan_args([1, h], "#{@keyword_prefix}1:", 2, @acc)
- end
- }.should raise_error(ArgumentError)
- ScratchPad.recorded.should == []
- end
+ ScratchPad.recorded.should == [1, nil, nil]
+ end
- it "considers the hash as a post argument when there is a splat" do
- h = {1 => 2, 3 => 4}
- suppress_warning do
- @o.rb_scan_args([1, 2, 3, 4, 5, h], "#{@keyword_prefix}11*1:&", 6, @acc, &@prc).should == 6
- end
- ScratchPad.recorded.should == [1, 2, [3, 4, 5], h, nil, @prc]
- end
+ it "assigns required, optional, splat, post-splat, Hash and block arguments" do
+ h = {a: 1, b: 2}
+ @o.rb_scan_args([1, 2, 3, 4, 5, h], "k11*1:&", 6, @acc, &@prc).should == 5
+ ScratchPad.recorded.should == [1, 2, [3, 4], 5, h, @prc]
end
- ruby_version_is '3.0' do
- it "does not reject non-symbol keys in keyword arguments" do
- h = {1 => 2, 3 => 4}
- @o.rb_scan_args([h], "#{@keyword_prefix}0:", 1, @acc).should == 0
- ScratchPad.recorded.should == [h]
- end
+ it "does not reject non-symbol keys in keyword arguments" do
+ h = {1 => 2, 3 => 4}
+ @o.rb_scan_args([h], "k0:", 1, @acc).should == 0
+ ScratchPad.recorded.should == [h]
+ end
- it "does not reject non-symbol keys in keyword arguments with required argument" do
- h = {1 => 2, 3 => 4}
- @o.rb_scan_args([1, h], "#{@keyword_prefix}1:", 2, @acc).should == 1
- ScratchPad.recorded.should == [1, h]
- end
+ it "does not reject non-symbol keys in keyword arguments with required argument" do
+ h = {1 => 2, 3 => 4}
+ @o.rb_scan_args([1, h], "k1:", 2, @acc).should == 1
+ ScratchPad.recorded.should == [1, h]
+ end
- it "considers keyword arguments with non-symbol keys as keywords when using splat and post arguments" do
- h = {1 => 2, 3 => 4}
- @o.rb_scan_args([1, 2, 3, 4, 5, h], "#{@keyword_prefix}11*1:&", 6, @acc, &@prc).should == 5
- ScratchPad.recorded.should == [1, 2, [3, 4], 5, h, @prc]
- end
+ it "considers keyword arguments with non-symbol keys as keywords when using splat and post arguments" do
+ h = {1 => 2, 3 => 4}
+ @o.rb_scan_args([1, 2, 3, 4, 5, h], "k11*1:&", 6, @acc, &@prc).should == 5
+ ScratchPad.recorded.should == [1, 2, [3, 4], 5, h, @prc]
end
end
diff --git a/spec/ruby/security/cve_2010_1330_spec.rb b/spec/ruby/security/cve_2010_1330_spec.rb
index 33e88d652e..2594439550 100644
--- a/spec/ruby/security/cve_2010_1330_spec.rb
+++ b/spec/ruby/security/cve_2010_1330_spec.rb
@@ -8,7 +8,7 @@ describe "String#gsub" do
# #gsub on a string in the UTF-8 encoding but with invalid an UTF-8 byte
# sequence.
- str = "\xF6<script>"
+ str = +"\xF6<script>"
str.force_encoding Encoding::BINARY
str.gsub(/</, "&lt;").should == "\xF6&lt;script>".b
str.force_encoding Encoding::UTF_8
diff --git a/spec/ruby/security/cve_2014_8080_spec.rb b/spec/ruby/security/cve_2014_8080_spec.rb
deleted file mode 100644
index 23770f94b1..0000000000
--- a/spec/ruby/security/cve_2014_8080_spec.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-require_relative '../spec_helper'
-
-ruby_version_is ''...'3.0' do
- require 'rexml/document'
-
- describe "REXML::Document.new" do
-
- it "resists CVE-2014-8080 by raising an exception when entity expansion has grown too large" do
- xml = <<XML
- <?xml version="1.0" encoding="UTF-8" ?>
- <!DOCTYPE x [
- <!ENTITY % x0 "xxxxxxxxxx">
- <!ENTITY % x1 "%x0;%x0;%x0;%x0;%x0;%x0;%x0;%x0;%x0;%x0;">
- <!ENTITY % x2 "%x1;%x1;%x1;%x1;%x1;%x1;%x1;%x1;%x1;%x1;">
- <!ENTITY % x3 "%x2;%x2;%x2;%x2;%x2;%x2;%x2;%x2;%x2;%x2;">
- <!ENTITY % x4 "%x3;%x3;%x3;%x3;%x3;%x3;%x3;%x3;%x3;%x3;">
- <!ENTITY % x5 "%x4;%x4;%x4;%x4;%x4;%x4;%x4;%x4;%x4;%x4;">
- <!ENTITY % x6 "%x5;%x5;%x5;%x5;%x5;%x5;%x5;%x5;%x5;%x5;">
- <!ENTITY % x7 "%x6;%x6;%x6;%x6;%x6;%x6;%x6;%x6;%x6;%x6;">
- <!ENTITY % x8 "%x7;%x7;%x7;%x7;%x7;%x7;%x7;%x7;%x7;%x7;">
- <!ENTITY % x9 "%x8;%x8;%x8;%x8;%x8;%x8;%x8;%x8;%x8;%x8;">
- ]>
- <x>
- %x9;%x9;%x9;%x9;%x9;%x9;%x9;%x9;%x9;%x9;
- </x>
-XML
-
- -> {
- REXML::Document.new(xml).doctype.entities['x9'].value
- }.should raise_error(REXML::ParseException, /entity expansion has grown too large/)
- end
-
- end
-end
diff --git a/spec/ruby/security/cve_2017_17742_spec.rb b/spec/ruby/security/cve_2017_17742_spec.rb
deleted file mode 100644
index b0d93e42b8..0000000000
--- a/spec/ruby/security/cve_2017_17742_spec.rb
+++ /dev/null
@@ -1,37 +0,0 @@
-require_relative '../spec_helper'
-
-# webrick is no longer in stdlib in Ruby 3+
-ruby_version_is ""..."3.0" do
- require "webrick"
- require "stringio"
- require "net/http"
-
- describe "WEBrick" do
- describe "resists CVE-2017-17742" do
- it "for a response splitting headers" do
- config = WEBrick::Config::HTTP
- res = WEBrick::HTTPResponse.new config
- res['X-header'] = "malicious\r\nCookie: hack"
- io = StringIO.new
- res.send_response io
- io.rewind
- res = Net::HTTPResponse.read_new(Net::BufferedIO.new(io))
- res.code.should == '500'
- io.string.should_not =~ /hack/
- end
-
- it "for a response splitting cookie headers" do
- user_input = "malicious\r\nCookie: hack"
- config = WEBrick::Config::HTTP
- res = WEBrick::HTTPResponse.new config
- res.cookies << WEBrick::Cookie.new('author', user_input)
- io = StringIO.new
- res.send_response io
- io.rewind
- res = Net::HTTPResponse.read_new(Net::BufferedIO.new(io))
- res.code.should == '500'
- io.string.should_not =~ /hack/
- end
- end
- end
-end
diff --git a/spec/ruby/security/cve_2018_16396_spec.rb b/spec/ruby/security/cve_2018_16396_spec.rb
index c9624e9c63..6f8a5d2f5d 100644
--- a/spec/ruby/security/cve_2018_16396_spec.rb
+++ b/spec/ruby/security/cve_2018_16396_spec.rb
@@ -1,21 +1,7 @@
require_relative '../spec_helper'
describe "Array#pack" do
- ruby_version_is ''...'2.7' do
- it "resists CVE-2018-16396 by tainting output based on input" do
- "aAZBbHhuMmPp".each_char do |f|
- ["123456".taint].pack(f).tainted?.should be_true
- end
- end
- end
end
describe "String#unpack" do
- ruby_version_is ''...'2.7' do
- it "resists CVE-2018-16396 by tainting output based on input" do
- "aAZBbHhuMm".each_char do |f|
- "123456".taint.unpack(f).first.tainted?.should be_true
- end
- end
- end
end
diff --git a/spec/ruby/security/cve_2019_8322_spec.rb b/spec/ruby/security/cve_2019_8322_spec.rb
index a84d7a5a95..b70d78c033 100644
--- a/spec/ruby/security/cve_2019_8322_spec.rb
+++ b/spec/ruby/security/cve_2019_8322_spec.rb
@@ -5,19 +5,17 @@ require 'rubygems'
require 'rubygems/safe_yaml'
require 'rubygems/commands/owner_command'
-platform_is_not :darwin do # frequent timeout/hang on macOS
- describe "CVE-2019-8322 is resisted by" do
- it "sanitising owner names" do
- command = Gem::Commands::OwnerCommand.new
- def command.rubygems_api_request(*args)
- Struct.new(:body).new("---\n- email: \"\e]2;nyan\a\"\n handle: handle\n id: id\n")
- end
- def command.with_response(response)
- yield response
- end
- command.should_receive(:say).with("Owners for gem: name")
- command.should_receive(:say).with("- .]2;nyan.")
- command.show_owners "name"
+describe "CVE-2019-8322 is resisted by" do
+ it "sanitising owner names" do
+ command = Gem::Commands::OwnerCommand.new
+ def command.rubygems_api_request(*args)
+ Struct.new(:body).new("---\n- email: \"\e]2;nyan\a\"\n handle: handle\n id: id\n")
end
+ def command.with_response(response)
+ yield response
+ end
+ command.should_receive(:say).with("Owners for gem: name")
+ command.should_receive(:say).with("- .]2;nyan.")
+ command.show_owners "name"
end
end
diff --git a/spec/ruby/security/cve_2019_8323_spec.rb b/spec/ruby/security/cve_2019_8323_spec.rb
index 3632d3b028..49a31a6682 100644
--- a/spec/ruby/security/cve_2019_8323_spec.rb
+++ b/spec/ruby/security/cve_2019_8323_spec.rb
@@ -1,38 +1,46 @@
require_relative '../spec_helper'
-platform_is_not :darwin do # frequent timeout/hang on macOS
- require 'optparse'
+require 'optparse'
- require 'rubygems'
- require 'rubygems/gemcutter_utilities'
+require 'rubygems'
+require 'rubygems/gemcutter_utilities'
- describe "CVE-2019-8323 is resisted by" do
- describe "sanitising the body" do
- it "for success codes" do
- cutter = Class.new {
- include Gem::GemcutterUtilities
- }.new
- response = Net::HTTPSuccess.new(nil, nil, nil)
- def response.body
- "\e]2;nyan\a"
- end
- cutter.should_receive(:say).with(".]2;nyan.")
- cutter.with_response response
+describe "CVE-2019-8323 is resisted by" do
+ describe "sanitising the body" do
+ it "for success codes" do
+ cutter = Class.new {
+ include Gem::GemcutterUtilities
+ }.new
+ klass = if defined?(Gem::Net::HTTPSuccess)
+ Gem::Net::HTTPSuccess
+ else
+ Net::HTTPSuccess
+ end
+ response = klass.new(nil, nil, nil)
+ def response.body
+ "\e]2;nyan\a"
end
+ cutter.should_receive(:say).with(".]2;nyan.")
+ cutter.with_response response
+ end
- it "for error codes" do
- cutter = Class.new {
- include Gem::GemcutterUtilities
- }.new
- def cutter.terminate_interaction(n)
- end
- response = Net::HTTPNotFound.new(nil, nil, nil)
- def response.body
- "\e]2;nyan\a"
- end
- cutter.should_receive(:say).with(".]2;nyan.")
- cutter.with_response response
+ it "for error codes" do
+ cutter = Class.new {
+ include Gem::GemcutterUtilities
+ }.new
+ def cutter.terminate_interaction(n)
+ end
+ klass = if defined?(Gem::Net::HTTPNotFound)
+ Gem::Net::HTTPNotFound
+ else
+ Net::HTTPNotFound
+ end
+ response = klass.new(nil, nil, nil)
+ def response.body
+ "\e]2;nyan\a"
end
+ cutter.should_receive(:say).with(".]2;nyan.")
+ cutter.with_response response
end
end
end
diff --git a/spec/ruby/security/cve_2019_8325_spec.rb b/spec/ruby/security/cve_2019_8325_spec.rb
index 309445a50f..bbddb3a6ce 100644
--- a/spec/ruby/security/cve_2019_8325_spec.rb
+++ b/spec/ruby/security/cve_2019_8325_spec.rb
@@ -1,38 +1,46 @@
require_relative '../spec_helper'
-platform_is_not :darwin do # frequent timeout/hang on macOS
- require 'rubygems'
- require 'rubygems/command_manager'
+require 'rubygems'
+require 'rubygems/command_manager'
- describe "CVE-2019-8325 is resisted by" do
- describe "sanitising error message components" do
- it "for the 'while executing' message" do
- manager = Gem::CommandManager.new
- def manager.process_args(args, build_args)
- raise StandardError, "\e]2;nyan\a"
- end
- def manager.terminate_interaction(n)
- end
- manager.should_receive(:alert_error).with("While executing gem ... (StandardError)\n .]2;nyan.")
- manager.run nil, nil
+describe "CVE-2019-8325 is resisted by" do
+ describe "sanitising error message components" do
+ before :each do
+ @ui = Gem::SilentUI.new
+ end
+
+ after :each do
+ @ui.close
+ end
+
+ it "for the 'while executing' message" do
+ manager = Gem::CommandManager.new
+ manager.ui = @ui
+ def manager.process_args(args, build_args)
+ raise StandardError, "\e]2;nyan\a"
end
+ def manager.terminate_interaction(n)
+ end
+ manager.should_receive(:alert_error).with("While executing gem ... (StandardError)\n .]2;nyan.")
+ manager.run nil, nil
+ end
- it "for the 'invalid option' message" do
- manager = Gem::CommandManager.new
- def manager.terminate_interaction(n)
- end
- manager.should_receive(:alert_error).with("Invalid option: --.]2;nyan.. See 'gem --help'.")
- manager.process_args ["--\e]2;nyan\a"], nil
+ it "for the 'invalid option' message" do
+ manager = Gem::CommandManager.new
+ def manager.terminate_interaction(n)
end
+ manager.should_receive(:alert_error).with("Invalid option: --.]2;nyan.. See 'gem --help'.")
+ manager.process_args ["--\e]2;nyan\a"], nil
+ end
- it "for the 'loading command' message" do
- manager = Gem::CommandManager.new
- def manager.require(x)
- raise 'foo'
- end
- manager.should_receive(:alert_error).with("Loading command: .]2;nyan. (RuntimeError)\n\tfoo")
- manager.send :load_and_instantiate, "\e]2;nyan\a"
+ it "for the 'loading command' message" do
+ manager = Gem::CommandManager.new
+ manager.ui = @ui
+ def manager.require(x)
+ raise 'foo'
end
+ manager.should_receive(:alert_error).with("Loading command: .]2;nyan. (RuntimeError)\n\tfoo")
+ manager.send :load_and_instantiate, "\e]2;nyan\a"
end
end
end
diff --git a/spec/ruby/security/cve_2020_10663_spec.rb b/spec/ruby/security/cve_2020_10663_spec.rb
index 766590d501..cce1beb012 100644
--- a/spec/ruby/security/cve_2020_10663_spec.rb
+++ b/spec/ruby/security/cve_2020_10663_spec.rb
@@ -18,25 +18,22 @@ module JSONSpecs
end
guard -> {
- ruby_version_is "2.6.6" or
JSON.const_defined?(:Pure) or
version_is(JSON::VERSION, '2.3.0')
} do
- platform_is_not :darwin do # frequent timeout/hang on macOS
- describe "CVE-2020-10663 is resisted by" do
- it "only creating custom objects if passed create_additions: true or using JSON.load" do
- obj = JSONSpecs::MyClass.new("bar")
- JSONSpecs::MyClass.should.json_creatable?
- json = JSON.dump(obj)
+ describe "CVE-2020-10663 is resisted by" do
+ it "only creating custom objects if passed create_additions: true or using JSON.load" do
+ obj = JSONSpecs::MyClass.new("bar")
+ JSONSpecs::MyClass.should.json_creatable?
+ json = JSON.dump(obj)
- JSON.parse(json, create_additions: true).class.should == JSONSpecs::MyClass
- JSON(json, create_additions: true).class.should == JSONSpecs::MyClass
- JSON.load(json).class.should == JSONSpecs::MyClass
+ JSON.parse(json, create_additions: true).class.should == JSONSpecs::MyClass
+ JSON(json, create_additions: true).class.should == JSONSpecs::MyClass
+ JSON.load(json).class.should == JSONSpecs::MyClass
- JSON.parse(json).class.should == Hash
- JSON.parse(json, nil).class.should == Hash
- JSON(json).class.should == Hash
- end
+ JSON.parse(json).class.should == Hash
+ JSON.parse(json, nil).class.should == Hash
+ JSON(json).class.should == Hash
end
end
end
diff --git a/spec/ruby/shared/file/executable.rb b/spec/ruby/shared/file/executable.rb
index 7b5c4c580c..baa156de98 100644
--- a/spec/ruby/shared/file/executable.rb
+++ b/spec/ruby/shared/file/executable.rb
@@ -39,6 +39,41 @@ describe :file_executable, shared: true do
-> { @object.send(@method, nil) }.should raise_error(TypeError)
-> { @object.send(@method, false) }.should raise_error(TypeError)
end
+
+ platform_is_not :windows do
+ as_superuser do
+ context "when run by a superuser" do
+ before :each do
+ @file = tmp('temp3.txt')
+ touch @file
+ end
+
+ after :each do
+ rm_r @file
+ end
+
+ it "returns true if file owner has permission to execute" do
+ File.chmod(0766, @file)
+ @object.send(@method, @file).should == true
+ end
+
+ it "returns true if group has permission to execute" do
+ File.chmod(0676, @file)
+ @object.send(@method, @file).should == true
+ end
+
+ it "returns true if other have permission to execute" do
+ File.chmod(0667, @file)
+ @object.send(@method, @file).should == true
+ end
+
+ it "return false if nobody has permission to execute" do
+ File.chmod(0666, @file)
+ @object.send(@method, @file).should == false
+ end
+ end
+ end
+ end
end
describe :file_executable_missing, shared: true do
diff --git a/spec/ruby/shared/file/executable_real.rb b/spec/ruby/shared/file/executable_real.rb
index ce3d5ca176..bf2734ea07 100644
--- a/spec/ruby/shared/file/executable_real.rb
+++ b/spec/ruby/shared/file/executable_real.rb
@@ -37,6 +37,41 @@ describe :file_executable_real, shared: true do
-> { @object.send(@method, nil) }.should raise_error(TypeError)
-> { @object.send(@method, false) }.should raise_error(TypeError)
end
+
+ platform_is_not :windows do
+ as_real_superuser do
+ context "when run by a real superuser" do
+ before :each do
+ @file = tmp('temp3.txt')
+ touch @file
+ end
+
+ after :each do
+ rm_r @file
+ end
+
+ it "returns true if file owner has permission to execute" do
+ File.chmod(0766, @file)
+ @object.send(@method, @file).should == true
+ end
+
+ it "returns true if group has permission to execute" do
+ File.chmod(0676, @file)
+ @object.send(@method, @file).should == true
+ end
+
+ it "returns true if other have permission to execute" do
+ File.chmod(0667, @file)
+ @object.send(@method, @file).should == true
+ end
+
+ it "return false if nobody has permission to execute" do
+ File.chmod(0666, @file)
+ @object.send(@method, @file).should == false
+ end
+ end
+ end
+ end
end
describe :file_executable_real_missing, shared: true do
diff --git a/spec/ruby/shared/file/exist.rb b/spec/ruby/shared/file/exist.rb
index 3bd97711b4..67424146c5 100644
--- a/spec/ruby/shared/file/exist.rb
+++ b/spec/ruby/shared/file/exist.rb
@@ -4,11 +4,6 @@ describe :file_exist, shared: true do
@object.send(@method, 'a_fake_file').should == false
end
- it "returns true if the file exist using the alias exists?" do
- @object.send(@method, __FILE__).should == true
- @object.send(@method, 'a_fake_file').should == false
- end
-
it "raises an ArgumentError if not passed one argument" do
-> { @object.send(@method) }.should raise_error(ArgumentError)
-> { @object.send(@method, __FILE__, __FILE__) }.should raise_error(ArgumentError)
diff --git a/spec/ruby/shared/file/readable.rb b/spec/ruby/shared/file/readable.rb
index eb2ca06812..7b45e23e36 100644
--- a/spec/ruby/shared/file/readable.rb
+++ b/spec/ruby/shared/file/readable.rb
@@ -24,6 +24,22 @@ describe :file_readable, shared: true do
it "accepts an object that has a #to_path method" do
@object.send(@method, mock_to_path(@file2)).should == true
end
+
+ platform_is_not :windows do
+ as_superuser do
+ context "when run by a superuser" do
+ it "returns true unconditionally" do
+ file = tmp('temp.txt')
+ touch file
+
+ File.chmod(0333, file)
+ @object.send(@method, file).should == true
+
+ rm_r file
+ end
+ end
+ end
+ end
end
describe :file_readable_missing, shared: true do
diff --git a/spec/ruby/shared/file/readable_real.rb b/spec/ruby/shared/file/readable_real.rb
index b6e53ac76d..32d38bc7a2 100644
--- a/spec/ruby/shared/file/readable_real.rb
+++ b/spec/ruby/shared/file/readable_real.rb
@@ -14,6 +14,22 @@ describe :file_readable_real, shared: true do
it "accepts an object that has a #to_path method" do
File.open(@file,'w') { @object.send(@method, mock_to_path(@file)).should == true }
end
+
+ platform_is_not :windows do
+ as_real_superuser do
+ context "when run by a real superuser" do
+ it "returns true unconditionally" do
+ file = tmp('temp.txt')
+ touch file
+
+ File.chmod(0333, file)
+ @object.send(@method, file).should == true
+
+ rm_r file
+ end
+ end
+ end
+ end
end
describe :file_readable_real_missing, shared: true do
diff --git a/spec/ruby/shared/file/writable.rb b/spec/ruby/shared/file/writable.rb
index 4bb8aedce6..65ea2c1781 100644
--- a/spec/ruby/shared/file/writable.rb
+++ b/spec/ruby/shared/file/writable.rb
@@ -19,6 +19,22 @@ describe :file_writable, shared: true do
it "accepts an object that has a #to_path method" do
File.open(@file,'w') { @object.send(@method, mock_to_path(@file)).should == true }
end
+
+ platform_is_not :windows do
+ as_superuser do
+ context "when run by a superuser" do
+ it "returns true unconditionally" do
+ file = tmp('temp.txt')
+ touch file
+
+ File.chmod(0555, file)
+ @object.send(@method, file).should == true
+
+ rm_r file
+ end
+ end
+ end
+ end
end
describe :file_writable_missing, shared: true do
diff --git a/spec/ruby/shared/file/writable_real.rb b/spec/ruby/shared/file/writable_real.rb
index e9721fd379..b4a0a58c6e 100644
--- a/spec/ruby/shared/file/writable_real.rb
+++ b/spec/ruby/shared/file/writable_real.rb
@@ -24,6 +24,22 @@ describe :file_writable_real, shared: true do
-> { @object.send(@method, nil) }.should raise_error(TypeError)
-> { @object.send(@method, false) }.should raise_error(TypeError)
end
+
+ platform_is_not :windows do
+ as_real_superuser do
+ context "when run by a real superuser" do
+ it "returns true unconditionally" do
+ file = tmp('temp.txt')
+ touch file
+
+ File.chmod(0555, file)
+ @object.send(@method, file).should == true
+
+ rm_r file
+ end
+ end
+ end
+ end
end
describe :file_writable_real_missing, shared: true do
diff --git a/spec/ruby/shared/kernel/at_exit.rb b/spec/ruby/shared/kernel/at_exit.rb
new file mode 100644
index 0000000000..16d41cb01c
--- /dev/null
+++ b/spec/ruby/shared/kernel/at_exit.rb
@@ -0,0 +1,70 @@
+describe :kernel_at_exit, shared: true do
+ it "runs after all other code" do
+ ruby_exe("#{@method} { print 5 }; print 6").should == "65"
+ end
+
+ it "runs in reverse order of registration" do
+ code = "#{@method} { print 4 }; #{@method} { print 5 }; print 6; #{@method} { print 7 }"
+ ruby_exe(code).should == "6754"
+ end
+
+ it "allows calling exit inside a handler" do
+ code = "#{@method} { print 3 }; #{@method} { print 4; exit; print 5 }; #{@method} { print 6 }"
+ ruby_exe(code).should == "643"
+ end
+
+ it "gives access to the last raised exception - global variables $! and $@" do
+ code = <<-EOC
+ #{@method} {
+ puts "The exception matches: \#{$! == $exception && $@ == $exception.backtrace} (message=\#{$!.message})"
+ }
+
+ begin
+ raise "foo"
+ rescue => $exception
+ raise
+ end
+ EOC
+
+ result = ruby_exe(code, args: "2>&1", exit_status: 1)
+ result.lines.should.include?("The exception matches: true (message=foo)\n")
+ end
+
+ it "both exceptions in a handler and in the main script are printed" do
+ code = "#{@method} { raise 'at_exit_error' }; raise 'main_script_error'"
+ result = ruby_exe(code, args: "2>&1", exit_status: 1)
+ result.should.include?('at_exit_error (RuntimeError)')
+ result.should.include?('main_script_error (RuntimeError)')
+ end
+
+ it "decides the exit status if both at_exit and the main script raise SystemExit" do
+ ruby_exe("#{@method} { exit 43 }; exit 42", args: "2>&1", exit_status: 43)
+ $?.exitstatus.should == 43
+ end
+
+ it "runs all handlers even if some raise exceptions" do
+ code = "#{@method} { STDERR.puts 'last' }; #{@method} { exit 43 }; #{@method} { STDERR.puts 'first' }; exit 42"
+ result = ruby_exe(code, args: "2>&1", exit_status: 43)
+ result.should == "first\nlast\n"
+ $?.exitstatus.should == 43
+ end
+
+ it "runs handlers even if the main script fails to parse" do
+ script = fixture(__FILE__, "#{@method}.rb")
+ result = ruby_exe('{', options: "-r#{script}", args: "2>&1", exit_status: 1)
+ $?.should_not.success?
+ result.should.include?("handler ran\n")
+
+ # it's tempting not to rely on error message and rely only on exception class name,
+ # but CRuby before 3.2 doesn't print class name for syntax error
+ result.should include_any_of("syntax error", "SyntaxError")
+ end
+
+ it "calls the nested handler right after the outer one if a handler is nested into another handler" do
+ ruby_exe(<<~ruby).should == "last\nbefore\nafter\nnested\nfirst\n"
+ #{@method} { puts :first }
+ #{@method} { puts :before; #{@method} { puts :nested }; puts :after };
+ #{@method} { puts :last }
+ ruby
+ end
+end
diff --git a/spec/ruby/shared/kernel/complex.rb b/spec/ruby/shared/kernel/complex.rb
new file mode 100644
index 0000000000..98ee0b2b3f
--- /dev/null
+++ b/spec/ruby/shared/kernel/complex.rb
@@ -0,0 +1,133 @@
+# Specs shared by Kernel#Complex() and String#to_c()
+describe :kernel_complex, shared: true do
+
+ it "returns a Complex object" do
+ @object.send(@method, '9').should be_an_instance_of(Complex)
+ end
+
+ it "understands integers" do
+ @object.send(@method, '20').should == Complex(20)
+ end
+
+ it "understands negative integers" do
+ @object.send(@method, '-3').should == Complex(-3)
+ end
+
+ it "understands fractions (numerator/denominator) for the real part" do
+ @object.send(@method, '2/3').should == Complex(Rational(2, 3))
+ end
+
+ it "understands fractions (numerator/denominator) for the imaginary part" do
+ @object.send(@method, '4+2/3i').should == Complex(4, Rational(2, 3))
+ end
+
+ it "understands negative fractions (-numerator/denominator) for the real part" do
+ @object.send(@method, '-2/3').should == Complex(Rational(-2, 3))
+ end
+
+ it "understands negative fractions (-numerator/denominator) for the imaginary part" do
+ @object.send(@method, '7-2/3i').should == Complex(7, Rational(-2, 3))
+ end
+
+ it "understands floats (a.b) for the real part" do
+ @object.send(@method, '2.3').should == Complex(2.3)
+ end
+
+ it "understands floats (a.b) for the imaginary part" do
+ @object.send(@method, '4+2.3i').should == Complex(4, 2.3)
+ end
+
+ it "understands negative floats (-a.b) for the real part" do
+ @object.send(@method, '-2.33').should == Complex(-2.33)
+ end
+
+ it "understands negative floats (-a.b) for the imaginary part" do
+ @object.send(@method, '7-28.771i').should == Complex(7, -28.771)
+ end
+
+ it "understands an integer followed by 'i' to mean that integer is the imaginary part" do
+ @object.send(@method, '35i').should == Complex(0,35)
+ end
+
+ it "understands a negative integer followed by 'i' to mean that negative integer is the imaginary part" do
+ @object.send(@method, '-29i').should == Complex(0,-29)
+ end
+
+ it "understands an 'i' by itself as denoting a complex number with an imaginary part of 1" do
+ @object.send(@method, 'i').should == Complex(0,1)
+ end
+
+ it "understands a '-i' by itself as denoting a complex number with an imaginary part of -1" do
+ @object.send(@method, '-i').should == Complex(0,-1)
+ end
+
+ it "understands 'a+bi' to mean a complex number with 'a' as the real part, 'b' as the imaginary" do
+ @object.send(@method, '79+4i').should == Complex(79,4)
+ end
+
+ it "understands 'a-bi' to mean a complex number with 'a' as the real part, '-b' as the imaginary" do
+ @object.send(@method, '79-4i').should == Complex(79,-4)
+ end
+
+ it "understands 'a+i' to mean a complex number with 'a' as the real part, 1i as the imaginary" do
+ @object.send(@method, '79+i').should == Complex(79, 1)
+ end
+
+ it "understands 'a-i' to mean a complex number with 'a' as the real part, -1i as the imaginary" do
+ @object.send(@method, '79-i').should == Complex(79, -1)
+ end
+
+ it "understands i, I, j, and J imaginary units" do
+ @object.send(@method, '79+4i').should == Complex(79, 4)
+ @object.send(@method, '79+4I').should == Complex(79, 4)
+ @object.send(@method, '79+4j').should == Complex(79, 4)
+ @object.send(@method, '79+4J').should == Complex(79, 4)
+ end
+
+ it "understands scientific notation for the real part" do
+ @object.send(@method, '2e3+4i').should == Complex(2e3,4)
+ end
+
+ it "understands negative scientific notation for the real part" do
+ @object.send(@method, '-2e3+4i').should == Complex(-2e3,4)
+ end
+
+ it "understands scientific notation for the imaginary part" do
+ @object.send(@method, '4+2e3i').should == Complex(4, 2e3)
+ end
+
+ it "understands negative scientific notation for the imaginary part" do
+ @object.send(@method, '4-2e3i').should == Complex(4, -2e3)
+ end
+
+ it "understands scientific notation for the real and imaginary part in the same String" do
+ @object.send(@method, '2e3+2e4i').should == Complex(2e3,2e4)
+ end
+
+ it "understands negative scientific notation for the real and imaginary part in the same String" do
+ @object.send(@method, '-2e3-2e4i').should == Complex(-2e3,-2e4)
+ end
+
+ it "understands scientific notation with e and E" do
+ @object.send(@method, '2e3+2e4i').should == Complex(2e3, 2e4)
+ @object.send(@method, '2E3+2E4i').should == Complex(2e3, 2e4)
+ end
+
+ it "understands 'm@a' to mean a complex number in polar form with 'm' as the modulus, 'a' as the argument" do
+ @object.send(@method, '79@4').should == Complex.polar(79, 4)
+ @object.send(@method, '-79@4').should == Complex.polar(-79, 4)
+ @object.send(@method, '79@-4').should == Complex.polar(79, -4)
+ end
+
+ it "ignores leading whitespaces" do
+ @object.send(@method, ' 79+4i').should == Complex(79, 4)
+ end
+
+ it "ignores trailing whitespaces" do
+ @object.send(@method, '79+4i ').should == Complex(79, 4)
+ end
+
+ it "understands _" do
+ @object.send(@method, '7_9+4_0i').should == Complex(79, 40)
+ end
+end
diff --git a/spec/ruby/shared/kernel/fixtures/END.rb b/spec/ruby/shared/kernel/fixtures/END.rb
new file mode 100644
index 0000000000..cc8ac17c36
--- /dev/null
+++ b/spec/ruby/shared/kernel/fixtures/END.rb
@@ -0,0 +1,3 @@
+END {
+ STDERR.puts "handler ran"
+}
diff --git a/spec/ruby/shared/kernel/fixtures/at_exit.rb b/spec/ruby/shared/kernel/fixtures/at_exit.rb
new file mode 100644
index 0000000000..e7bc8baf52
--- /dev/null
+++ b/spec/ruby/shared/kernel/fixtures/at_exit.rb
@@ -0,0 +1,3 @@
+at_exit do
+ STDERR.puts "handler ran"
+end
diff --git a/spec/ruby/shared/kernel/object_id.rb b/spec/ruby/shared/kernel/object_id.rb
index 7acdb27554..099df8ff94 100644
--- a/spec/ruby/shared/kernel/object_id.rb
+++ b/spec/ruby/shared/kernel/object_id.rb
@@ -52,10 +52,30 @@ describe :object_id, shared: true do
o1.send(@method).should_not == o2.send(@method)
end
- it "returns a different value for two String literals" do
- o1 = "hello"
- o2 = "hello"
- o1.send(@method).should_not == o2.send(@method)
+ guard -> { "test".frozen? && "test".equal?("test") } do # --enable-frozen-string-literal in $RUBYOPT
+ it "returns the same value for two identical String literals" do
+ o1 = "hello"
+ o2 = "hello"
+ o1.send(@method).should == o2.send(@method)
+ end
+ end
+
+ guard -> { "test".frozen? && !"test".equal?("test") } do # chilled string literals
+ it "returns a different frozen value for two String literals" do
+ o1 = "hello"
+ o2 = "hello"
+ o1.send(@method).should_not == o2.send(@method)
+ o1.frozen?.should == true
+ o2.frozen?.should == true
+ end
+ end
+
+ guard -> { !"test".frozen? } do
+ it "returns a different value for two String literals" do
+ o1 = "hello"
+ o2 = "hello"
+ o1.send(@method).should_not == o2.send(@method)
+ end
end
it "returns a different value for an object and its dup" do
diff --git a/spec/ruby/shared/kernel/raise.rb b/spec/ruby/shared/kernel/raise.rb
index 765ba0f929..1917a4c923 100644
--- a/spec/ruby/shared/kernel/raise.rb
+++ b/spec/ruby/shared/kernel/raise.rb
@@ -29,11 +29,41 @@ describe :kernel_raise, shared: true do
@data = data
end
end
- -> { @object.raise(data_error, {:data => 42}) }.should raise_error(data_error) do |ex|
- ex.data.should == {:data => 42}
+
+ -> { @object.raise(data_error, {data: 42}) }.should raise_error(data_error) do |ex|
+ ex.data.should == {data: 42}
end
end
+ # https://bugs.ruby-lang.org/issues/8257#note-36
+ it "allows extra keyword arguments for compatibility" do
+ data_error = Class.new(StandardError) do
+ attr_reader :data
+ def initialize(data)
+ @data = data
+ end
+ end
+
+ -> { @object.raise(data_error, data: 42) }.should raise_error(data_error) do |ex|
+ ex.data.should == {data: 42}
+ end
+ end
+
+ it "does not allow message and extra keyword arguments" do
+ data_error = Class.new(StandardError) do
+ attr_reader :data
+ def initialize(data)
+ @data = data
+ end
+ end
+
+ -> { @object.raise(data_error, {a: 1}, b: 2) }.should raise_error(StandardError) do |e|
+ [TypeError, ArgumentError].should.include?(e.class)
+ end
+
+ -> { @object.raise(data_error, {a: 1}, [], b: 2) }.should raise_error(ArgumentError)
+ end
+
it "raises RuntimeError if no exception class is given" do
-> { @object.raise }.should raise_error(RuntimeError, "")
end
@@ -116,4 +146,15 @@ describe :kernel_raise, shared: true do
@object.raise(ArgumentError, "message", caller)
end.should raise_error(ArgumentError, "message")
end
+
+ ruby_version_is "3.4" do
+ locations = caller_locations(1, 2)
+ it "allows Exception, message, and backtrace_locations parameters" do
+ -> do
+ @object.raise(ArgumentError, "message", locations)
+ end.should raise_error(ArgumentError, "message") { |error|
+ error.backtrace_locations.map(&:to_s).should == locations.map(&:to_s)
+ }
+ end
+ end
end
diff --git a/spec/ruby/shared/process/exit.rb b/spec/ruby/shared/process/exit.rb
index ae8abaea40..1e073614a3 100644
--- a/spec/ruby/shared/process/exit.rb
+++ b/spec/ruby/shared/process/exit.rb
@@ -21,6 +21,12 @@ describe :process_exit, shared: true do
end
end
+ it "raises a SystemExit with message 'exit'" do
+ -> { @object.exit }.should raise_error(SystemExit) { |e|
+ e.message.should == "exit"
+ }
+ end
+
it "tries to convert the passed argument to an Integer using #to_int" do
obj = mock('5')
obj.should_receive(:to_int).and_return(5)
@@ -98,6 +104,12 @@ describe :process_exit!, shared: true do
$?.exitstatus.should == 21
end
+ it "skips ensure clauses" do
+ out = ruby_exe("begin; STDERR.puts 'before'; #{@object}.send(:exit!, 21); ensure; STDERR.puts 'ensure'; end", args: '2>&1', exit_status: 21)
+ out.should == "before\n"
+ $?.exitstatus.should == 21
+ end
+
it "overrides the original exception and exit status when called from #at_exit" do
code = <<-RUBY
at_exit do
diff --git a/spec/ruby/shared/queue/deque.rb b/spec/ruby/shared/queue/deque.rb
index 8b755dd9b7..0abba5301e 100644
--- a/spec/ruby/shared/queue/deque.rb
+++ b/spec/ruby/shared/queue/deque.rb
@@ -37,6 +37,15 @@ describe :queue_deq, shared: true do
q.send(@method).should == 1
end
+ it "converts false-ish for non_blocking to boolean" do
+ q = @object.call
+ q << 1
+ q << 2
+
+ q.send(@method, false).should == 1
+ q.send(@method, nil).should == 2
+ end
+
it "returns nil for a closed empty queue" do
q = @object.call
q.close
@@ -55,6 +64,70 @@ describe :queue_deq, shared: true do
t.join
end
+ describe "with a timeout" do
+ ruby_version_is "3.2" do
+ it "returns an item if one is available in time" do
+ q = @object.call
+
+ t = Thread.new {
+ q.send(@method, timeout: TIME_TOLERANCE).should == 1
+ }
+ Thread.pass until t.status == "sleep" && q.num_waiting == 1
+ q << 1
+ t.join
+ end
+
+ it "returns nil if no item is available in time" do
+ q = @object.call
+
+ Thread.new {
+ q.send(@method, timeout: 0.001).should == nil
+ }.join
+ end
+
+ it "does nothing if the timeout is nil" do
+ q = @object.call
+ t = Thread.new {
+ q.send(@method, timeout: nil).should == 1
+ }
+ Thread.pass until t.status == "sleep" && q.num_waiting == 1
+ q << 1
+ t.join
+ end
+
+ it "immediately returns nil if no item is available and the timeout is 0" do
+ q = @object.call
+ q << 1
+ q.send(@method, timeout: 0).should == 1
+ q.send(@method, timeout: 0).should == nil
+ end
+
+ it "raise TypeError if timeout is not a valid numeric" do
+ q = @object.call
+ -> {
+ q.send(@method, timeout: "1")
+ }.should raise_error(TypeError, "no implicit conversion to float from string")
+
+ -> {
+ q.send(@method, timeout: false)
+ }.should raise_error(TypeError, "no implicit conversion to float from false")
+ end
+
+ it "raise ArgumentError if non_block = true is passed too" do
+ q = @object.call
+ -> {
+ q.send(@method, true, timeout: 1)
+ }.should raise_error(ArgumentError, "can't set a timeout if non_block is enabled")
+ end
+
+ it "returns nil for a closed empty queue" do
+ q = @object.call
+ q.close
+ q.send(@method, timeout: 0).should == nil
+ end
+ end
+ end
+
describe "in non-blocking mode" do
it "removes an item from the queue" do
q = @object.call
@@ -81,5 +154,13 @@ describe :queue_deq, shared: true do
q.close
-> { q.send(@method, true) }.should raise_error(ThreadError)
end
+
+ it "converts true-ish non_blocking argument to true" do
+ q = @object.call
+
+ -> { q.send(@method, true) }.should raise_error(ThreadError)
+ -> { q.send(@method, 1) }.should raise_error(ThreadError)
+ -> { q.send(@method, "") }.should raise_error(ThreadError)
+ end
end
end
diff --git a/spec/ruby/shared/rational/Rational.rb b/spec/ruby/shared/rational/Rational.rb
index 936a90c086..500f7ed271 100644
--- a/spec/ruby/shared/rational/Rational.rb
+++ b/spec/ruby/shared/rational/Rational.rb
@@ -65,40 +65,45 @@ describe :kernel_Rational, shared: true do
r_s.should == r
r_s.should_not == f_r
end
+ end
- describe "when passed a Numeric" do
- it "calls #to_r to convert the first argument to a Rational" do
- num = RationalSpecs::SubNumeric.new(2)
+ describe "when passed a Numeric" do
+ it "calls #to_r to convert the first argument to a Rational" do
+ num = RationalSpecs::SubNumeric.new(2)
- Rational(num).should == Rational(2)
- end
+ Rational(num).should == Rational(2)
end
+ end
- describe "when passed a Complex" do
- it "returns a Rational from the real part if the imaginary part is 0" do
- Rational(Complex(1, 0)).should == Rational(1)
- end
-
- it "raises a RangeError if the imaginary part is not 0" do
- -> { Rational(Complex(1, 2)) }.should raise_error(RangeError)
- end
+ describe "when passed a Complex" do
+ it "returns a Rational from the real part if the imaginary part is 0" do
+ Rational(Complex(1, 0)).should == Rational(1)
end
- it "raises a TypeError if the first argument is nil" do
- -> { Rational(nil) }.should raise_error(TypeError)
+ it "raises a RangeError if the imaginary part is not 0" do
+ -> { Rational(Complex(1, 2)) }.should raise_error(RangeError)
end
+ end
- it "raises a TypeError if the second argument is nil" do
- -> { Rational(1, nil) }.should raise_error(TypeError)
- 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 a Symbol" do
- -> { Rational(:sym) }.should raise_error(TypeError)
- end
+ it "raises a TypeError if the first argument is nil" do
+ -> { Rational(nil) }.should raise_error(TypeError)
+ end
- it "raises a TypeError if the second argument is a Symbol" do
- -> { Rational(1, :sym) }.should raise_error(TypeError)
- end
+ it "raises a TypeError if the second argument is nil" do
+ -> { Rational(1, nil) }.should raise_error(TypeError)
+ end
+
+ it "raises a TypeError if the first argument is a Symbol" do
+ -> { Rational(:sym) }.should raise_error(TypeError)
+ end
+
+ it "raises a TypeError if the second argument is a Symbol" do
+ -> { Rational(1, :sym) }.should raise_error(TypeError)
end
describe "when passed exception: false" do
@@ -138,4 +143,8 @@ describe :kernel_Rational, shared: true do
end
end
end
+
+ it "freezes its result" do
+ Rational(1).frozen?.should == true
+ end
end
diff --git a/spec/ruby/shared/rational/coerce.rb b/spec/ruby/shared/rational/coerce.rb
deleted file mode 100644
index ccc8901ba0..0000000000
--- a/spec/ruby/shared/rational/coerce.rb
+++ /dev/null
@@ -1,34 +0,0 @@
-require_relative '../../spec_helper'
-
-require 'bigdecimal'
-
-describe :rational_coerce, shared: true do
- it "returns the passed argument, self as Float, when given a Float" do
- result = Rational(3, 4).coerce(1.0)
- result.should == [1.0, 0.75]
- result.first.is_a?(Float).should be_true
- result.last.is_a?(Float).should be_true
- end
-
- it "returns the passed argument, self as Rational, when given an Integer" do
- result = Rational(3, 4).coerce(10)
- result.should == [Rational(10, 1), Rational(3, 4)]
- result.first.is_a?(Rational).should be_true
- result.last.is_a?(Rational).should be_true
- end
-
- it "coerces to Rational, when given a Complex" do
- Rational(3, 4).coerce(Complex(5)).should == [Rational(5, 1), Rational(3, 4)]
- Rational(12, 4).coerce(Complex(5, 1)).should == [Complex(5, 1), Complex(3)]
- end
-
- it "returns [argument, self] when given a Rational" do
- Rational(3, 7).coerce(Rational(9, 2)).should == [Rational(9, 2), Rational(3, 7)]
- end
-
- it "raises an error when passed a BigDecimal" do
- -> {
- Rational(500, 3).coerce(BigDecimal('166.666666666'))
- }.should raise_error(TypeError, /BigDecimal can't be coerced into Rational/)
- end
-end
diff --git a/spec/ruby/shared/rational/divmod.rb b/spec/ruby/shared/rational/divmod.rb
index 471cd7a967..9e23a18186 100644
--- a/spec/ruby/shared/rational/divmod.rb
+++ b/spec/ruby/shared/rational/divmod.rb
@@ -6,7 +6,7 @@ describe :rational_divmod_rat, shared: true do
Rational(7, 4).divmod(Rational(-1, 2)).should eql([-4, Rational(-1, 4)])
Rational(0, 4).divmod(Rational(4, 3)).should eql([0, Rational(0, 1)])
- Rational(bignum_value, 4).divmod(Rational(4, 3)).should eql([1729382256910270464, 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
@@ -19,7 +19,7 @@ describe :rational_divmod_int, shared: true do
Rational(7, 4).divmod(2).should eql([0, Rational(7, 4)])
Rational(7, 4).divmod(-2).should eql([-1, Rational(-1, 4)])
- Rational(bignum_value, 4).divmod(3).should == [768614336404564650, Rational(2, 1)]
+ Rational(bignum_value, 4).divmod(3).should eql([1537228672809129301, Rational(1, 1)])
end
it "raises a ZeroDivisionError when passed 0" do
diff --git a/spec/ruby/shared/rational/exponent.rb b/spec/ruby/shared/rational/exponent.rb
index 3fd02de08f..b0e9b23574 100644
--- a/spec/ruby/shared/rational/exponent.rb
+++ b/spec/ruby/shared/rational/exponent.rb
@@ -40,10 +40,10 @@ describe :rational_exponent, shared: true do
(Rational(-3, 4) ** -4).should == Rational(256, 81)
(Rational(3, -4) ** -4).should == Rational(256, 81)
- (Rational(bignum_value, 4) ** 4).should == Rational(28269553036454149273332760011886696253239742350009903329945699220681916416, 1)
- (Rational(3, bignum_value) ** -4).should == Rational(7237005577332262213973186563042994240829374041602535252466099000494570602496, 81)
- (Rational(-bignum_value, 4) ** -4).should == Rational(1, 28269553036454149273332760011886696253239742350009903329945699220681916416)
- (Rational(3, -bignum_value) ** -4).should == Rational(7237005577332262213973186563042994240829374041602535252466099000494570602496, 81)
+ (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
diff --git a/spec/ruby/shared/rational/marshal_dump.rb b/spec/ruby/shared/rational/marshal_dump.rb
deleted file mode 100644
index 09782b45a5..0000000000
--- a/spec/ruby/shared/rational/marshal_dump.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-require_relative '../../spec_helper'
-
-describe :rational_marshal_dump, shared: true do
- it "needs to be reviewed for spec completeness"
-end
diff --git a/spec/ruby/shared/rational/marshal_load.rb b/spec/ruby/shared/rational/marshal_load.rb
deleted file mode 100644
index 20bdd6fdf4..0000000000
--- a/spec/ruby/shared/rational/marshal_load.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-require_relative '../../spec_helper'
-
-describe :rational_marshal_load, shared: true do
- it "needs to be reviewed for spec completeness"
-end
diff --git a/spec/ruby/shared/rational/minus.rb b/spec/ruby/shared/rational/minus.rb
deleted file mode 100644
index 0a0946fdb9..0000000000
--- a/spec/ruby/shared/rational/minus.rb
+++ /dev/null
@@ -1,48 +0,0 @@
-require_relative '../../spec_helper'
-
-describe :rational_minus_rat, shared: true do
- it "returns the result of subtracting other from self as a Rational" do
- (Rational(3, 4) - Rational(0, 1)).should eql(Rational(3, 4))
- (Rational(3, 4) - Rational(1, 4)).should eql(Rational(1, 2))
-
- (Rational(3, 4) - Rational(2, 1)).should eql(Rational(-5, 4))
- end
-end
-
-describe :rational_minus_int, shared: true do
- it "returns the result of subtracting other from self as a Rational" do
- (Rational(3, 4) - 1).should eql(Rational(-1, 4))
- (Rational(3, 4) - 2).should eql(Rational(-5, 4))
- end
-end
-
-describe :rational_minus_float, shared: true do
- it "returns the result of subtracting other from self as a Float" do
- (Rational(3, 4) - 0.2).should eql(0.55)
- (Rational(3, 4) - 2.5).should eql(-1.75)
- end
-end
-
-describe :rational_minus, shared: true do
- it "calls #coerce on the passed argument with self" do
- rational = Rational(3, 4)
- obj = mock("Object")
- obj.should_receive(:coerce).with(rational).and_return([1, 2])
-
- rational - obj
- end
-
- it "calls #- on the coerced Rational with the coerced Object" do
- rational = Rational(3, 4)
-
- coerced_rational = mock("Coerced Rational")
- coerced_rational.should_receive(:-).and_return(:result)
-
- coerced_obj = mock("Coerced Object")
-
- obj = mock("Object")
- obj.should_receive(:coerce).and_return([coerced_rational, coerced_obj])
-
- (rational - obj).should == :result
- end
-end
diff --git a/spec/ruby/shared/rational/quo.rb b/spec/ruby/shared/rational/quo.rb
deleted file mode 100644
index 53b32fed2f..0000000000
--- a/spec/ruby/shared/rational/quo.rb
+++ /dev/null
@@ -1,5 +0,0 @@
-require_relative '../../spec_helper'
-
-describe :rational_quo, shared: true do
- it "needs to be reviewed for spec completeness"
-end
diff --git a/spec/ruby/shared/rational/to_f.rb b/spec/ruby/shared/rational/to_f.rb
index 56e0b61d68..472a585daa 100644
--- a/spec/ruby/shared/rational/to_f.rb
+++ b/spec/ruby/shared/rational/to_f.rb
@@ -7,4 +7,10 @@ describe :rational_to_f, shared: true do
Rational(-1, 4).to_f.should eql(-0.25)
Rational(-1, -4).to_f.should eql(0.25)
end
+
+ it "converts to a Float for large numerator and denominator" do
+ num = 1000000000000000000000000000000000048148248609680896326399448564623182963452541226153892315137780403285956264146010000000000000000000000000000000000048148248609680896326399448564623182963452541226153892315137780403285956264146010000000000000000000000000000000000048148248609680896326399448564623182963452541226153892315137780403285956264146009
+ den = 2000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
+ Rational(num, den).to_f.should == 500.0
+ end
end
diff --git a/spec/ruby/shared/rational/truncate.rb b/spec/ruby/shared/rational/truncate.rb
index 761dd3113a..df5198ca02 100644
--- a/spec/ruby/shared/rational/truncate.rb
+++ b/spec/ruby/shared/rational/truncate.rb
@@ -17,6 +17,18 @@ describe :rational_truncate, shared: true do
end
end
+ describe "with an explicit precision = 0" do
+ it "returns an integer" do
+ @rational.truncate(0).should be_kind_of(Integer)
+ end
+
+ it "returns the truncated value toward 0" do
+ @rational.truncate(0).should == 314
+ Rational(1, 2).truncate(0).should == 0
+ Rational(-1, 2).truncate(0).should == 0
+ end
+ end
+
describe "with a precision < 0" do
it "returns an integer" do
@rational.truncate(-2).should be_kind_of(Integer)
@@ -42,4 +54,18 @@ describe :rational_truncate, shared: true do
@rational.truncate(3).should == Rational(62857, 200)
end
end
+
+ describe "with an invalid value for precision" do
+ it "raises a TypeError" do
+ -> { @rational.truncate(nil) }.should raise_error(TypeError, "not an integer")
+ -> { @rational.truncate(1.0) }.should raise_error(TypeError, "not an integer")
+ -> { @rational.truncate('') }.should raise_error(TypeError, "not an integer")
+ end
+
+ it "does not call to_int on the argument" do
+ object = Object.new
+ object.should_not_receive(:to_int)
+ -> { @rational.truncate(object) }.should raise_error(TypeError, "not an integer")
+ end
+ end
end
diff --git a/spec/ruby/shared/sizedqueue/enque.rb b/spec/ruby/shared/sizedqueue/enque.rb
index 6ef12349f8..2f25517675 100644
--- a/spec/ruby/shared/sizedqueue/enque.rb
+++ b/spec/ruby/shared/sizedqueue/enque.rb
@@ -37,7 +37,7 @@ describe :sizedqueue_enq, shared: true do
q << 1
t = Thread.new {
- -> { q.send(@method, 2) }.should raise_error(ClosedQueueError)
+ -> { q.send(@method, 2) }.should raise_error(ClosedQueueError, "queue closed")
}
Thread.pass until q.num_waiting == 1
@@ -47,4 +47,85 @@ describe :sizedqueue_enq, shared: true do
t.join
q.pop.should == 1
end
+
+ describe "with a timeout" do
+ ruby_version_is "3.2" do
+ it "returns self if the item was pushed in time" do
+ q = @object.call(1)
+ q << 1
+
+ t = Thread.new {
+ q.send(@method, 2, timeout: TIME_TOLERANCE).should == q
+ }
+ Thread.pass until t.status == "sleep" && q.num_waiting == 1
+ q.pop
+ t.join
+ end
+
+ it "does nothing if the timeout is nil" do
+ q = @object.call(1)
+ q << 1
+ t = Thread.new {
+ q.send(@method, 2, timeout: nil).should == q
+ }
+ t.join(0.2).should == nil
+ q.pop
+ t.join
+ end
+
+ it "returns nil if no space is available and timeout is 0" do
+ q = @object.call(1)
+ q.send(@method, 1, timeout: 0).should == q
+ q.send(@method, 2, timeout: 0).should == nil
+ end
+
+ it "returns nil if no space is available in time" do
+ q = @object.call(1)
+ q << 1
+ Thread.new {
+ q.send(@method, 2, timeout: 0.001).should == nil
+ }.join
+ end
+
+ it "raise TypeError if timeout is not a valid numeric" do
+ q = @object.call(1)
+ -> {
+ q.send(@method, 2, timeout: "1")
+ }.should raise_error(TypeError, "no implicit conversion to float from string")
+
+ -> {
+ q.send(@method, 2, timeout: false)
+ }.should raise_error(TypeError, "no implicit conversion to float from false")
+ end
+
+ it "raise ArgumentError if non_block = true is passed too" do
+ q = @object.call(1)
+ -> {
+ q.send(@method, 2, true, timeout: 1)
+ }.should raise_error(ArgumentError, "can't set a timeout if non_block is enabled")
+ end
+
+ it "raise ClosedQueueError when closed before enqueued" do
+ q = @object.call(1)
+ q.close
+ -> { q.send(@method, 2, timeout: 1) }.should raise_error(ClosedQueueError, "queue closed")
+ end
+
+ it "interrupts enqueuing threads with ClosedQueueError when the queue is closed" do
+ q = @object.call(1)
+ q << 1
+
+ t = Thread.new {
+ -> { q.send(@method, 1, timeout: TIME_TOLERANCE) }.should raise_error(ClosedQueueError, "queue closed")
+ }
+
+ Thread.pass until q.num_waiting == 1
+
+ q.close
+
+ t.join
+ q.pop.should == 1
+ end
+ end
+ end
end
diff --git a/spec/ruby/shared/sizedqueue/new.rb b/spec/ruby/shared/sizedqueue/new.rb
index 713785fb50..2573194efb 100644
--- a/spec/ruby/shared/sizedqueue/new.rb
+++ b/spec/ruby/shared/sizedqueue/new.rb
@@ -1,7 +1,12 @@
describe :sizedqueue_new, shared: true do
- it "raises a TypeError when the given argument is not Numeric" do
- -> { @object.call("foo") }.should raise_error(TypeError)
+ it "raises a TypeError when the given argument doesn't respond to #to_int" do
+ -> { @object.call("12") }.should raise_error(TypeError)
-> { @object.call(Object.new) }.should raise_error(TypeError)
+
+ @object.call(12.9).max.should == 12
+ object = Object.new
+ object.define_singleton_method(:to_int) { 42 }
+ @object.call(object).max.should == 42
end
it "raises an argument error when no argument is given" do
diff --git a/spec/ruby/shared/string/end_with.rb b/spec/ruby/shared/string/end_with.rb
index 5f2a011235..94a7f97513 100644
--- a/spec/ruby/shared/string/end_with.rb
+++ b/spec/ruby/shared/string/end_with.rb
@@ -38,7 +38,7 @@ describe :end_with, shared: true do
it "uses only the needed arguments" do
find = mock('h')
find.should_not_receive(:to_str)
- "hello".send(@method).should.end_with?("o",find)
+ "hello".send(@method).should.end_with?("o", find)
end
it "works for multibyte strings" do
@@ -51,4 +51,11 @@ describe :end_with, shared: true do
"あれ".send(@method).end_with?(pat)
end.should raise_error(Encoding::CompatibilityError)
end
+
+ it "checks that we are starting to match at the head of a character" do
+ "\xC3\xA9".send(@method).should_not.end_with?("\xA9")
+ "\xe3\x81\x82".send(@method).should_not.end_with?("\x82")
+ "ab".dup.force_encoding("UTF-16BE").send(@method).should_not.end_with?(
+ "b".dup.force_encoding("UTF-16BE"))
+ end
end
diff --git a/spec/ruby/shared/string/start_with.rb b/spec/ruby/shared/string/start_with.rb
index d8d6e13f6a..4b947a3bbf 100644
--- a/spec/ruby/shared/string/start_with.rb
+++ b/spec/ruby/shared/string/start_with.rb
@@ -69,4 +69,16 @@ describe :start_with, shared: true do
Regexp.last_match.should be_nil
$1.should be_nil
end
+
+ ruby_version_is ""..."3.3" do
+ it "does not check that we are not matching part of a character" do
+ "\xC3\xA9".send(@method).should.start_with?("\xC3")
+ end
+ end
+
+ ruby_version_is "3.3" do # #19784
+ it "checks that we are not matching part of a character" do
+ "\xC3\xA9".send(@method).should_not.start_with?("\xC3")
+ end
+ end
end
diff --git a/spec/ruby/shared/string/times.rb b/spec/ruby/shared/string/times.rb
index cd4edf5340..aaf748bad9 100644
--- a/spec/ruby/shared/string/times.rb
+++ b/spec/ruby/shared/string/times.rb
@@ -32,36 +32,14 @@ describe :string_times, shared: true do
@object.call("", max_long).should == ""
end
- ruby_version_is ''...'3.0' do
- it "returns subclass instances" do
- @object.call(MyString.new("cool"), 0).should be_an_instance_of(MyString)
- @object.call(MyString.new("cool"), 1).should be_an_instance_of(MyString)
- @object.call(MyString.new("cool"), 2).should be_an_instance_of(MyString)
- end
- end
-
- ruby_version_is '3.0' do
- it "returns String instances" do
- @object.call(MyString.new("cool"), 0).should be_an_instance_of(String)
- @object.call(MyString.new("cool"), 1).should be_an_instance_of(String)
- @object.call(MyString.new("cool"), 2).should be_an_instance_of(String)
- end
- end
-
- ruby_version_is ''...'2.7' do
- it "always taints the result when self is tainted" do
- ["", "OK", MyString.new(""), MyString.new("OK")].each do |str|
- str.taint
-
- [0, 1, 2].each do |arg|
- @object.call(str, arg).should.tainted?
- end
- end
- end
+ it "returns String instances" do
+ @object.call(MyString.new("cool"), 0).should be_an_instance_of(String)
+ @object.call(MyString.new("cool"), 1).should be_an_instance_of(String)
+ @object.call(MyString.new("cool"), 2).should be_an_instance_of(String)
end
it "returns a String in the same encoding as self" do
- str = "\xE3\x81\x82".force_encoding Encoding::UTF_8
+ str = "\xE3\x81\x82".dup.force_encoding Encoding::UTF_8
result = @object.call(str, 2)
result.encoding.should equal(Encoding::UTF_8)
end
diff --git a/spec/ruby/shared/types/rb_num2dbl_fails.rb b/spec/ruby/shared/types/rb_num2dbl_fails.rb
new file mode 100644
index 0000000000..ec7cc11986
--- /dev/null
+++ b/spec/ruby/shared/types/rb_num2dbl_fails.rb
@@ -0,0 +1,17 @@
+#
+# Shared tests for rb_num2dbl related conversion failures.
+#
+# Usage example:
+# it_behaves_like :rb_num2dbl_fails, nil, -> v { o = A.new; o.foo(v) }
+#
+
+describe :rb_num2dbl_fails, shared: true do
+ it "fails if string is provided" do
+ -> { @object.call("123") }.should raise_error(TypeError, "no implicit conversion to float from string")
+ end
+
+ it "fails if boolean is provided" do
+ -> { @object.call(true) }.should raise_error(TypeError, "no implicit conversion to float from true")
+ -> { @object.call(false) }.should raise_error(TypeError, "no implicit conversion to float from false")
+ end
+end
diff --git a/spec/ruby/spec_helper.rb b/spec/ruby/spec_helper.rb
index c38965d3c5..af1c385878 100644
--- a/spec/ruby/spec_helper.rb
+++ b/spec/ruby/spec_helper.rb
@@ -1,5 +1,5 @@
use_realpath = File.respond_to?(:realpath)
-root = File.dirname(__FILE__)
+root = __dir__
dir = "fixtures/code"
CODE_LOADING_DIR = use_realpath ? File.realpath(dir, root) : File.expand_path(dir, root)
@@ -14,8 +14,7 @@ else
end
end
-# Running directly with ruby some_spec.rb
-unless ENV['MSPEC_RUNNER']
+unless ENV['MSPEC_RUNNER'] # Running directly with ruby some_spec.rb
mspec_lib = File.expand_path("../../mspec/lib", __FILE__)
$LOAD_PATH << mspec_lib if File.directory?(mspec_lib)
@@ -26,7 +25,14 @@ unless ENV['MSPEC_RUNNER']
puts "Please add -Ipath/to/mspec/lib or clone mspec as a sibling to run the specs."
exit 1
end
+end
+
+# Compare with SpecVersion directly here so it works even with --unguarded
+if VersionGuard::FULL_RUBY_VERSION < SpecVersion.new('2.7')
+ abort "This version of ruby/spec requires Ruby 2.7+"
+end
+unless ENV['MSPEC_RUNNER'] # Running directly with ruby some_spec.rb
ARGV.unshift $0
MSpecRun.main
end