From 1b3382cbab83f0dbf21b0d3683d4ab5335f6c342 Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Sun, 4 Jan 2026 14:53:24 +0100 Subject: [PATCH 1/8] Update to ruby/spec@f54296d --- spec/ruby/.rubocop.yml | 1 + spec/ruby/command_line/frozen_strings_spec.rb | 24 +- spec/ruby/core/array/pack/shared/basic.rb | 10 +- .../builtin_constants_spec.rb | 74 ++++++ spec/ruby/core/comparable/clamp_spec.rb | 79 +++++++ spec/ruby/core/comparable/fixtures/classes.rb | 1 + spec/ruby/core/data/fixtures/classes.rb | 6 + spec/ruby/core/data/initialize_spec.rb | 10 + spec/ruby/core/encoding/find_spec.rb | 2 +- spec/ruby/core/enumerable/to_set_spec.rb | 8 - spec/ruby/core/fiber/fixtures/scheduler.rb | 35 +++ spec/ruby/core/fiber/scheduler_spec.rb | 8 + spec/ruby/core/fiber/set_scheduler_spec.rb | 8 + spec/ruby/core/fiber/shared/scheduler.rb | 51 +++++ spec/ruby/core/file/socket_spec.rb | 32 --- spec/ruby/core/filetest/socket_spec.rb | 4 + spec/ruby/core/gc/config_spec.rb | 83 +++++++ spec/ruby/core/integer/shared/modulo.rb | 46 +++- spec/ruby/core/io/shared/new.rb | 23 ++ spec/ruby/core/kernel/Float_spec.rb | 4 + spec/ruby/core/kernel/Rational_spec.rb | 98 +++++++- spec/ruby/core/kernel/raise_spec.rb | 4 +- spec/ruby/core/kernel/sleep_spec.rb | 35 +++ spec/ruby/core/math/expm1_spec.rb | 37 +++ spec/ruby/core/math/log1p_spec.rb | 49 ++++ spec/ruby/core/module/fixtures/classes.rb | 2 +- spec/ruby/core/proc/parameters_spec.rb | 14 ++ spec/ruby/core/range/to_set_spec.rb | 55 +++++ spec/ruby/core/regexp/linear_time_spec.rb | 6 + spec/ruby/core/string/unpack/shared/basic.rb | 17 +- spec/ruby/core/string/uplus_spec.rb | 44 +++- spec/ruby/core/symbol/shared/id2name.rb | 14 ++ .../core/unboundmethod/equal_value_spec.rb | 2 +- spec/ruby/core/warning/categories_spec.rb | 12 + spec/ruby/core/warning/warn_spec.rb | 8 +- spec/ruby/default.mspec | 5 +- spec/ruby/language/block_spec.rb | 64 +++++- spec/ruby/language/class_spec.rb | 42 +++- spec/ruby/language/fixtures/module.rb | 9 - spec/ruby/language/it_parameter_spec.rb | 66 ++++++ spec/ruby/language/magic_comment_spec.rb | 17 +- spec/ruby/language/method_spec.rb | 8 +- spec/ruby/language/module_spec.rb | 32 ++- spec/ruby/language/reserved_keywords.rb | 149 +++++++++++++ .../library/cgi/escapeURIComponent_spec.rb | 59 +++-- .../library/cgi/unescapeURIComponent_spec.rb | 128 +++++++++++ .../library/socket/addrinfo/afamily_spec.rb | 16 +- .../socket/addrinfo/family_addrinfo_spec.rb | 48 ++-- .../socket/addrinfo/getnameinfo_spec.rb | 20 +- .../socket/addrinfo/initialize_spec.rb | 58 +++-- .../socket/addrinfo/inspect_sockaddr_spec.rb | 18 +- .../library/socket/addrinfo/inspect_spec.rb | 26 +-- .../socket/addrinfo/ip_address_spec.rb | 14 +- .../library/socket/addrinfo/ip_port_spec.rb | 14 +- spec/ruby/library/socket/addrinfo/ip_spec.rb | 14 +- .../library/socket/addrinfo/ip_unpack_spec.rb | 14 +- .../socket/addrinfo/ipv4_loopback_spec.rb | 14 +- .../socket/addrinfo/ipv4_multicast_spec.rb | 14 +- .../socket/addrinfo/ipv4_private_spec.rb | 16 +- .../ruby/library/socket/addrinfo/ipv4_spec.rb | 14 +- .../socket/addrinfo/ipv6_loopback_spec.rb | 16 +- .../socket/addrinfo/ipv6_multicast_spec.rb | 16 +- .../ruby/library/socket/addrinfo/ipv6_spec.rb | 14 +- .../socket/addrinfo/ipv6_to_ipv4_spec.rb | 2 +- .../socket/addrinfo/marshal_dump_spec.rb | 50 ++--- .../socket/addrinfo/marshal_load_spec.rb | 20 +- .../library/socket/addrinfo/pfamily_spec.rb | 16 +- .../library/socket/addrinfo/protocol_spec.rb | 14 +- .../socket/addrinfo/shared/to_sockaddr.rb | 16 +- .../library/socket/addrinfo/socktype_spec.rb | 14 +- .../library/socket/addrinfo/unix_path_spec.rb | 46 ++-- .../ruby/library/socket/addrinfo/unix_spec.rb | 46 ++-- .../basicsocket/connect_address_spec.rb | 80 ++++--- .../socket/basicsocket/getpeereid_spec.rb | 2 +- .../socket/basicsocket/setsockopt_spec.rb | 26 +-- spec/ruby/library/socket/shared/address.rb | 86 +++---- .../library/socket/shared/pack_sockaddr.rb | 30 ++- .../socket/socket/unix_server_loop_spec.rb | 76 +++---- .../socket/socket/unix_server_socket_spec.rb | 56 +++-- spec/ruby/library/socket/socket/unix_spec.rb | 56 +++-- .../socket/socket/unpack_sockaddr_in_spec.rb | 16 +- .../socket/socket/unpack_sockaddr_un_spec.rb | 34 ++- spec/ruby/library/socket/spec_helper.rb | 1 - .../socket/unixserver/accept_nonblock_spec.rb | 114 +++++----- .../library/socket/unixserver/accept_spec.rb | 166 +++++++------- .../library/socket/unixserver/for_fd_spec.rb | 28 ++- .../socket/unixserver/initialize_spec.rb | 36 ++- .../library/socket/unixserver/listen_spec.rb | 24 +- .../library/socket/unixserver/new_spec.rb | 14 +- .../library/socket/unixserver/open_spec.rb | 30 ++- .../socket/unixserver/sysaccept_spec.rb | 64 +++--- .../library/socket/unixsocket/addr_spec.rb | 48 ++-- .../socket/unixsocket/initialize_spec.rb | 60 ++--- .../library/socket/unixsocket/inspect_spec.rb | 20 +- .../socket/unixsocket/local_address_spec.rb | 132 ++++++----- .../library/socket/unixsocket/new_spec.rb | 14 +- .../library/socket/unixsocket/open_spec.rb | 34 ++- .../library/socket/unixsocket/pair_spec.rb | 20 +- .../unixsocket/partially_closable_spec.rb | 30 ++- .../library/socket/unixsocket/path_spec.rb | 34 ++- .../socket/unixsocket/peeraddr_spec.rb | 38 ++-- .../library/socket/unixsocket/recv_io_spec.rb | 2 +- .../socket/unixsocket/recvfrom_spec.rb | 152 +++++++++---- .../socket/unixsocket/remote_address_spec.rb | 60 +++-- .../library/socket/unixsocket/send_io_spec.rb | 2 +- .../library/socket/unixsocket/shared/pair.rb | 39 +++- .../socket/unixsocket/socketpair_spec.rb | 20 +- .../ruby/library/stringio/readpartial_spec.rb | 8 + .../thread_safety/fixtures/classes.rb | 39 ++++ spec/ruby/optional/thread_safety/hash_spec.rb | 210 ++++++++++++++++++ spec/ruby/shared/file/socket.rb | 32 ++- 111 files changed, 2752 insertions(+), 1236 deletions(-) create mode 100644 spec/ruby/core/fiber/fixtures/scheduler.rb create mode 100644 spec/ruby/core/fiber/scheduler_spec.rb create mode 100644 spec/ruby/core/fiber/set_scheduler_spec.rb create mode 100644 spec/ruby/core/fiber/shared/scheduler.rb create mode 100644 spec/ruby/core/gc/config_spec.rb create mode 100644 spec/ruby/core/math/expm1_spec.rb create mode 100644 spec/ruby/core/math/log1p_spec.rb create mode 100644 spec/ruby/core/range/to_set_spec.rb create mode 100644 spec/ruby/core/warning/categories_spec.rb create mode 100644 spec/ruby/language/it_parameter_spec.rb create mode 100644 spec/ruby/language/reserved_keywords.rb create mode 100644 spec/ruby/library/cgi/unescapeURIComponent_spec.rb create mode 100644 spec/ruby/optional/thread_safety/fixtures/classes.rb create mode 100644 spec/ruby/optional/thread_safety/hash_spec.rb diff --git a/spec/ruby/.rubocop.yml b/spec/ruby/.rubocop.yml index 68cce312808bce..0b59a11512f445 100644 --- a/spec/ruby/.rubocop.yml +++ b/spec/ruby/.rubocop.yml @@ -197,6 +197,7 @@ Style/Lambda: - 'language/lambda_spec.rb' - 'language/proc_spec.rb' - 'language/numbered_parameters_spec.rb' + - 'language/it_parameter_spec.rb' - 'core/kernel/lambda_spec.rb' Style/EmptyLambdaParameter: diff --git a/spec/ruby/command_line/frozen_strings_spec.rb b/spec/ruby/command_line/frozen_strings_spec.rb index 014153e0b4afbe..8acab5bc1d66ee 100644 --- a/spec/ruby/command_line/frozen_strings_spec.rb +++ b/spec/ruby/command_line/frozen_strings_spec.rb @@ -42,8 +42,28 @@ ruby_exe(fixture(__FILE__, "freeze_flag_one_literal.rb")).chomp.should == "false" end - it "if file has no frozen_string_literal comment produce different mutable strings each time" do - ruby_exe(fixture(__FILE__, "string_literal_raw.rb")).chomp.should == "frozen:false interned:false" + context "if file has no frozen_string_literal comment" do + it "produce different mutable strings each time" do + ruby_exe(fixture(__FILE__, "string_literal_raw.rb")).chomp.should == "frozen:false interned:false" + end + + guard -> { ruby_version_is "3.4" and !"test".frozen? } do + it "complain about modification of produced mutable strings" do + -> { eval(<<~RUBY) }.should complain(/warning: literal string will be frozen in the future \(run with --debug-frozen-string-literal for more information\)/) + "test" << "!" + RUBY + end + + it "does not complain about modification if Warning[:deprecated] is false" do + deprecated = Warning[:deprecated] + Warning[:deprecated] = false + -> { eval(<<~RUBY) }.should_not complain + "test" << "!" + RUBY + ensure + Warning[:deprecated] = deprecated + end + end end it "if file has frozen_string_literal:true comment produce same frozen strings each time" do diff --git a/spec/ruby/core/array/pack/shared/basic.rb b/spec/ruby/core/array/pack/shared/basic.rb index ebd9f75d9dc66a..a63f64d296a312 100644 --- a/spec/ruby/core/array/pack/shared/basic.rb +++ b/spec/ruby/core/array/pack/shared/basic.rb @@ -33,19 +33,15 @@ end ruby_version_is ""..."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 ':'/) + -> { [@obj, @obj].pack("a K" + pack_format) }.should complain(/unknown pack directive 'K' in 'a K#{pack_format}'/) + -> { [@obj, @obj].pack("a 0" + pack_format) }.should complain(/unknown pack directive '0' in 'a 0#{pack_format}'/) + -> { [@obj, @obj].pack("a :" + pack_format) }.should complain(/unknown pack directive ':' in 'a :#{pack_format}'/) end end ruby_version_is "3.3" do - # https://bugs.ruby-lang.org/issues/19150 - # NOTE: Added this case just to not forget about the decision in the ticket it "raise ArgumentError when a directive is unknown" do # additional directive ('a') is required for the X directive -> { [@obj, @obj].pack("a R" + pack_format) }.should raise_error(ArgumentError, /unknown pack directive 'R'/) diff --git a/spec/ruby/core/builtin_constants/builtin_constants_spec.rb b/spec/ruby/core/builtin_constants/builtin_constants_spec.rb index eaf311783a4a08..13e066cc7f1664 100644 --- a/spec/ruby/core/builtin_constants/builtin_constants_spec.rb +++ b/spec/ruby/core/builtin_constants/builtin_constants_spec.rb @@ -46,6 +46,16 @@ end end +describe "RUBY_ENGINE_VERSION" do + it "is a String" do + RUBY_ENGINE_VERSION.should be_kind_of(String) + end + + it "is frozen" do + RUBY_ENGINE_VERSION.should.frozen? + end +end + describe "RUBY_PLATFORM" do it "is a String" do RUBY_PLATFORM.should be_kind_of(String) @@ -75,3 +85,67 @@ RUBY_REVISION.should.frozen? end end + +ruby_version_is "4.0" do + context "The constant" do + describe "Ruby" do + it "is a Module" do + Ruby.should.instance_of?(Module) + end + end + + describe "Ruby::VERSION" do + it "is equal to RUBY_VERSION" do + Ruby::VERSION.should equal(RUBY_VERSION) + end + end + + describe "RUBY::PATCHLEVEL" do + it "is equal to RUBY_PATCHLEVEL" do + Ruby::PATCHLEVEL.should equal(RUBY_PATCHLEVEL) + end + end + + describe "Ruby::COPYRIGHT" do + it "is equal to RUBY_COPYRIGHT" do + Ruby::COPYRIGHT.should equal(RUBY_COPYRIGHT) + end + end + + describe "Ruby::DESCRIPTION" do + it "is equal to RUBY_DESCRIPTION" do + Ruby::DESCRIPTION.should equal(RUBY_DESCRIPTION) + end + end + + describe "Ruby::ENGINE" do + it "is equal to RUBY_ENGINE" do + Ruby::ENGINE.should equal(RUBY_ENGINE) + end + end + + describe "Ruby::ENGINE_VERSION" do + it "is equal to RUBY_ENGINE_VERSION" do + Ruby::ENGINE_VERSION.should equal(RUBY_ENGINE_VERSION) + end + end + + describe "Ruby::PLATFORM" do + it "is equal to RUBY_PLATFORM" do + Ruby::PLATFORM.should equal(RUBY_PLATFORM) + end + end + + describe "Ruby::RELEASE_DATE" do + it "is equal to RUBY_RELEASE_DATE" do + Ruby::RELEASE_DATE.should equal(RUBY_RELEASE_DATE) + end + end + + describe "Ruby::REVISION" do + it "is equal to RUBY_REVISION" do + Ruby::REVISION.should equal(RUBY_REVISION) + end + end + end +end diff --git a/spec/ruby/core/comparable/clamp_spec.rb b/spec/ruby/core/comparable/clamp_spec.rb index cc1df977e2ae09..18f616a997998d 100644 --- a/spec/ruby/core/comparable/clamp_spec.rb +++ b/spec/ruby/core/comparable/clamp_spec.rb @@ -40,6 +40,39 @@ c.clamp(one, two).should equal(two) end + context 'max is nil' do + it 'returns min if less than it' do + one = ComparableSpecs::WithOnlyCompareDefined.new(1) + c = ComparableSpecs::Weird.new(0) + c.clamp(one, nil).should equal(one) + end + + it 'always returns self if greater than min' do + one = ComparableSpecs::WithOnlyCompareDefined.new(1) + c = ComparableSpecs::Weird.new(2) + c.clamp(one, nil).should equal(c) + end + end + + context 'min is nil' do + it 'returns max if greater than it' do + one = ComparableSpecs::WithOnlyCompareDefined.new(1) + c = ComparableSpecs::Weird.new(2) + c.clamp(nil, one).should equal(one) + end + + it 'always returns self if less than max' do + one = ComparableSpecs::WithOnlyCompareDefined.new(1) + c = ComparableSpecs::Weird.new(0) + c.clamp(nil, one).should equal(c) + end + end + + it 'always returns self when min is nil and max is nil' do + c = ComparableSpecs::Weird.new(1) + c.clamp(nil, nil).should equal(c) + end + it 'returns self if within the given range parameters' do one = ComparableSpecs::WithOnlyCompareDefined.new(1) two = ComparableSpecs::WithOnlyCompareDefined.new(2) @@ -76,6 +109,26 @@ -> { c.clamp(one...two) }.should raise_error(ArgumentError) end + context 'with nil as the max argument' do + it 'returns min argument if less than it' do + one = ComparableSpecs::WithOnlyCompareDefined.new(1) + zero = ComparableSpecs::WithOnlyCompareDefined.new(0) + c = ComparableSpecs::Weird.new(0) + + c.clamp(one, nil).should equal(one) + c.clamp(zero, nil).should equal(c) + end + + it 'always returns self if greater than min argument' do + one = ComparableSpecs::WithOnlyCompareDefined.new(1) + two = ComparableSpecs::WithOnlyCompareDefined.new(2) + c = ComparableSpecs::Weird.new(2) + + c.clamp(one, nil).should equal(c) + c.clamp(two, nil).should equal(c) + end + end + context 'with endless range' do it 'returns minimum value of the range parameters if less than it' do one = ComparableSpecs::WithOnlyCompareDefined.new(1) @@ -103,6 +156,24 @@ end end + context 'with nil as the min argument' do + it 'returns max argument if greater than it' do + one = ComparableSpecs::WithOnlyCompareDefined.new(1) + c = ComparableSpecs::Weird.new(2) + + c.clamp(nil, one).should equal(one) + end + + it 'always returns self if less than max argument' do + one = ComparableSpecs::WithOnlyCompareDefined.new(1) + zero = ComparableSpecs::WithOnlyCompareDefined.new(0) + c = ComparableSpecs::Weird.new(0) + + c.clamp(nil, one).should equal(c) + c.clamp(nil, zero).should equal(c) + end + end + context 'with beginless range' do it 'returns maximum value of the range parameters if greater than it' do one = ComparableSpecs::WithOnlyCompareDefined.new(1) @@ -128,6 +199,14 @@ end end + context 'with nil as the min and the max argument' do + it 'always returns self' do + c = ComparableSpecs::Weird.new(1) + + c.clamp(nil, nil).should equal(c) + end + end + context 'with beginless-and-endless range' do it 'always returns self' do c = ComparableSpecs::Weird.new(1) diff --git a/spec/ruby/core/comparable/fixtures/classes.rb b/spec/ruby/core/comparable/fixtures/classes.rb index 4239a47d2f5738..2bdabbf0140c60 100644 --- a/spec/ruby/core/comparable/fixtures/classes.rb +++ b/spec/ruby/core/comparable/fixtures/classes.rb @@ -7,6 +7,7 @@ def initialize(value) end def <=>(other) + return nil if other.nil? self.value <=> other.value end end diff --git a/spec/ruby/core/data/fixtures/classes.rb b/spec/ruby/core/data/fixtures/classes.rb index ffd361d781d7a0..650c0b2a623fdd 100644 --- a/spec/ruby/core/data/fixtures/classes.rb +++ b/spec/ruby/core/data/fixtures/classes.rb @@ -24,5 +24,11 @@ def initialize(*rest, **kw) ScratchPad.record [:initialize, rest, kw] end end + + Area = Data.define(:width, :height, :area) do + def initialize(width:, height:) + super(width: width, height: height, area: width * height) + end + end end end diff --git a/spec/ruby/core/data/initialize_spec.rb b/spec/ruby/core/data/initialize_spec.rb index 9d272780a85b23..010c73b91b8fea 100644 --- a/spec/ruby/core/data/initialize_spec.rb +++ b/spec/ruby/core/data/initialize_spec.rb @@ -110,5 +110,15 @@ def initialize(*, **) DataSpecs::DataWithOverriddenInitialize[amount: 42, unit: "m"] ScratchPad.recorded.should == [:initialize, [], {amount: 42, unit: "m"}] end + + # See https://github.com/ruby/psych/pull/765 + it "can be deserialized by calling Data.instance_method(:initialize)" do + d1 = DataSpecs::Area.new(width: 2, height: 3) + d1.area.should == 6 + + d2 = DataSpecs::Area.allocate + Data.instance_method(:initialize).bind_call(d2, **d1.to_h) + d2.should == d1 + end end end diff --git a/spec/ruby/core/encoding/find_spec.rb b/spec/ruby/core/encoding/find_spec.rb index 8a0873070fc90b..9c34fe0e77ffee 100644 --- a/spec/ruby/core/encoding/find_spec.rb +++ b/spec/ruby/core/encoding/find_spec.rb @@ -50,7 +50,7 @@ def to_str; @encoding_name; end end it "raises an ArgumentError if the given encoding does not exist" do - -> { Encoding.find('dh2dh278d') }.should raise_error(ArgumentError) + -> { Encoding.find('dh2dh278d') }.should raise_error(ArgumentError, 'unknown encoding name - dh2dh278d') end # Not sure how to do a better test, since locale depends on weird platform-specific stuff diff --git a/spec/ruby/core/enumerable/to_set_spec.rb b/spec/ruby/core/enumerable/to_set_spec.rb index 91499aeb5b180c..c02ead11fa4638 100644 --- a/spec/ruby/core/enumerable/to_set_spec.rb +++ b/spec/ruby/core/enumerable/to_set_spec.rb @@ -27,12 +27,4 @@ set.to_a.sort.should == [1, 2, 3] end end - - it "does not need explicit `require 'set'`" do - output = ruby_exe(<<~RUBY, options: '--disable-gems', args: '2>&1') - puts [1, 2, 3].to_set.to_a.inspect - RUBY - - output.chomp.should == "[1, 2, 3]" - end end diff --git a/spec/ruby/core/fiber/fixtures/scheduler.rb b/spec/ruby/core/fiber/fixtures/scheduler.rb new file mode 100644 index 00000000000000..16bd2f6b443457 --- /dev/null +++ b/spec/ruby/core/fiber/fixtures/scheduler.rb @@ -0,0 +1,35 @@ +module FiberSpecs + + class LoggingScheduler + attr_reader :events + def initialize + @events = [] + end + + def block(*args) + @events << { event: :block, fiber: Fiber.current, args: args } + Fiber.yield + end + + def io_wait(*args) + @events << { event: :io_wait, fiber: Fiber.current, args: args } + Fiber.yield + end + + def kernel_sleep(*args) + @events << { event: :kernel_sleep, fiber: Fiber.current, args: args } + Fiber.yield + end + + def unblock(*args) + @events << { event: :unblock, fiber: Fiber.current, args: args } + Fiber.yield + end + + def fiber_interrupt(*args) + @events << { event: :fiber_interrupt, fiber: Fiber.current, args: args } + Fiber.yield + end + end + +end diff --git a/spec/ruby/core/fiber/scheduler_spec.rb b/spec/ruby/core/fiber/scheduler_spec.rb new file mode 100644 index 00000000000000..15a03c147921aa --- /dev/null +++ b/spec/ruby/core/fiber/scheduler_spec.rb @@ -0,0 +1,8 @@ +require_relative '../../spec_helper' +require_relative 'shared/scheduler' + +require "fiber" + +describe "Fiber.scheduler" do + it_behaves_like :scheduler, :scheduler +end diff --git a/spec/ruby/core/fiber/set_scheduler_spec.rb b/spec/ruby/core/fiber/set_scheduler_spec.rb new file mode 100644 index 00000000000000..82f6acbe866f19 --- /dev/null +++ b/spec/ruby/core/fiber/set_scheduler_spec.rb @@ -0,0 +1,8 @@ +require_relative '../../spec_helper' +require_relative 'shared/scheduler' + +require "fiber" + +describe "Fiber.scheduler" do + it_behaves_like :scheduler, :set_scheduler +end diff --git a/spec/ruby/core/fiber/shared/scheduler.rb b/spec/ruby/core/fiber/shared/scheduler.rb new file mode 100644 index 00000000000000..19bfb75e3e1313 --- /dev/null +++ b/spec/ruby/core/fiber/shared/scheduler.rb @@ -0,0 +1,51 @@ +describe :scheduler, shared: true do + it "validates the scheduler for required methods" do + required_methods = [:block, :unblock, :kernel_sleep, :io_wait] + required_methods.each do |missing_method| + scheduler = Object.new + required_methods.difference([missing_method]).each do |method| + scheduler.define_singleton_method(method) {} + end + -> { + suppress_warning { Fiber.set_scheduler(scheduler) } + }.should raise_error(ArgumentError, /Scheduler must implement ##{missing_method}/) + end + end + + it "can set and get the scheduler" do + required_methods = [:block, :unblock, :kernel_sleep, :io_wait] + scheduler = Object.new + required_methods.each do |method| + scheduler.define_singleton_method(method) {} + end + suppress_warning { Fiber.set_scheduler(scheduler) } + Fiber.scheduler.should == scheduler + end + + it "returns the scheduler after setting it" do + required_methods = [:block, :unblock, :kernel_sleep, :io_wait] + scheduler = Object.new + required_methods.each do |method| + scheduler.define_singleton_method(method) {} + end + result = suppress_warning { Fiber.set_scheduler(scheduler) } + result.should == scheduler + end + + it "can remove the scheduler" do + required_methods = [:block, :unblock, :kernel_sleep, :io_wait] + scheduler = Object.new + required_methods.each do |method| + scheduler.define_singleton_method(method) {} + end + suppress_warning { Fiber.set_scheduler(scheduler) } + Fiber.set_scheduler(nil) + Fiber.scheduler.should be_nil + end + + it "can assign a nil scheduler multiple times" do + Fiber.set_scheduler(nil) + Fiber.set_scheduler(nil) + Fiber.scheduler.should be_nil + end +end diff --git a/spec/ruby/core/file/socket_spec.rb b/spec/ruby/core/file/socket_spec.rb index 5d12e21f5596b6..d3f4eb013a3513 100644 --- a/spec/ruby/core/file/socket_spec.rb +++ b/spec/ruby/core/file/socket_spec.rb @@ -1,42 +1,10 @@ require_relative '../../spec_helper' require_relative '../../shared/file/socket' -require 'socket' describe "File.socket?" do it_behaves_like :file_socket, :socket?, File -end -describe "File.socket?" do it "returns false if file does not exist" do File.socket?("I_am_a_bogus_file").should == false end - - it "returns false if the file is not a socket" do - filename = tmp("i_exist") - touch(filename) - - File.socket?(filename).should == false - - rm_r filename - end -end - -platform_is_not :windows do - describe "File.socket?" do - before :each do - # We need a really short name here. - # On Linux the path length is limited to 107, see unix(7). - @name = tmp("s") - @server = UNIXServer.new @name - end - - after :each do - @server.close - rm_r @name - end - - it "returns true if the file is a socket" do - File.socket?(@name).should == true - end - end end diff --git a/spec/ruby/core/filetest/socket_spec.rb b/spec/ruby/core/filetest/socket_spec.rb index 63a6a31ecbb3fe..f274be6318c203 100644 --- a/spec/ruby/core/filetest/socket_spec.rb +++ b/spec/ruby/core/filetest/socket_spec.rb @@ -3,4 +3,8 @@ describe "FileTest.socket?" do it_behaves_like :file_socket, :socket?, FileTest + + it "returns false if file does not exist" do + FileTest.socket?("I_am_a_bogus_file").should == false + end end diff --git a/spec/ruby/core/gc/config_spec.rb b/spec/ruby/core/gc/config_spec.rb new file mode 100644 index 00000000000000..e20e8e4a16a97f --- /dev/null +++ b/spec/ruby/core/gc/config_spec.rb @@ -0,0 +1,83 @@ +require_relative '../../spec_helper' + +ruby_version_is "3.4" do + describe "GC.config" do + context "without arguments" do + it "returns a hash of current settings" do + GC.config.should be_kind_of(Hash) + end + + it "includes the name of currently loaded GC implementation as a global key" do + GC.config.should include(:implementation) + GC.config[:implementation].should be_kind_of(String) + end + end + + context "with a hash of options" do + it "allows to set GC implementation's options, returning the new config" do + config = GC.config({}) + # Try to find a boolean setting to reliably test changing it. + key, _value = config.find { |_k, v| v == true } + skip unless key + + GC.config(key => false).should == config.merge(key => false) + GC.config[key].should == false + GC.config(key => true).should == config + GC.config[key].should == true + ensure + GC.config(config.except(:implementation)) + end + + it "does not change settings that aren't present in the hash" do + previous = GC.config + GC.config({}) + GC.config.should == previous + end + + it "ignores unknown keys" do + previous = GC.config + GC.config(foo: "bar") + GC.config.should == previous + end + + it "raises an ArgumentError if options include global keys" do + -> { GC.config(implementation: "default") }.should raise_error(ArgumentError, 'Attempting to set read-only key "Implementation"') + end + end + + context "with a non-hash argument" do + it "returns current settings if argument is nil" do + GC.config(nil).should == GC.config + end + + it "raises ArgumentError for all other arguments" do + -> { GC.config([]) }.should raise_error(ArgumentError) + -> { GC.config("default") }.should raise_error(ArgumentError) + -> { GC.config(1) }.should raise_error(ArgumentError) + end + end + + guard -> { PlatformGuard.standard? && GC.config[:implementation] == "default" } do + context "with default GC implementation on MRI" do + before do + @default_config = GC.config({}) + end + + after do + GC.config(@default_config.except(:implementation)) + end + + it "includes :rgengc_allow_full_mark option, true by default" do + GC.config.should include(:rgengc_allow_full_mark) + GC.config[:rgengc_allow_full_mark].should be_true + end + + it "allows to set :rgengc_allow_full_mark" do + # This key maps truthy and falsey values to true and false. + GC.config(rgengc_allow_full_mark: nil).should == @default_config.merge(rgengc_allow_full_mark: false) + GC.config(rgengc_allow_full_mark: 1.23).should == @default_config.merge(rgengc_allow_full_mark: true) + end + end + end + end +end diff --git a/spec/ruby/core/integer/shared/modulo.rb b/spec/ruby/core/integer/shared/modulo.rb index f678a10806d93e..d91af1e924176d 100644 --- a/spec/ruby/core/integer/shared/modulo.rb +++ b/spec/ruby/core/integer/shared/modulo.rb @@ -1,6 +1,12 @@ describe :integer_modulo, shared: true do context "fixnum" do it "returns the modulus obtained from dividing self by the given argument" do + # test all possible combinations: + # - integer/double/bignum argument + # - positive/negative argument + # - positive/negative self + # - self greater/smaller than argument + 13.send(@method, 4).should == 1 4.send(@method, 13).should == 4 @@ -16,8 +22,22 @@ (200).send(@method, -256).should == -56 (1000).send(@method, -512).should == -24 + 13.send(@method, -4.0).should == -3.0 + 4.send(@method, -13.0).should == -9.0 + + -13.send(@method, -4.0).should == -1.0 + -4.send(@method, -13.0).should == -4.0 + + -13.send(@method, 4.0).should == 3.0 + -4.send(@method, 13.0).should == 9.0 + 1.send(@method, 2.0).should == 1.0 200.send(@method, bignum_value).should == 200 + + 4.send(@method, bignum_value(10)).should == 4 + 4.send(@method, -bignum_value(10)).should == -18446744073709551622 + -4.send(@method, bignum_value(10)).should == 18446744073709551622 + -4.send(@method, -bignum_value(10)).should == -4 end it "raises a ZeroDivisionError when the given argument is 0" do @@ -44,15 +64,35 @@ context "bignum" do before :each do - @bignum = bignum_value + @bignum = bignum_value(10) end it "returns the modulus obtained from dividing self by the given argument" do + # test all possible combinations: + # - integer/double/bignum argument + # - positive/negative argument + # - positive/negative self + # - self greater/smaller than argument + @bignum.send(@method, 5).should == 1 @bignum.send(@method, -5).should == -4 - @bignum.send(@method, -100).should == -84 + (-@bignum).send(@method, 5).should == 4 + (-@bignum).send(@method, -5).should == -1 + @bignum.send(@method, 2.22).should be_close(1.5603603603605034, TOLERANCE) - @bignum.send(@method, bignum_value(10)).should == 18446744073709551616 + @bignum.send(@method, -2.22).should be_close(-0.6596396396394968, TOLERANCE) + (-@bignum).send(@method, 2.22).should be_close(0.6596396396394968, TOLERANCE) + (-@bignum).send(@method, -2.22).should be_close(-1.5603603603605034, TOLERANCE) + + @bignum.send(@method, @bignum + 10).should == 18446744073709551626 + @bignum.send(@method, -(@bignum + 10)).should == -10 + (-@bignum).send(@method, @bignum + 10).should == 10 + (-@bignum).send(@method, -(@bignum + 10)).should == -18446744073709551626 + + (@bignum + 10).send(@method, @bignum).should == 10 + (@bignum + 10).send(@method, -@bignum).should == -18446744073709551616 + (-(@bignum + 10)).send(@method, @bignum).should == 18446744073709551616 + (-(@bignum + 10)).send(@method, -@bignum).should == -10 end it "raises a ZeroDivisionError when the given argument is 0" do diff --git a/spec/ruby/core/io/shared/new.rb b/spec/ruby/core/io/shared/new.rb index cba5f33ebfc1f2..e84133493c8c63 100644 --- a/spec/ruby/core/io/shared/new.rb +++ b/spec/ruby/core/io/shared/new.rb @@ -208,6 +208,26 @@ @io.internal_encoding.to_s.should == 'IBM866' end + it "does not use binary encoding when mode encoding is specified along with binmode: true option" do + @io = IO.send(@method, @fd, 'w:iso-8859-1', binmode: true) + @io.external_encoding.to_s.should == 'ISO-8859-1' + end + + it "does not use textmode argument when mode encoding is specified" do + @io = IO.send(@method, @fd, 'w:ascii-8bit', textmode: true) + @io.external_encoding.to_s.should == 'ASCII-8BIT' + end + + it "does not use binmode argument when external encoding is specified via the :external_encoding option" do + @io = IO.send(@method, @fd, 'w', binmode: true, external_encoding: 'iso-8859-1') + @io.external_encoding.to_s.should == 'ISO-8859-1' + end + + it "does not use textmode argument when external encoding is specified via the :external_encoding option" do + @io = IO.send(@method, @fd, 'w', textmode: true, external_encoding: 'ascii-8bit') + @io.external_encoding.to_s.should == 'ASCII-8BIT' + end + it "raises ArgumentError for nil options" do -> { IO.send(@method, @fd, 'w', nil) @@ -324,6 +344,9 @@ -> { @io = IO.send(@method, @fd, 'w:ISO-8859-1', external_encoding: 'ISO-8859-1') }.should raise_error(ArgumentError) + -> { + @io = IO.send(@method, @fd, 'w:ISO-8859-1', internal_encoding: 'ISO-8859-1') + }.should raise_error(ArgumentError) -> { @io = IO.send(@method, @fd, 'w:ISO-8859-1:UTF-8', internal_encoding: 'ISO-8859-1') }.should raise_error(ArgumentError) diff --git a/spec/ruby/core/kernel/Float_spec.rb b/spec/ruby/core/kernel/Float_spec.rb index 74f6f1b0bdbcce..9c436b05f73012 100644 --- a/spec/ruby/core/kernel/Float_spec.rb +++ b/spec/ruby/core/kernel/Float_spec.rb @@ -261,6 +261,10 @@ def to_f() 1.2 end @object.send(:Float, "0x_10", exception: false).should be_nil end + it "parses negative hexadecimal string as negative float" do + @object.send(:Float, "-0x7b").should == -123.0 + end + ruby_version_is "3.4" do it "accepts a fractional part" do @object.send(:Float, "0x0.8").should == 0.5 diff --git a/spec/ruby/core/kernel/Rational_spec.rb b/spec/ruby/core/kernel/Rational_spec.rb index 841c8e8c64d147..cc11a354515c98 100644 --- a/spec/ruby/core/kernel/Rational_spec.rb +++ b/spec/ruby/core/kernel/Rational_spec.rb @@ -76,12 +76,62 @@ 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) + context "[Complex]" do + it "returns a Rational from the real part if the imaginary part is 0" do + Rational(Complex(1, 0)).should == Rational(1) + end + + it "raises a RangeError if the imaginary part is not 0" do + -> { Rational(Complex(1, 2)) }.should raise_error(RangeError, "can't convert 1+2i into Rational") + end end - it "raises a RangeError if the imaginary part is not 0" do - -> { Rational(Complex(1, 2)) }.should raise_error(RangeError) + context "[Numeric, Complex]" do + it "uses the real part if the imaginary part is 0" do + Rational(1, Complex(2, 0)).should == Rational(1, 2) + end + + it "divides a numerator by the Complex denominator if the imaginary part is not 0" do + Rational(1, Complex(2, 1)).should == Complex(2/5r, -1/5r) + end + end + end + + context "when passed neither a Numeric nor a String" do + it "converts to Rational with #to_r method" do + obj = Object.new + def obj.to_r; 1/2r; end + + Rational(obj).should == 1/2r + end + + it "tries to convert to Integer with #to_int method if it does not respond to #to_r" do + obj = Object.new + def obj.to_int; 1; end + + Rational(obj).should == 1r + end + + it "raises TypeError if it neither responds to #to_r nor #to_int method" do + -> { Rational([]) }.should raise_error(TypeError, "can't convert Array into Rational") + -> { Rational({}) }.should raise_error(TypeError, "can't convert Hash into Rational") + -> { Rational(nil) }.should raise_error(TypeError, "can't convert nil into Rational") + end + + it "swallows exception raised in #to_int method" do + object = Object.new + def object.to_int() raise NoMethodError; end + + -> { Rational(object) }.should raise_error(TypeError) + -> { Rational(object, 1) }.should raise_error(TypeError) + -> { Rational(1, object) }.should raise_error(TypeError) + end + + it "raises TypeError if #to_r does not return Rational" do + obj = Object.new + def obj.to_r; []; end + + -> { Rational(obj) }.should raise_error(TypeError, "can't convert Object to Rational (Object#to_r gives Array)") end end @@ -91,11 +141,11 @@ end it "raises a TypeError if the first argument is nil" do - -> { Rational(nil) }.should raise_error(TypeError) + -> { Rational(nil) }.should raise_error(TypeError, "can't convert nil into Rational") end it "raises a TypeError if the second argument is nil" do - -> { Rational(1, nil) }.should raise_error(TypeError) + -> { Rational(1, nil) }.should raise_error(TypeError, "can't convert nil into Rational") end it "raises a TypeError if the first argument is a Symbol" do @@ -112,6 +162,18 @@ Rational(:sym, exception: false).should == nil Rational("abc", exception: false).should == nil end + + it "swallows an exception raised in #to_r" do + obj = Object.new + def obj.to_r; raise; end + Rational(obj, exception: false).should == nil + end + + it "swallows an exception raised in #to_int" do + obj = Object.new + def obj.to_int; raise; end + Rational(obj, exception: false).should == nil + end end describe "and [non-Numeric, Numeric]" do @@ -119,6 +181,18 @@ Rational(:sym, 1, exception: false).should == nil Rational("abc", 1, exception: false).should == nil end + + it "swallows an exception raised in #to_r" do + obj = Object.new + def obj.to_r; raise; end + Rational(obj, 1, exception: false).should == nil + end + + it "swallows an exception raised in #to_int" do + obj = Object.new + def obj.to_int; raise; end + Rational(obj, 1, exception: false).should == nil + end end describe "and [anything, non-Numeric]" do @@ -126,6 +200,18 @@ Rational(:sym, :sym, exception: false).should == nil Rational("abc", :sym, exception: false).should == nil end + + it "swallows an exception raised in #to_r" do + obj = Object.new + def obj.to_r; raise; end + Rational(obj, obj, exception: false).should == nil + end + + it "swallows an exception raised in #to_int" do + obj = Object.new + def obj.to_int; raise; end + Rational(obj, obj, exception: false).should == nil + end end describe "and non-Numeric String arguments" do diff --git a/spec/ruby/core/kernel/raise_spec.rb b/spec/ruby/core/kernel/raise_spec.rb index a4ab963fa35d12..fcd011d4e62e88 100644 --- a/spec/ruby/core/kernel/raise_spec.rb +++ b/spec/ruby/core/kernel/raise_spec.rb @@ -51,11 +51,11 @@ -> { raise(cause: nil) }.should raise_error(ArgumentError, "only cause is given with no arguments") end - it "raises an ArgumentError when given cause is not an instance of Exception" do + it "raises a TypeError when given cause is not an instance of Exception" do -> { raise "message", cause: Object.new }.should raise_error(TypeError, "exception object expected") end - it "doesn't raise an ArgumentError when given cause is nil" do + it "doesn't raise a TypeError when given cause is nil" do -> { raise "message", cause: nil }.should raise_error(RuntimeError, "message") end diff --git a/spec/ruby/core/kernel/sleep_spec.rb b/spec/ruby/core/kernel/sleep_spec.rb index 4401e542563a9d..e9c600aac41107 100644 --- a/spec/ruby/core/kernel/sleep_spec.rb +++ b/spec/ruby/core/kernel/sleep_spec.rb @@ -1,4 +1,5 @@ require_relative '../../spec_helper' +require_relative '../fiber/fixtures/scheduler' describe "Kernel#sleep" do it "is a private method" do @@ -84,6 +85,40 @@ def o.divmod(*); [0, 0.001]; end t.value.should == 5 end end + + context "Kernel.sleep with Fiber scheduler" do + before :each do + Fiber.set_scheduler(FiberSpecs::LoggingScheduler.new) + end + + after :each do + Fiber.set_scheduler(nil) + end + + it "calls the scheduler without arguments when no duration is given" do + sleeper = Fiber.new(blocking: false) do + sleep + end + sleeper.resume + Fiber.scheduler.events.should == [{ event: :kernel_sleep, fiber: sleeper, args: [] }] + end + + it "calls the scheduler with the given duration" do + sleeper = Fiber.new(blocking: false) do + sleep(0.01) + end + sleeper.resume + Fiber.scheduler.events.should == [{ event: :kernel_sleep, fiber: sleeper, args: [0.01] }] + end + + it "does not call the scheduler if the fiber is blocking" do + sleeper = Fiber.new(blocking: true) do + sleep(0.01) + end + sleeper.resume + Fiber.scheduler.events.should == [] + end + end end describe "Kernel.sleep" do diff --git a/spec/ruby/core/math/expm1_spec.rb b/spec/ruby/core/math/expm1_spec.rb new file mode 100644 index 00000000000000..5725319abbb458 --- /dev/null +++ b/spec/ruby/core/math/expm1_spec.rb @@ -0,0 +1,37 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +ruby_version_is "4.0" do + describe "Math.expm1" do + it "calculates Math.exp(arg) - 1" do + Math.expm1(3).should == Math.exp(3) - 1 + end + + it "preserves precision that can be lost otherwise" do + Math.expm1(1.0e-16).should be_close(1.0e-16, TOLERANCE) + Math.expm1(1.0e-16).should != 0.0 + end + + it "raises a TypeError if the argument cannot be coerced with Float()" do + -> { Math.expm1("test") }.should raise_error(TypeError, "can't convert String into Float") + end + + it "returns NaN given NaN" do + Math.expm1(nan_value).nan?.should be_true + end + + it "raises a TypeError if the argument is nil" do + -> { Math.expm1(nil) }.should raise_error(TypeError, "can't convert nil into Float") + end + + it "accepts any argument that can be coerced with Float()" do + Math.expm1(MathSpecs::Float.new).should be_close(Math::E - 1, TOLERANCE) + end + end + + describe "Math#expm1" do + it "is accessible as a private instance method" do + IncludesMath.new.send(:expm1, 23.1415).should be_close(11226018483.0012, TOLERANCE) + end + end +end diff --git a/spec/ruby/core/math/log1p_spec.rb b/spec/ruby/core/math/log1p_spec.rb new file mode 100644 index 00000000000000..216358a3c47802 --- /dev/null +++ b/spec/ruby/core/math/log1p_spec.rb @@ -0,0 +1,49 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +ruby_version_is "4.0" do + describe "Math.log1p" do + it "calculates Math.log(1 + arg)" do + Math.log1p(3).should == Math.log(1 + 3) + end + + it "preserves precision that can be lost otherwise" do + Math.log1p(1e-16).should be_close(1.0e-16, TOLERANCE) + Math.log1p(1e-16).should != 0.0 + end + + it "raises an Math::DomainError if the argument is less than 1" do + -> { Math.log1p(-1-1e-15) }.should raise_error(Math::DomainError, "Numerical argument is out of domain - log1p") + end + + it "raises a TypeError if the argument cannot be coerced with Float()" do + -> { Math.log1p("test") }.should raise_error(TypeError, "can't convert String into Float") + end + + it "raises a TypeError for numerical values passed as string" do + -> { Math.log1p("10") }.should raise_error(TypeError, "can't convert String into Float") + end + + it "does not accept a second argument for the base" do + -> { Math.log1p(9, 3) }.should raise_error(ArgumentError, "wrong number of arguments (given 2, expected 1)") + end + + it "returns NaN given NaN" do + Math.log1p(nan_value).nan?.should be_true + end + + it "raises a TypeError if the argument is nil" do + -> { Math.log1p(nil) }.should raise_error(TypeError, "can't convert nil into Float") + end + + it "accepts any argument that can be coerced with Float()" do + Math.log1p(MathSpecs::Float.new).should be_close(0.6931471805599453, TOLERANCE) + end + end + + describe "Math#log1p" do + it "is accessible as a private instance method" do + IncludesMath.new.send(:log1p, 4.21).should be_close(1.65057985576528, TOLERANCE) + end + end +end diff --git a/spec/ruby/core/module/fixtures/classes.rb b/spec/ruby/core/module/fixtures/classes.rb index a434e7b0b8fc2a..964f64c593b8da 100644 --- a/spec/ruby/core/module/fixtures/classes.rb +++ b/spec/ruby/core/module/fixtures/classes.rb @@ -1,6 +1,6 @@ module ModuleSpecs def self.without_test_modules(modules) - ignore = %w[MSpecRSpecAdapter PP::ObjectMixin ModuleSpecs::IncludedInObject MainSpecs::Module ConstantSpecs::ModuleA] + ignore = %w[MSpecRSpecAdapter PP::ObjectMixin MainSpecs::Module ConstantSpecs::ModuleA] modules.reject { |k| ignore.include?(k.name) } end diff --git a/spec/ruby/core/proc/parameters_spec.rb b/spec/ruby/core/proc/parameters_spec.rb index e9bc9a1c5798af..cf8a8f5b12b942 100644 --- a/spec/ruby/core/proc/parameters_spec.rb +++ b/spec/ruby/core/proc/parameters_spec.rb @@ -158,4 +158,18 @@ it "returns :nokey for **nil parameter" do proc { |**nil| }.parameters.should == [[:nokey]] end + + ruby_version_is "3.4"..."4.0" do + it "handles the usage of `it` as a parameter" do + eval("proc { it }").parameters.should == [[:opt, nil]] + eval("lambda { it }").parameters.should == [[:req]] + end + end + + ruby_version_is "4.0" do + it "handles the usage of `it` as a parameter" do + eval("proc { it }").parameters.should == [[:opt]] + eval("lambda { it }").parameters.should == [[:req]] + end + end end diff --git a/spec/ruby/core/range/to_set_spec.rb b/spec/ruby/core/range/to_set_spec.rb new file mode 100644 index 00000000000000..589c0e9aedec26 --- /dev/null +++ b/spec/ruby/core/range/to_set_spec.rb @@ -0,0 +1,55 @@ +require_relative '../../spec_helper' +require_relative '../enumerable/fixtures/classes' + +describe "Enumerable#to_set" do + it "returns a new Set created from self" do + (1..4).to_set.should == Set[1, 2, 3, 4] + (1...4).to_set.should == Set[1, 2, 3] + end + + it "passes down passed blocks" do + (1..3).to_set { |x| x * x }.should == Set[1, 4, 9] + end + + ruby_version_is "4.0" do + it "raises a RangeError if the range is infinite" do + -> { (1..).to_set }.should raise_error(RangeError, "cannot convert endless range to a set") + -> { (1...).to_set }.should raise_error(RangeError, "cannot convert endless range to a set") + end + end + + ruby_version_is ""..."4.0" do + it "instantiates an object of provided as the first argument set class" do + set = (1..3).to_set(EnumerableSpecs::SetSubclass) + set.should be_kind_of(EnumerableSpecs::SetSubclass) + set.to_a.sort.should == [1, 2, 3] + end + end + + ruby_version_is "4.0"..."4.1" do + it "instantiates an object of provided as the first argument set class and warns" do + set = nil + proc { + set = (1..3).to_set(EnumerableSpecs::SetSubclass) + }.should complain(/Enumerable#to_set/) + set.should be_kind_of(EnumerableSpecs::SetSubclass) + set.to_a.sort.should == [1, 2, 3] + end + end + + ruby_version_is "4.1" do + it "does not accept any positional argument" do + -> { + (1..3).to_set(EnumerableSpecs::SetSubclass) + }.should raise_error(ArgumentError, 'wrong number of arguments (given 1, expected 0)') + end + end + + it "does not need explicit `require 'set'`" do + output = ruby_exe(<<~RUBY, options: '--disable-gems', args: '2>&1') + puts (1..3).to_set.to_a.inspect + RUBY + + output.chomp.should == "[1, 2, 3]" + end +end diff --git a/spec/ruby/core/regexp/linear_time_spec.rb b/spec/ruby/core/regexp/linear_time_spec.rb index c3b3500549b2e6..cf9e73c37c2b64 100644 --- a/spec/ruby/core/regexp/linear_time_spec.rb +++ b/spec/ruby/core/regexp/linear_time_spec.rb @@ -24,4 +24,10 @@ Regexp.linear_time?(/a/, Regexp::IGNORECASE) }.should complain(/warning: flags ignored/) end + + ruby_version_is "3.3" do + it "returns true for positive lookarounds" do + Regexp.linear_time?(/(?:(?=a*)a)*/).should == true + end + end end diff --git a/spec/ruby/core/string/unpack/shared/basic.rb b/spec/ruby/core/string/unpack/shared/basic.rb index b37a447683a95c..734630bda0a620 100644 --- a/spec/ruby/core/string/unpack/shared/basic.rb +++ b/spec/ruby/core/string/unpack/shared/basic.rb @@ -9,12 +9,19 @@ "abc".unpack(d).should be_an_instance_of(Array) end + ruby_version_is ""..."3.3" do + it "warns about using an unknown directive" do + -> { "abcdefgh".unpack("a R" + unpack_format) }.should complain(/unknown unpack directive 'R' in 'a R#{unpack_format}'/) + -> { "abcdefgh".unpack("a 0" + unpack_format) }.should complain(/unknown unpack directive '0' in 'a 0#{unpack_format}'/) + -> { "abcdefgh".unpack("a :" + unpack_format) }.should complain(/unknown unpack directive ':' in 'a :#{unpack_format}'/) + end + end + ruby_version_is "3.3" do - # https://bugs.ruby-lang.org/issues/19150 - it 'raise ArgumentError when a directive is unknown' do - -> { "abcdefgh".unpack("a R" + unpack_format) }.should raise_error(ArgumentError, /unknown unpack directive 'R'/) - -> { "abcdefgh".unpack("a 0" + unpack_format) }.should raise_error(ArgumentError, /unknown unpack directive '0'/) - -> { "abcdefgh".unpack("a :" + unpack_format) }.should raise_error(ArgumentError, /unknown unpack directive ':'/) + it "raises ArgumentError when a directive is unknown" do + -> { "abcdefgh".unpack("a K" + unpack_format) }.should raise_error(ArgumentError, "unknown unpack directive 'K' in 'a K#{unpack_format}'") + -> { "abcdefgh".unpack("a 0" + unpack_format) }.should raise_error(ArgumentError, "unknown unpack directive '0' in 'a 0#{unpack_format}'") + -> { "abcdefgh".unpack("a :" + unpack_format) }.should raise_error(ArgumentError, "unknown unpack directive ':' in 'a :#{unpack_format}'") end end end diff --git a/spec/ruby/core/string/uplus_spec.rb b/spec/ruby/core/string/uplus_spec.rb index c0b0c49edeef22..20767bcc015e74 100644 --- a/spec/ruby/core/string/uplus_spec.rb +++ b/spec/ruby/core/string/uplus_spec.rb @@ -13,14 +13,48 @@ output.should == 'foobar' end - it 'returns self if the String is not frozen' do - input = 'foo' + it 'returns a mutable String itself' do + input = String.new("foo") output = +input - output.equal?(input).should == true + output.should.equal?(input) + + input << "bar" + output.should == "foobar" + end + + context 'if file has "frozen_string_literal: true" magic comment' do + it 'returns mutable copy of a literal' do + ruby_exe(fixture(__FILE__, "freeze_magic_comment.rb")).should == 'mutable' + end end - it 'returns mutable copy despite freeze-magic-comment in file' do - ruby_exe(fixture(__FILE__, "freeze_magic_comment.rb")).should == 'mutable' + context 'if file has "frozen_string_literal: false" magic comment' do + it 'returns literal string itself' do + input = 'foo' + output = +input + + output.equal?(input).should == true + end + end + + context 'if file has no frozen_string_literal magic comment' do + ruby_version_is ''...'3.4' do + it 'returns literal string itself' do + eval(<<~RUBY).should == true + s = "foo" + s.equal?(+s) + RUBY + end + end + + ruby_version_is '3.4' do + it 'returns mutable copy of a literal' do + eval(<<~RUBY).should == false + s = "foo" + s.equal?(+s) + RUBY + end + end end end diff --git a/spec/ruby/core/symbol/shared/id2name.rb b/spec/ruby/core/symbol/shared/id2name.rb index d012b7634e5510..00a9c7d7dc69a6 100644 --- a/spec/ruby/core/symbol/shared/id2name.rb +++ b/spec/ruby/core/symbol/shared/id2name.rb @@ -13,4 +13,18 @@ symbol.send(@method).encoding.should == Encoding::US_ASCII end + + ruby_version_is "3.4" do + it "warns about mutating returned string" do + -> { :bad!.send(@method).upcase! }.should complain(/warning: string returned by :bad!.to_s will be frozen in the future/) + end + + it "does not warn about mutation when Warning[:deprecated] is false" do + deprecated = Warning[:deprecated] + Warning[:deprecated] = false + -> { :bad!.send(@method).upcase! }.should_not complain + ensure + Warning[:deprecated] = deprecated + end + end end diff --git a/spec/ruby/core/unboundmethod/equal_value_spec.rb b/spec/ruby/core/unboundmethod/equal_value_spec.rb index 4d4fc66504c7a2..b2d78c50afb359 100644 --- a/spec/ruby/core/unboundmethod/equal_value_spec.rb +++ b/spec/ruby/core/unboundmethod/equal_value_spec.rb @@ -81,7 +81,7 @@ (@child1 == @parent).should == true end - it "returns false if same method but extracted from two different subclasses" do + it "returns true if same method but extracted from two different subclasses" do (@child2 == @child1).should == true (@child1 == @child2).should == true end diff --git a/spec/ruby/core/warning/categories_spec.rb b/spec/ruby/core/warning/categories_spec.rb new file mode 100644 index 00000000000000..1e310ef38badcc --- /dev/null +++ b/spec/ruby/core/warning/categories_spec.rb @@ -0,0 +1,12 @@ +require_relative '../../spec_helper' + +ruby_version_is "3.4" do + describe "Warning.categories" do + # There might be more, but these are standard across Ruby implementations + it "returns the list of possible warning categories" do + Warning.categories.should.include? :deprecated + Warning.categories.should.include? :experimental + Warning.categories.should.include? :performance + end + end +end diff --git a/spec/ruby/core/warning/warn_spec.rb b/spec/ruby/core/warning/warn_spec.rb index 12677349874e5b..2e4a822e026d72 100644 --- a/spec/ruby/core/warning/warn_spec.rb +++ b/spec/ruby/core/warning/warn_spec.rb @@ -99,14 +99,14 @@ def Warning.warn(msg) ruby_version_is "3.4" do it "warns when category is :strict_unused_block but Warning[:strict_unused_block] is false" do - warn_experimental = Warning[:strict_unused_block] + warn_strict_unused_block = Warning[:strict_unused_block] Warning[:strict_unused_block] = true begin -> { Warning.warn("foo", category: :strict_unused_block) }.should complain("foo") ensure - Warning[:strict_unused_block] = warn_experimental + Warning[:strict_unused_block] = warn_strict_unused_block end end end @@ -137,14 +137,14 @@ def Warning.warn(msg) ruby_version_is "3.4" do it "doesn't print message when category is :strict_unused_block but Warning[:strict_unused_block] is false" do - warn_experimental = Warning[:strict_unused_block] + warn_strict_unused_block = Warning[:strict_unused_block] Warning[:strict_unused_block] = false begin -> { Warning.warn("foo", category: :strict_unused_block) }.should_not complain ensure - Warning[:strict_unused_block] = warn_experimental + Warning[:strict_unused_block] = warn_strict_unused_block end end end diff --git a/spec/ruby/default.mspec b/spec/ruby/default.mspec index 1e8f8893aa1f9c..c8b1215f561d9c 100644 --- a/spec/ruby/default.mspec +++ b/spec/ruby/default.mspec @@ -20,8 +20,11 @@ class MSpecScript # C extension API specs set :capi, [ 'optional/capi' ] + # Thread safety specs + set :thread_safety, [ 'optional/thread_safety' ] + # A list of _all_ optional specs - set :optional, get(:capi) + set :optional, get(:capi) + get(:thread_safety) # An ordered list of the directories containing specs to run set :files, get(:command_line) + get(:language) + get(:core) + get(:library) + get(:security) + get(:optional) diff --git a/spec/ruby/language/block_spec.rb b/spec/ruby/language/block_spec.rb index e1e4a363c82b74..cc003b8946270e 100644 --- a/spec/ruby/language/block_spec.rb +++ b/spec/ruby/language/block_spec.rb @@ -1049,6 +1049,12 @@ def all_kwrest(arg1, arg2, *rest, post1, post2, kw1: 1, kw2: 2, okw1:, okw2:, ** }.should complain(/warning: `it` calls without arguments will refer to the first block param in Ruby 3.4; use it\(\) or self.it/) end + it "emits a deprecation warning if numbered parameters are used" do + -> { + eval "proc { it; _1 }" + }.should complain(/warning: `it` calls without arguments will refer to the first block param in Ruby 3.4; use it\(\) or self.it/) + end + it "does not emit a deprecation warning when a block has parameters" do -> { eval "proc { |a, b| it }" }.should_not complain -> { eval "proc { |*rest| it }" }.should_not complain @@ -1058,21 +1064,75 @@ def all_kwrest(arg1, arg2, *rest, post1, post2, kw1: 1, kw2: 2, okw1:, okw2:, ** -> { eval "proc { |**| it }" }.should_not complain -> { eval "proc { |&block| it }" }.should_not complain -> { eval "proc { |&| it }" }.should_not complain + -> { eval "proc { || it }" }.should_not complain end it "does not emit a deprecation warning when `it` calls with arguments" do -> { eval "proc { it(42) }" }.should_not complain + -> { eval "proc { it 42 }" }.should_not complain + end + + it "does not emit a deprecation warning when `it` calls with a block" do + -> { eval "proc { it {} }" }.should_not complain + end + + it "does not emit a deprecation warning when a local variable inside the block named `it` exists" do + -> { eval "proc { it = 42; it }" }.should_not complain end it "does not emit a deprecation warning when `it` calls with explicit empty arguments list" do -> { eval "proc { it() }" }.should_not complain end + + it "calls the method `it` if defined" do + o = Object.new + def o.it + 21 + end + suppress_warning do + o.instance_eval("proc { it * 2 }").call(1).should == 42 + end + end + end + + ruby_version_is "3.4" do + it "does not emit a deprecation warning" do + -> { + eval "proc { it }" + }.should_not complain + end + + it "acts as the first argument if no local variables exist" do + eval("proc { it * 2 }").call(5).should == 10 + end + + it "can be reassigned to act as a local variable" do + eval("proc { tmp = it; it = tmp * 2; it }").call(21).should == 42 + end + + it "can be used in nested calls" do + eval("proc { it.map { it * 2 } }").call([1, 2, 3]).should == [2, 4, 6] + end + + it "cannot be mixed with numbered parameters" do + -> { + eval "proc { it + _1 }" + }.should raise_error(SyntaxError, /numbered parameters are not allowed when 'it' is already used|'it' is already used in/) + + -> { + eval "proc { _1 + it }" + }.should raise_error(SyntaxError, /numbered parameter is already used in|'it' is not allowed when a numbered parameter is already used/) + end end end -describe "if `it` is defined outside of a block" do - it "treats `it` as a captured variable" do +describe "if `it` is defined as a variable" do + it "treats `it` as a captured variable if defined outside of a block" do it = 5 proc { it }.call(0).should == 5 end + + it "treats `it` as a local variable if defined inside of a block" do + proc { it = 5; it }.call(0).should == 5 + end end diff --git a/spec/ruby/language/class_spec.rb b/spec/ruby/language/class_spec.rb index 0b770d69b58ea7..6fb785fd568d6a 100644 --- a/spec/ruby/language/class_spec.rb +++ b/spec/ruby/language/class_spec.rb @@ -46,7 +46,14 @@ class ClassSpecsKeywordWithSemicolon; end -> { class ClassSpecsNumber end - }.should raise_error(TypeError) + }.should raise_error(TypeError, /\AClassSpecsNumber is not a class/) + end + + it "raises TypeError if constant given as class name exists and is a Module but not a Class" do + -> { + class ClassSpecs + end + }.should raise_error(TypeError, /\AClassSpecs is not a class/) end # test case known to be detecting bugs (JRuby, MRI) @@ -346,6 +353,39 @@ def self.m ClassSpecs::M.m.should == 1 ClassSpecs::L.singleton_class.send(:remove_method, :m) end + + it "does not reopen a class included in Object" do + ruby_exe(<<~RUBY).should == "false" + module IncludedInObject + class IncludedClass + end + end + class Object + include IncludedInObject + end + class IncludedClass + end + print IncludedInObject::IncludedClass == Object::IncludedClass + RUBY + end + + it "does not reopen a class included in non-Object modules" do + ruby_exe(<<~RUBY).should == "false/false" + module Included + module IncludedClass; end + end + module M + include Included + module IncludedClass; end + end + class C + include Included + module IncludedClass; end + end + print Included::IncludedClass == M::IncludedClass, "/", + Included::IncludedClass == C::IncludedClass + RUBY + end end describe "class provides hooks" do diff --git a/spec/ruby/language/fixtures/module.rb b/spec/ruby/language/fixtures/module.rb index 33d323846e2d8d..75eee7779172a6 100644 --- a/spec/ruby/language/fixtures/module.rb +++ b/spec/ruby/language/fixtures/module.rb @@ -12,13 +12,4 @@ class Klass module Anonymous end - - module IncludedInObject - module IncludedModuleSpecs - end - end -end - -class Object - include ModuleSpecs::IncludedInObject end diff --git a/spec/ruby/language/it_parameter_spec.rb b/spec/ruby/language/it_parameter_spec.rb new file mode 100644 index 00000000000000..72023180d91d54 --- /dev/null +++ b/spec/ruby/language/it_parameter_spec.rb @@ -0,0 +1,66 @@ +require_relative '../spec_helper' + +ruby_version_is "3.4" do + describe "The `it` parameter" do + it "provides it in a block" do + -> { it }.call("a").should == "a" + proc { it }.call("a").should == "a" + lambda { it }.call("a").should == "a" + ["a"].map { it }.should == ["a"] + end + + it "assigns nil to not passed parameters" do + proc { it }.call().should == nil + end + + it "can be used in both outer and nested blocks at the same time" do + -> { it + -> { it * it }.call(2) }.call(3).should == 7 + end + + it "is a regular local variable if there is already a 'it' local variable" do + it = 0 + proc { it }.call("a").should == 0 + end + + it "raises SyntaxError when block parameters are specified explicitly" do + -> { eval("-> () { it }") }.should raise_error(SyntaxError, /ordinary parameter is defined/) + -> { eval("-> (x) { it }") }.should raise_error(SyntaxError, /ordinary parameter is defined/) + + -> { eval("proc { || it }") }.should raise_error(SyntaxError, /ordinary parameter is defined/) + -> { eval("proc { |x| it }") }.should raise_error(SyntaxError, /ordinary parameter is defined/) + + -> { eval("lambda { || it }") }.should raise_error(SyntaxError, /ordinary parameter is defined/) + -> { eval("lambda { |x| it }") }.should raise_error(SyntaxError, /ordinary parameter is defined/) + + -> { eval("['a'].map { || it }") }.should raise_error(SyntaxError, /ordinary parameter is defined/) + -> { eval("['a'].map { |x| it }") }.should raise_error(SyntaxError, /ordinary parameter is defined/) + end + + it "affects block arity" do + -> {}.arity.should == 0 + -> { it }.arity.should == 1 + end + + it "affects block parameters" do + -> { it }.parameters.should == [[:req]] + + ruby_version_is ""..."4.0" do + proc { it }.parameters.should == [[:opt, nil]] + end + ruby_version_is "4.0" do + proc { it }.parameters.should == [[:opt]] + end + end + + it "does not affect binding local variables" do + -> { it; binding.local_variables }.call("a").should == [] + end + + it "does not work in methods" do + obj = Object.new + def obj.foo; it; end + + -> { obj.foo("a") }.should raise_error(ArgumentError, /wrong number of arguments/) + end + end +end diff --git a/spec/ruby/language/magic_comment_spec.rb b/spec/ruby/language/magic_comment_spec.rb index f2bf3a08e53ab2..90bb83e279be8a 100644 --- a/spec/ruby/language/magic_comment_spec.rb +++ b/spec/ruby/language/magic_comment_spec.rb @@ -45,10 +45,19 @@ describe "Magic comments" do describe "in stdin" do - it_behaves_like :magic_comments, :locale, -> file { - print_at_exit = fixture(__FILE__, "print_magic_comment_result_at_exit.rb") - ruby_exe(nil, args: "< #{fixture(__FILE__, file)}", options: "-r#{print_at_exit}") - } + ruby_version_is ""..."4.0" do + it_behaves_like :magic_comments, :locale, -> file { + print_at_exit = fixture(__FILE__, "print_magic_comment_result_at_exit.rb") + ruby_exe(nil, args: "< #{fixture(__FILE__, file)}", options: "-r#{print_at_exit}") + } + end + + ruby_version_is "4.0" do + it_behaves_like :magic_comments, :UTF8, -> file { + print_at_exit = fixture(__FILE__, "print_magic_comment_result_at_exit.rb") + ruby_exe(nil, args: "< #{fixture(__FILE__, file)}", options: "-r#{print_at_exit}") + } + end end platform_is_not :windows do diff --git a/spec/ruby/language/method_spec.rb b/spec/ruby/language/method_spec.rb index 39b245fe2a9de2..8f72bd45ed8cbe 100644 --- a/spec/ruby/language/method_spec.rb +++ b/spec/ruby/language/method_spec.rb @@ -1621,12 +1621,12 @@ def m_that_does_not_use_block # ensure that warning is emitted -> { m_that_does_not_use_block { } }.should complain(verbose: true) - warn_experimental = Warning[:strict_unused_block] + warn_strict_unused_block = Warning[:strict_unused_block] Warning[:strict_unused_block] = false begin -> { m_that_does_not_use_block { } }.should_not complain(verbose: true) ensure - Warning[:strict_unused_block] = warn_experimental + Warning[:strict_unused_block] = warn_strict_unused_block end end @@ -1635,14 +1635,14 @@ def m_that_does_not_use_block 42 end - warn_experimental = Warning[:strict_unused_block] + warn_strict_unused_block = Warning[:strict_unused_block] Warning[:strict_unused_block] = true begin -> { m_that_does_not_use_block { } }.should complain(/the block passed to 'm_that_does_not_use_block' defined at .+ may be ignored/) ensure - Warning[:strict_unused_block] = warn_experimental + Warning[:strict_unused_block] = warn_strict_unused_block end end end diff --git a/spec/ruby/language/module_spec.rb b/spec/ruby/language/module_spec.rb index 4db00bd7fb9e66..fba4aa8c6e68b7 100644 --- a/spec/ruby/language/module_spec.rb +++ b/spec/ruby/language/module_spec.rb @@ -31,10 +31,34 @@ module ModuleSpecs; Reopened = true; end end it "does not reopen a module included in Object" do - module IncludedModuleSpecs; Reopened = true; end - ModuleSpecs::IncludedInObject::IncludedModuleSpecs.should_not == Object::IncludedModuleSpecs - ensure - IncludedModuleSpecs.send(:remove_const, :Reopened) + ruby_exe(<<~RUBY).should == "false" + module IncludedInObject + module IncludedModule; end + end + class Object + include IncludedInObject + end + module IncludedModule; end + print IncludedInObject::IncludedModule == Object::IncludedModule + RUBY + end + + it "does not reopen a module included in non-Object modules" do + ruby_exe(<<~RUBY).should == "false/false" + module Included + module IncludedModule; end + end + module M + include Included + module IncludedModule; end + end + class C + include Included + module IncludedModule; end + end + print Included::IncludedModule == M::IncludedModule, "/", + Included::IncludedModule == C::IncludedModule + RUBY end it "raises a TypeError if the constant is a Class" do diff --git a/spec/ruby/language/reserved_keywords.rb b/spec/ruby/language/reserved_keywords.rb new file mode 100644 index 00000000000000..6c40e34cccc92e --- /dev/null +++ b/spec/ruby/language/reserved_keywords.rb @@ -0,0 +1,149 @@ +require_relative '../spec_helper' + +describe "Ruby's reserved keywords" do + # Copied from https://github.com/ruby/ruby/blob/master/defs/keywords + keywords = %w[ + alias + and + begin + BEGIN + break + case + class + def + defined? + do + else + elsif + end + END + ensure + false + for + if + in + module + next + nil + not + or + redo + rescue + retry + return + self + super + then + true + undef + unless + until + when + while + yield + __ENCODING__ + __FILE__ + __LINE__ + ] + + keywords.each do |name| + describe "keyword '#{name}'" do + it "can't be used as local variable name" do + -> { eval(<<~RUBY) }.should raise_error(SyntaxError) + #{name} = :local_variable + RUBY + end + + if name == "defined?" + it "can't be used as an instance variable name" do + -> { eval(<<~RUBY) }.should raise_error(SyntaxError) + @#{name} = :instance_variable + RUBY + end + + it "can't be used as a class variable name" do + -> { eval(<<~RUBY) }.should raise_error(SyntaxError) + class C + @@#{name} = :class_variable + end + RUBY + end + + it "can't be used as a global variable name" do + -> { eval(<<~RUBY) }.should raise_error(SyntaxError) + $#{name} = :global_variable + RUBY + end + else + it "can be used as an instance variable name" do + result = eval <<~RUBY + @#{name} = :instance_variable + @#{name} + RUBY + + result.should == :instance_variable + end + + it "can be used as a class variable name" do + result = eval <<~RUBY + class C + @@#{name} = :class_variable + @@#{name} + end + RUBY + + result.should == :class_variable + end + + it "can be used as a global variable name" do + result = eval <<~RUBY + $#{name} = :global_variable + $#{name} + RUBY + + result.should == :global_variable + end + end + + it "can't be used as a positional parameter name" do + -> { eval(<<~RUBY) }.should raise_error(SyntaxError) + def x(#{name}); end + RUBY + end + + invalid_kw_param_names = ["BEGIN","END","defined?"] + + if invalid_kw_param_names.include?(name) + it "can't be used a keyword parameter name" do + -> { eval(<<~RUBY) }.should raise_error(SyntaxError) + def m(#{name}:); end + RUBY + end + else + it "can be used a keyword parameter name" do + result = instance_eval <<~RUBY + def m(#{name}:) + binding.local_variable_get(:#{name}) + end + + m(#{name}: :argument) + RUBY + + result.should == :argument + end + end + + it "can be used as a method name" do + result = instance_eval <<~RUBY + def #{name} + :method_return_value + end + + send(:#{name}) + RUBY + + result.should == :method_return_value + end + end + end +end diff --git a/spec/ruby/library/cgi/escapeURIComponent_spec.rb b/spec/ruby/library/cgi/escapeURIComponent_spec.rb index 02921ab8bf43a8..1cea2b786a626b 100644 --- a/spec/ruby/library/cgi/escapeURIComponent_spec.rb +++ b/spec/ruby/library/cgi/escapeURIComponent_spec.rb @@ -6,48 +6,67 @@ end 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' + it "percent-encodes characters reserved according to RFC 3986" do + # https://www.rfc-editor.org/rfc/rfc3986#section-2.2 + string = ":/?#[]@!$&'()*+,;=" + CGI.escapeURIComponent(string).should == "%3A%2F%3F%23%5B%5D%40%21%24%26%27%28%29%2A%2B%2C%3B%3D" end - it "does not escape with unreserved characters" do + it "does not percent-encode unreserved characters according to RFC 3986" 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" + it "encodes % character as %25" do + CGI.escapeURIComponent("%").should == "%25" end - it "processes String bytes one by one, not characters" do - CGI.escapeURIComponent("β").should == "%CE%B2" # "β" bytes representation is CE B2 + # Compare to .escape which uses "+". + it "percent-encodes single whitespace" do + CGI.escapeURIComponent(" ").should == "%20" end - it "raises a TypeError with nil" do - -> { - CGI.escapeURIComponent(nil) - }.should raise_error(TypeError, 'no implicit conversion of nil into String') + it "percent-encodes all non-reserved and non-unreserved ASCII characters" do + special_set = ":/?#[]@!$&'()*+,;=ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-._~" + all_other = (0x00..0x7F).filter_map { |i| i.chr unless special_set.include?(i.chr) }.join + encoded = CGI.escapeURIComponent(all_other) + encoded.should.match?(/\A(?:%[0-9A-F]{2}){#{all_other.length}}\z/) end - it "encodes empty string" do - CGI.escapeURIComponent("").should == "" + it "percent-encodes non-ASCII bytes" do + bytes = (0x80..0xFF).map(&:chr).join + encoded = CGI.escapeURIComponent(bytes) + encoded.should.match?(/\A(?:%[0-9A-F]{2}){#{bytes.length}}\z/) end - it "encodes single whitespace" do - CGI.escapeURIComponent(" ").should == "%20" + it "processes multi-byte characters as separate bytes, percent-encoding each one" do + CGI.escapeURIComponent("β").should == "%CE%B2" # "β" bytes representation is CE B2 end - it "encodes double whitespace" do - CGI.escapeURIComponent(" ").should == "%20%20" + it "produces a copy of an empty string" do + string = "".encode(Encoding::BINARY) + encoded = CGI.escapeURIComponent(string) + encoded.should == "" + encoded.encoding.should == Encoding::BINARY + string.should_not.equal?(encoded) end - it "preserves encoding" do + it "preserves string's encoding" do string = "whatever".encode("ASCII-8BIT") CGI.escapeURIComponent(string).encoding.should == Encoding::ASCII_8BIT end + it "processes even strings with invalid encoding, percent-encoding octets as-is" do + string = "\xC0<<".dup.force_encoding("UTF-8") + CGI.escapeURIComponent(string).should == "%C0%3C%3C" + end + + it "raises a TypeError with nil" do + -> { + CGI.escapeURIComponent(nil) + }.should raise_error(TypeError, "no implicit conversion of nil into String") + end + it "uses implicit type conversion to String" do object = Object.new def object.to_str diff --git a/spec/ruby/library/cgi/unescapeURIComponent_spec.rb b/spec/ruby/library/cgi/unescapeURIComponent_spec.rb new file mode 100644 index 00000000000000..f80eb1626b4454 --- /dev/null +++ b/spec/ruby/library/cgi/unescapeURIComponent_spec.rb @@ -0,0 +1,128 @@ +require_relative '../../spec_helper' + +ruby_version_is ""..."4.0" do + require 'cgi' +end +ruby_version_is "4.0" do + require 'cgi/escape' +end + +describe "CGI.unescapeURIComponent" do + it "decodes any percent-encoded octets to their corresponding bytes according to RFC 3986" do + string = (0x00..0xff).map { |i| "%%%02x" % i }.join + expected = (0x00..0xff).map { |i| i.chr }.join.force_encoding(Encoding::UTF_8) + CGI.unescapeURIComponent(string).should == expected + end + + it "disregards case of characters in a percent-encoding triplet" do + CGI.unescapeURIComponent("%CE%B2abc").should == "βabc" + CGI.unescapeURIComponent("%ce%b2ABC").should == "βABC" + end + + it "leaves any non-percent-encoded characters as-is" do + string = "ABCDEFGHIJKLMNOPQRSTUVWXYZ:/?#[]@!$&'()*+,;=\t\x0D\xFFβᛉ▒90%" + decoded = CGI.unescapeURIComponent(string) + decoded.should == string + string.should_not.equal?(decoded) + end + + it "leaves sequences which can't be a percent-encoded octet as-is" do + string = "%AZ%B" + decoded = CGI.unescapeURIComponent(string) + decoded.should == string + string.should_not.equal?(decoded) + end + + it "creates a String with the specified target Encoding" do + string = CGI.unescapeURIComponent("%D2%3C%3CABC", Encoding::ISO_8859_1) + string.encoding.should == Encoding::ISO_8859_1 + string.should == "Ò< { CGI.unescapeURIComponent("ABC", "ISO-JOKE-1") }.should raise_error(ArgumentError, "unknown encoding name - ISO-JOKE-1") + end + + ruby_version_is ""..."4.0" do + it "uses CGI.accept_charset as the default target encoding" do + original_charset = CGI.accept_charset + CGI.accept_charset = "ISO-8859-1" + decoded = CGI.unescapeURIComponent("%D2%3C%3CABC") + decoded.should == "Ò< { + CGI.unescapeURIComponent(nil) + }.should raise_error(TypeError, "no implicit conversion of nil into String") + end + + it "uses implicit type conversion to String" do + object = Object.new + def object.to_str + "a%20b" + end + + CGI.unescapeURIComponent(object).should == "a b" + end +end diff --git a/spec/ruby/library/socket/addrinfo/afamily_spec.rb b/spec/ruby/library/socket/addrinfo/afamily_spec.rb index 7229dab9de12c2..5d075be05758f0 100644 --- a/spec/ruby/library/socket/addrinfo/afamily_spec.rb +++ b/spec/ruby/library/socket/addrinfo/afamily_spec.rb @@ -23,15 +23,13 @@ end end - with_feature :unix_socket do - describe "for a unix socket" do - before :each do - @addrinfo = Addrinfo.unix("/tmp/sock") - end - - it "returns Socket::AF_UNIX" do - @addrinfo.afamily.should == Socket::AF_UNIX - end + describe "for a unix socket" do + before :each do + @addrinfo = Addrinfo.unix("/tmp/sock") + end + + it "returns Socket::AF_UNIX" do + @addrinfo.afamily.should == Socket::AF_UNIX end end end diff --git a/spec/ruby/library/socket/addrinfo/family_addrinfo_spec.rb b/spec/ruby/library/socket/addrinfo/family_addrinfo_spec.rb index 2bc3b6a2e34e7b..3c2f9f73d8a0a9 100644 --- a/spec/ruby/library/socket/addrinfo/family_addrinfo_spec.rb +++ b/spec/ruby/library/socket/addrinfo/family_addrinfo_spec.rb @@ -50,38 +50,36 @@ end end - with_feature :unix_socket do - describe 'with a UNIX Addrinfo' do - before do - @source = Addrinfo.unix('cats') - end + describe 'with a UNIX Addrinfo' do + before do + @source = Addrinfo.unix('cats') + end - it 'raises ArgumentError if more than 1 argument is given' do - -> { @source.family_addrinfo('foo', 'bar') }.should raise_error(ArgumentError) - end + it 'raises ArgumentError if more than 1 argument is given' do + -> { @source.family_addrinfo('foo', 'bar') }.should raise_error(ArgumentError) + end - it 'returns an Addrinfo when a UNIX socket path is given' do - addr = @source.family_addrinfo('dogs') + it 'returns an Addrinfo when a UNIX socket path is given' do + addr = @source.family_addrinfo('dogs') - addr.should be_an_instance_of(Addrinfo) - end + addr.should be_an_instance_of(Addrinfo) + end - describe 'the returned Addrinfo' do - before do - @addr = @source.family_addrinfo('dogs') - end + describe 'the returned Addrinfo' do + before do + @addr = @source.family_addrinfo('dogs') + end - it 'uses AF_UNIX as the address family' do - @addr.afamily.should == Socket::AF_UNIX - end + it 'uses AF_UNIX as the address family' do + @addr.afamily.should == Socket::AF_UNIX + end - it 'uses PF_UNIX as the protocol family' do - @addr.pfamily.should == Socket::PF_UNIX - end + it 'uses PF_UNIX as the protocol family' do + @addr.pfamily.should == Socket::PF_UNIX + end - it 'uses the given socket path' do - @addr.unix_path.should == 'dogs' - end + it 'uses the given socket path' do + @addr.unix_path.should == 'dogs' end end end diff --git a/spec/ruby/library/socket/addrinfo/getnameinfo_spec.rb b/spec/ruby/library/socket/addrinfo/getnameinfo_spec.rb index 76579de74c0c67..43b5a2000a8091 100644 --- a/spec/ruby/library/socket/addrinfo/getnameinfo_spec.rb +++ b/spec/ruby/library/socket/addrinfo/getnameinfo_spec.rb @@ -22,19 +22,17 @@ platform_is :linux do platform_is_not :android do - with_feature :unix_socket do - describe 'using a UNIX Addrinfo' do - before do - @addr = Addrinfo.unix('cats') - @host = Socket.gethostname - end + describe 'using a UNIX Addrinfo' do + before do + @addr = Addrinfo.unix('cats') + @host = Socket.gethostname + end - it 'returns the hostname and UNIX socket path' do - host, path = @addr.getnameinfo + it 'returns the hostname and UNIX socket path' do + host, path = @addr.getnameinfo - host.should == @host - path.should == 'cats' - end + host.should == @host + path.should == 'cats' end end end diff --git a/spec/ruby/library/socket/addrinfo/initialize_spec.rb b/spec/ruby/library/socket/addrinfo/initialize_spec.rb index b7477efc7959f7..1f16531aaa4dea 100644 --- a/spec/ruby/library/socket/addrinfo/initialize_spec.rb +++ b/spec/ruby/library/socket/addrinfo/initialize_spec.rb @@ -17,7 +17,7 @@ @addrinfo.ip_port.should == 25 end - it "returns the Socket::UNSPEC pfamily" do + it "returns the UNSPEC pfamily" do @addrinfo.pfamily.should == Socket::PF_UNSPEC end @@ -53,7 +53,7 @@ @addrinfo.ip_port.should == 25 end - it "returns the Socket::UNSPEC pfamily" do + it "returns the INET6 pfamily" do @addrinfo.pfamily.should == Socket::PF_INET6 end @@ -83,7 +83,7 @@ @addrinfo.ip_port.should == 25 end - it "returns the Socket::UNSPEC pfamily" do + it "returns the INET6 pfamily" do @addrinfo.pfamily.should == Socket::PF_INET6 end @@ -113,7 +113,7 @@ @addrinfo.ip_port.should == 25 end - it "returns the Socket::UNSPEC pfamily" do + it "returns the INET6 pfamily" do @addrinfo.pfamily.should == Socket::PF_INET6 end @@ -147,11 +147,11 @@ @addrinfo.ip_port.should == 46102 end - it "returns the Socket::PF_INET pfamily" do + it "returns the INET pfamily" do @addrinfo.pfamily.should == Socket::PF_INET end - it "returns the INET6 afamily" do + it "returns the INET afamily" do @addrinfo.afamily.should == Socket::AF_INET end @@ -217,11 +217,11 @@ @addrinfo.ip_port.should == 46102 end - it "returns the Socket::UNSPEC pfamily" do + it "returns the INET pfamily" do @addrinfo.pfamily.should == Socket::PF_INET end - it "returns the INET6 afamily" do + it "returns the INET afamily" do @addrinfo.afamily.should == Socket::AF_INET end @@ -247,11 +247,11 @@ @addrinfo.ip_port.should == 46102 end - it "returns the Socket::UNSPEC pfamily" do + it "returns the INET pfamily" do @addrinfo.pfamily.should == Socket::PF_INET end - it "returns the INET6 afamily" do + it "returns the INET afamily" do @addrinfo.afamily.should == Socket::AF_INET end @@ -311,11 +311,11 @@ @addrinfo.ip_port.should == 46102 end - it "returns the Socket::UNSPEC pfamily" do + it "returns the INET pfamily" do @addrinfo.pfamily.should == Socket::PF_INET end - it "returns the INET6 afamily" do + it "returns the INET afamily" do @addrinfo.afamily.should == Socket::AF_INET end @@ -514,13 +514,13 @@ @sockaddr = Socket.sockaddr_in(80, '127.0.0.1') end - it 'returns an Addrinfo with :PF_INET family' do + it 'returns an Addrinfo with :PF_INET family' do addr = Addrinfo.new(@sockaddr, :PF_INET) addr.pfamily.should == Socket::PF_INET end - it 'returns an Addrinfo with :INET family' do + it 'returns an Addrinfo with :INET family' do addr = Addrinfo.new(@sockaddr, :INET) addr.pfamily.should == Socket::PF_INET @@ -544,13 +544,13 @@ @sockaddr = Socket.sockaddr_in(80, '127.0.0.1') end - it 'returns an Addrinfo with "PF_INET" family' do + it 'returns an Addrinfo with "PF_INET" family' do addr = Addrinfo.new(@sockaddr, 'PF_INET') addr.pfamily.should == Socket::PF_INET end - it 'returns an Addrinfo with "INET" family' do + it 'returns an Addrinfo with "INET" family' do addr = Addrinfo.new(@sockaddr, 'INET') addr.pfamily.should == Socket::PF_INET @@ -569,23 +569,21 @@ end end - with_feature :unix_socket do - describe 'using separate arguments for a Unix socket' do - before do - @sockaddr = Socket.pack_sockaddr_un('socket') - end + describe 'using separate arguments for a Unix socket' do + before do + @sockaddr = Socket.pack_sockaddr_un('socket') + end - it 'returns an Addrinfo with the correct unix path' do - Addrinfo.new(@sockaddr).unix_path.should == 'socket' - end + it 'returns an Addrinfo with the correct unix path' do + Addrinfo.new(@sockaddr).unix_path.should == 'socket' + end - it 'returns an Addrinfo with the correct protocol family' do - Addrinfo.new(@sockaddr).pfamily.should == Socket::PF_UNSPEC - end + it 'returns an Addrinfo with the correct protocol family' do + Addrinfo.new(@sockaddr).pfamily.should == Socket::PF_UNSPEC + end - it 'returns an Addrinfo with the correct address family' do - Addrinfo.new(@sockaddr).afamily.should == Socket::AF_UNIX - end + it 'returns an Addrinfo with the correct address family' do + Addrinfo.new(@sockaddr).afamily.should == Socket::AF_UNIX end end end diff --git a/spec/ruby/library/socket/addrinfo/inspect_sockaddr_spec.rb b/spec/ruby/library/socket/addrinfo/inspect_sockaddr_spec.rb index 70ca4dd4d76388..6b18c794694499 100644 --- a/spec/ruby/library/socket/addrinfo/inspect_sockaddr_spec.rb +++ b/spec/ruby/library/socket/addrinfo/inspect_sockaddr_spec.rb @@ -32,19 +32,17 @@ end end - with_feature :unix_socket do - describe 'using a UNIX path' do - it 'returns a String containing the UNIX path' do - addr = Addrinfo.unix('/foo/bar') + describe 'using a UNIX path' do + it 'returns a String containing the UNIX path' do + addr = Addrinfo.unix('/foo/bar') - addr.inspect_sockaddr.should == '/foo/bar' - end + addr.inspect_sockaddr.should == '/foo/bar' + end - it 'returns a String containing the UNIX path when using a relative path' do - addr = Addrinfo.unix('foo') + it 'returns a String containing the UNIX path when using a relative path' do + addr = Addrinfo.unix('foo') - addr.inspect_sockaddr.should == 'UNIX foo' - end + addr.inspect_sockaddr.should == 'UNIX foo' end end end diff --git a/spec/ruby/library/socket/addrinfo/inspect_spec.rb b/spec/ruby/library/socket/addrinfo/inspect_spec.rb index 98e1e83ffa921f..1442af61627302 100644 --- a/spec/ruby/library/socket/addrinfo/inspect_spec.rb +++ b/spec/ruby/library/socket/addrinfo/inspect_spec.rb @@ -41,25 +41,23 @@ end end - with_feature :unix_socket do - describe 'using a UNIX Addrinfo' do - it 'returns a String' do - addr = Addrinfo.unix('/foo') + describe 'using a UNIX Addrinfo' do + it 'returns a String' do + addr = Addrinfo.unix('/foo') - addr.inspect.should == '#' - end + addr.inspect.should == '#' + end - it 'returns a String when using a relative UNIX path' do - addr = Addrinfo.unix('foo') + it 'returns a String when using a relative UNIX path' do + addr = Addrinfo.unix('foo') - addr.inspect.should == '#' - end + addr.inspect.should == '#' + end - it 'returns a String when using a DGRAM socket' do - addr = Addrinfo.unix('/foo', Socket::SOCK_DGRAM) + it 'returns a String when using a DGRAM socket' do + addr = Addrinfo.unix('/foo', Socket::SOCK_DGRAM) - addr.inspect.should == '#' - end + addr.inspect.should == '#' end end end diff --git a/spec/ruby/library/socket/addrinfo/ip_address_spec.rb b/spec/ruby/library/socket/addrinfo/ip_address_spec.rb index 4522cf5cfd4f44..193432e861cf0f 100644 --- a/spec/ruby/library/socket/addrinfo/ip_address_spec.rb +++ b/spec/ruby/library/socket/addrinfo/ip_address_spec.rb @@ -21,15 +21,13 @@ end end - with_feature :unix_socket do - describe "for a unix socket" do - before :each do - @addrinfo = Addrinfo.unix("/tmp/sock") - end + describe "for a unix socket" do + before :each do + @addrinfo = Addrinfo.unix("/tmp/sock") + end - it "raises an exception" do - -> { @addrinfo.ip_address }.should raise_error(SocketError) - end + it "raises an exception" do + -> { @addrinfo.ip_address }.should raise_error(SocketError) end end diff --git a/spec/ruby/library/socket/addrinfo/ip_port_spec.rb b/spec/ruby/library/socket/addrinfo/ip_port_spec.rb index 4118607db0dab7..f10ce35143d822 100644 --- a/spec/ruby/library/socket/addrinfo/ip_port_spec.rb +++ b/spec/ruby/library/socket/addrinfo/ip_port_spec.rb @@ -21,15 +21,13 @@ end end - with_feature :unix_socket do - describe "for a unix socket" do - before :each do - @addrinfo = Addrinfo.unix("/tmp/sock") - end + describe "for a unix socket" do + before :each do + @addrinfo = Addrinfo.unix("/tmp/sock") + end - it "raises an exception" do - -> { @addrinfo.ip_port }.should raise_error(SocketError) - end + it "raises an exception" do + -> { @addrinfo.ip_port }.should raise_error(SocketError) end end end diff --git a/spec/ruby/library/socket/addrinfo/ip_spec.rb b/spec/ruby/library/socket/addrinfo/ip_spec.rb index 80e7a62df7c902..09b93416055933 100644 --- a/spec/ruby/library/socket/addrinfo/ip_spec.rb +++ b/spec/ruby/library/socket/addrinfo/ip_spec.rb @@ -22,15 +22,13 @@ end end - with_feature :unix_socket do - describe "for a unix socket" do - before :each do - @addrinfo = Addrinfo.unix("/tmp/sock") - end + describe "for a unix socket" do + before :each do + @addrinfo = Addrinfo.unix("/tmp/sock") + end - it "returns false" do - @addrinfo.ip?.should be_false - end + it "returns false" do + @addrinfo.ip?.should be_false end end end diff --git a/spec/ruby/library/socket/addrinfo/ip_unpack_spec.rb b/spec/ruby/library/socket/addrinfo/ip_unpack_spec.rb index 6c81c48d1ca066..58260c45578972 100644 --- a/spec/ruby/library/socket/addrinfo/ip_unpack_spec.rb +++ b/spec/ruby/library/socket/addrinfo/ip_unpack_spec.rb @@ -21,15 +21,13 @@ end end - with_feature :unix_socket do - describe "for a unix socket" do - before :each do - @addrinfo = Addrinfo.unix("/tmp/sock") - end + describe "for a unix socket" do + before :each do + @addrinfo = Addrinfo.unix("/tmp/sock") + end - it "raises an exception" do - -> { @addrinfo.ip_unpack }.should raise_error(SocketError) - end + it "raises an exception" do + -> { @addrinfo.ip_unpack }.should raise_error(SocketError) end end end diff --git a/spec/ruby/library/socket/addrinfo/ipv4_loopback_spec.rb b/spec/ruby/library/socket/addrinfo/ipv4_loopback_spec.rb index 10ad084fc93bb4..3a584d4f52fbcd 100644 --- a/spec/ruby/library/socket/addrinfo/ipv4_loopback_spec.rb +++ b/spec/ruby/library/socket/addrinfo/ipv4_loopback_spec.rb @@ -29,15 +29,13 @@ end end - with_feature :unix_socket do - describe "for a unix socket" do - before :each do - @addrinfo = Addrinfo.unix("/tmp/sock") - end + describe "for a unix socket" do + before :each do + @addrinfo = Addrinfo.unix("/tmp/sock") + end - it "returns false" do - @addrinfo.ipv4_loopback?.should be_false - end + it "returns false" do + @addrinfo.ipv4_loopback?.should be_false end end end diff --git a/spec/ruby/library/socket/addrinfo/ipv4_multicast_spec.rb b/spec/ruby/library/socket/addrinfo/ipv4_multicast_spec.rb index f7fead86409680..e4b4cfcc84a773 100644 --- a/spec/ruby/library/socket/addrinfo/ipv4_multicast_spec.rb +++ b/spec/ruby/library/socket/addrinfo/ipv4_multicast_spec.rb @@ -15,15 +15,13 @@ Addrinfo.ip('::1').should_not.ipv4_multicast? end - with_feature :unix_socket do - describe "for a unix socket" do - before :each do - @addrinfo = Addrinfo.unix("/tmp/sock") - end + describe "for a unix socket" do + before :each do + @addrinfo = Addrinfo.unix("/tmp/sock") + end - it "returns false" do - @addrinfo.ipv4_multicast?.should be_false - end + it "returns false" do + @addrinfo.ipv4_multicast?.should be_false end end end diff --git a/spec/ruby/library/socket/addrinfo/ipv4_private_spec.rb b/spec/ruby/library/socket/addrinfo/ipv4_private_spec.rb index e5a33b4953f38f..97218b5ba327dd 100644 --- a/spec/ruby/library/socket/addrinfo/ipv4_private_spec.rb +++ b/spec/ruby/library/socket/addrinfo/ipv4_private_spec.rb @@ -33,15 +33,13 @@ end end - with_feature :unix_socket do - describe "for a unix socket" do - before :each do - @addrinfo = Addrinfo.unix("/tmp/sock") - end - - it "returns false" do - @addrinfo.ipv4_private?.should be_false - end + describe "for a unix socket" do + before :each do + @addrinfo = Addrinfo.unix("/tmp/sock") + end + + it "returns false" do + @addrinfo.ipv4_private?.should be_false end end end diff --git a/spec/ruby/library/socket/addrinfo/ipv4_spec.rb b/spec/ruby/library/socket/addrinfo/ipv4_spec.rb index 7cba8209b6b1b1..61f7759b108952 100644 --- a/spec/ruby/library/socket/addrinfo/ipv4_spec.rb +++ b/spec/ruby/library/socket/addrinfo/ipv4_spec.rb @@ -21,15 +21,13 @@ end end - with_feature :unix_socket do - describe "for a unix socket" do - before :each do - @addrinfo = Addrinfo.unix("/tmp/sock") - end + describe "for a unix socket" do + before :each do + @addrinfo = Addrinfo.unix("/tmp/sock") + end - it "returns false" do - @addrinfo.ipv4?.should be_false - end + it "returns false" do + @addrinfo.ipv4?.should be_false end end end diff --git a/spec/ruby/library/socket/addrinfo/ipv6_loopback_spec.rb b/spec/ruby/library/socket/addrinfo/ipv6_loopback_spec.rb index 9ff8f107bf32e5..ffc75185ead603 100644 --- a/spec/ruby/library/socket/addrinfo/ipv6_loopback_spec.rb +++ b/spec/ruby/library/socket/addrinfo/ipv6_loopback_spec.rb @@ -31,15 +31,13 @@ end end - with_feature :unix_socket do - describe "for a unix socket" do - before :each do - @addrinfo = Addrinfo.unix("/tmp/sock") - end - - it "returns false" do - @addrinfo.ipv6_loopback?.should be_false - end + describe "for a unix socket" do + before :each do + @addrinfo = Addrinfo.unix("/tmp/sock") + end + + it "returns false" do + @addrinfo.ipv6_loopback?.should be_false end end end diff --git a/spec/ruby/library/socket/addrinfo/ipv6_multicast_spec.rb b/spec/ruby/library/socket/addrinfo/ipv6_multicast_spec.rb index 2c987b59210acf..99d4e8cf4d8577 100644 --- a/spec/ruby/library/socket/addrinfo/ipv6_multicast_spec.rb +++ b/spec/ruby/library/socket/addrinfo/ipv6_multicast_spec.rb @@ -34,15 +34,13 @@ end end - with_feature :unix_socket do - describe "for a unix socket" do - before :each do - @addrinfo = Addrinfo.unix("/tmp/sock") - end - - it "returns false" do - @addrinfo.ipv6_multicast?.should be_false - end + describe "for a unix socket" do + before :each do + @addrinfo = Addrinfo.unix("/tmp/sock") + end + + it "returns false" do + @addrinfo.ipv6_multicast?.should be_false end end end diff --git a/spec/ruby/library/socket/addrinfo/ipv6_spec.rb b/spec/ruby/library/socket/addrinfo/ipv6_spec.rb index 131e38849c3abe..436d5e930b415e 100644 --- a/spec/ruby/library/socket/addrinfo/ipv6_spec.rb +++ b/spec/ruby/library/socket/addrinfo/ipv6_spec.rb @@ -21,15 +21,13 @@ end end - with_feature :unix_socket do - describe "for a unix socket" do - before :each do - @addrinfo = Addrinfo.unix("/tmp/sock") - end + describe "for a unix socket" do + before :each do + @addrinfo = Addrinfo.unix("/tmp/sock") + end - it "returns false" do - @addrinfo.ipv6?.should be_false - end + it "returns false" do + @addrinfo.ipv6?.should be_false end end end diff --git a/spec/ruby/library/socket/addrinfo/ipv6_to_ipv4_spec.rb b/spec/ruby/library/socket/addrinfo/ipv6_to_ipv4_spec.rb index 6dfaf531aecc7a..29050bec20e9cd 100644 --- a/spec/ruby/library/socket/addrinfo/ipv6_to_ipv4_spec.rb +++ b/spec/ruby/library/socket/addrinfo/ipv6_to_ipv4_spec.rb @@ -62,7 +62,7 @@ Addrinfo.ip('192.168.1.1').ipv6_to_ipv4.should be_nil end - with_feature :unix_socket do + describe 'for a unix socket' do it 'returns nil for a UNIX Addrinfo' do Addrinfo.unix('foo').ipv6_to_ipv4.should be_nil end diff --git a/spec/ruby/library/socket/addrinfo/marshal_dump_spec.rb b/spec/ruby/library/socket/addrinfo/marshal_dump_spec.rb index 2d69a33b53b73f..e2c3497f7fc513 100644 --- a/spec/ruby/library/socket/addrinfo/marshal_dump_spec.rb +++ b/spec/ruby/library/socket/addrinfo/marshal_dump_spec.rb @@ -42,40 +42,38 @@ end end - with_feature :unix_socket do - describe 'using a UNIX Addrinfo' do + describe 'using a UNIX Addrinfo' do + before do + @addr = Addrinfo.unix('foo') + end + + it 'returns an Array' do + @addr.marshal_dump.should be_an_instance_of(Array) + end + + describe 'the returned Array' do before do - @addr = Addrinfo.unix('foo') + @array = @addr.marshal_dump end - it 'returns an Array' do - @addr.marshal_dump.should be_an_instance_of(Array) + it 'includes the address family as the 1st value' do + @array[0].should == 'AF_UNIX' end - describe 'the returned Array' do - before do - @array = @addr.marshal_dump - end - - it 'includes the address family as the 1st value' do - @array[0].should == 'AF_UNIX' - end - - it 'includes the UNIX path as the 2nd value' do - @array[1].should == @addr.unix_path - end + it 'includes the UNIX path as the 2nd value' do + @array[1].should == @addr.unix_path + end - it 'includes the protocol family as the 3rd value' do - @array[2].should == 'PF_UNIX' - end + it 'includes the protocol family as the 3rd value' do + @array[2].should == 'PF_UNIX' + end - it 'includes the socket type as the 4th value' do - @array[3].should == 'SOCK_STREAM' - end + it 'includes the socket type as the 4th value' do + @array[3].should == 'SOCK_STREAM' + end - it 'includes the protocol as the 5th value' do - @array[4].should == 0 - end + it 'includes the protocol as the 5th value' do + @array[4].should == 0 end end end diff --git a/spec/ruby/library/socket/addrinfo/marshal_load_spec.rb b/spec/ruby/library/socket/addrinfo/marshal_load_spec.rb index aa208652241ae6..02cef901158188 100644 --- a/spec/ruby/library/socket/addrinfo/marshal_load_spec.rb +++ b/spec/ruby/library/socket/addrinfo/marshal_load_spec.rb @@ -18,18 +18,16 @@ end end - with_feature :unix_socket do - describe 'using a UNIX socket' do - it 'returns a new Addrinfo' do - source = Addrinfo.unix('foo') - addr = Marshal.load(Marshal.dump(source)) + describe 'using a UNIX socket' do + it 'returns a new Addrinfo' do + source = Addrinfo.unix('foo') + addr = Marshal.load(Marshal.dump(source)) - addr.afamily.should == source.afamily - addr.pfamily.should == source.pfamily - addr.socktype.should == source.socktype - addr.protocol.should == source.protocol - addr.unix_path.should == source.unix_path - end + addr.afamily.should == source.afamily + addr.pfamily.should == source.pfamily + addr.socktype.should == source.socktype + addr.protocol.should == source.protocol + addr.unix_path.should == source.unix_path end end end diff --git a/spec/ruby/library/socket/addrinfo/pfamily_spec.rb b/spec/ruby/library/socket/addrinfo/pfamily_spec.rb index 984744a964a805..da530b7fdc19c1 100644 --- a/spec/ruby/library/socket/addrinfo/pfamily_spec.rb +++ b/spec/ruby/library/socket/addrinfo/pfamily_spec.rb @@ -29,15 +29,13 @@ end end - with_feature :unix_socket do - describe "for a unix socket" do - before :each do - @addrinfo = Addrinfo.unix("/tmp/sock") - end - - it "returns Socket::PF_UNIX" do - @addrinfo.pfamily.should == Socket::PF_UNIX - end + describe "for a unix socket" do + before :each do + @addrinfo = Addrinfo.unix("/tmp/sock") + end + + it "returns Socket::PF_UNIX" do + @addrinfo.pfamily.should == Socket::PF_UNIX end end end diff --git a/spec/ruby/library/socket/addrinfo/protocol_spec.rb b/spec/ruby/library/socket/addrinfo/protocol_spec.rb index ea143fc4a80c19..f6ffc9acf9e893 100644 --- a/spec/ruby/library/socket/addrinfo/protocol_spec.rb +++ b/spec/ruby/library/socket/addrinfo/protocol_spec.rb @@ -10,15 +10,13 @@ Addrinfo.tcp('::1', 80).protocol.should == Socket::IPPROTO_TCP end - with_feature :unix_socket do - describe "for a unix socket" do - before :each do - @addrinfo = Addrinfo.unix("/tmp/sock") - end + describe "for a unix socket" do + before :each do + @addrinfo = Addrinfo.unix("/tmp/sock") + end - it "returns 0" do - @addrinfo.protocol.should == 0 - end + it "returns 0" do + @addrinfo.protocol.should == 0 end end end diff --git a/spec/ruby/library/socket/addrinfo/shared/to_sockaddr.rb b/spec/ruby/library/socket/addrinfo/shared/to_sockaddr.rb index 4f7cf439a07ac1..70d6bfbbfed7a7 100644 --- a/spec/ruby/library/socket/addrinfo/shared/to_sockaddr.rb +++ b/spec/ruby/library/socket/addrinfo/shared/to_sockaddr.rb @@ -19,15 +19,13 @@ end end - with_feature :unix_socket do - describe "for a unix socket" do - before :each do - @addrinfo = Addrinfo.unix("/tmp/sock") - end - - it "returns a sockaddr packed structure" do - @addrinfo.send(@method).should == Socket.sockaddr_un('/tmp/sock') - end + describe "for a unix socket" do + before :each do + @addrinfo = Addrinfo.unix("/tmp/sock") + end + + it "returns a sockaddr packed structure" do + @addrinfo.send(@method).should == Socket.sockaddr_un('/tmp/sock') end end diff --git a/spec/ruby/library/socket/addrinfo/socktype_spec.rb b/spec/ruby/library/socket/addrinfo/socktype_spec.rb index b994bea140d63f..e5f02cd7593cf3 100644 --- a/spec/ruby/library/socket/addrinfo/socktype_spec.rb +++ b/spec/ruby/library/socket/addrinfo/socktype_spec.rb @@ -9,15 +9,13 @@ Addrinfo.tcp('127.0.0.1', 80).socktype.should == Socket::SOCK_STREAM end - with_feature :unix_socket do - describe "for a unix socket" do - before :each do - @addrinfo = Addrinfo.unix("/tmp/sock") - end + describe "for a unix socket" do + before :each do + @addrinfo = Addrinfo.unix("/tmp/sock") + end - it "returns Socket::SOCK_STREAM" do - @addrinfo.socktype.should == Socket::SOCK_STREAM - end + it "returns Socket::SOCK_STREAM" do + @addrinfo.socktype.should == Socket::SOCK_STREAM end end end diff --git a/spec/ruby/library/socket/addrinfo/unix_path_spec.rb b/spec/ruby/library/socket/addrinfo/unix_path_spec.rb index 6bfb56a4ac9cc3..2a9076a3544271 100644 --- a/spec/ruby/library/socket/addrinfo/unix_path_spec.rb +++ b/spec/ruby/library/socket/addrinfo/unix_path_spec.rb @@ -1,37 +1,35 @@ require_relative '../spec_helper' -with_feature :unix_socket do - describe "Addrinfo#unix_path" do - describe "for an ipv4 socket" do +describe "Addrinfo#unix_path" do + describe "for an ipv4 socket" do - before :each do - @addrinfo = Addrinfo.tcp("127.0.0.1", 80) - end - - it "raises an exception" do - -> { @addrinfo.unix_path }.should raise_error(SocketError) - end + before :each do + @addrinfo = Addrinfo.tcp("127.0.0.1", 80) + end + it "raises an exception" do + -> { @addrinfo.unix_path }.should raise_error(SocketError) end - describe "for an ipv6 socket" do - before :each do - @addrinfo = Addrinfo.tcp("::1", 80) - end + end - it "raises an exception" do - -> { @addrinfo.unix_path }.should raise_error(SocketError) - end + describe "for an ipv6 socket" do + before :each do + @addrinfo = Addrinfo.tcp("::1", 80) end - describe "for a unix socket" do - before :each do - @addrinfo = Addrinfo.unix("/tmp/sock") - end + it "raises an exception" do + -> { @addrinfo.unix_path }.should raise_error(SocketError) + end + end + + describe "for a unix socket" do + before :each do + @addrinfo = Addrinfo.unix("/tmp/sock") + end - it "returns the socket path" do - @addrinfo.unix_path.should == "/tmp/sock" - end + it "returns the socket path" do + @addrinfo.unix_path.should == "/tmp/sock" end end end diff --git a/spec/ruby/library/socket/addrinfo/unix_spec.rb b/spec/ruby/library/socket/addrinfo/unix_spec.rb index 4596ece17e5d9a..7597533a769c7d 100644 --- a/spec/ruby/library/socket/addrinfo/unix_spec.rb +++ b/spec/ruby/library/socket/addrinfo/unix_spec.rb @@ -1,36 +1,34 @@ require_relative '../spec_helper' -with_feature :unix_socket do - describe 'Addrinfo.unix' do - it 'returns an Addrinfo instance' do - Addrinfo.unix('socket').should be_an_instance_of(Addrinfo) - end +describe 'Addrinfo.unix' do + it 'returns an Addrinfo instance' do + Addrinfo.unix('socket').should be_an_instance_of(Addrinfo) + end - it 'sets the IP address' do - Addrinfo.unix('socket').unix_path.should == 'socket' - end + it 'sets the IP address' do + Addrinfo.unix('socket').unix_path.should == 'socket' + end - it 'sets the address family' do - Addrinfo.unix('socket').afamily.should == Socket::AF_UNIX - end + it 'sets the address family' do + Addrinfo.unix('socket').afamily.should == Socket::AF_UNIX + end - it 'sets the protocol family' do - Addrinfo.unix('socket').pfamily.should == Socket::PF_UNIX - end + it 'sets the protocol family' do + Addrinfo.unix('socket').pfamily.should == Socket::PF_UNIX + end - it 'sets the socket type' do - Addrinfo.unix('socket').socktype.should == Socket::SOCK_STREAM - end + it 'sets the socket type' do + Addrinfo.unix('socket').socktype.should == Socket::SOCK_STREAM + end - it 'sets a custom socket type' do - addr = Addrinfo.unix('socket', Socket::SOCK_DGRAM) + it 'sets a custom socket type' do + addr = Addrinfo.unix('socket', Socket::SOCK_DGRAM) - addr.socktype.should == Socket::SOCK_DGRAM - end + addr.socktype.should == Socket::SOCK_DGRAM + end - it 'sets the socket protocol to 0' do - Addrinfo.unix('socket').protocol.should == 0 - end + it 'sets the socket protocol to 0' do + Addrinfo.unix('socket').protocol.should == 0 end end diff --git a/spec/ruby/library/socket/basicsocket/connect_address_spec.rb b/spec/ruby/library/socket/basicsocket/connect_address_spec.rb index 1a1c9982d942ca..2e318fcb851391 100644 --- a/spec/ruby/library/socket/basicsocket/connect_address_spec.rb +++ b/spec/ruby/library/socket/basicsocket/connect_address_spec.rb @@ -94,61 +94,59 @@ end end - with_feature :unix_socket do - platform_is_not :aix do - describe 'using an unbound UNIX socket' do - before do - @path = SocketSpecs.socket_path - @server = UNIXServer.new(@path) - @client = UNIXSocket.new(@path) - end - - after do - @client.close - @server.close - rm_r(@path) - end - - it 'raises SocketError' do - -> { @client.connect_address }.should raise_error(SocketError) - end - end - end - - describe 'using a bound UNIX socket' do + platform_is_not :aix do + describe 'using an unbound UNIX socket' do before do @path = SocketSpecs.socket_path - @sock = UNIXServer.new(@path) + @server = UNIXServer.new(@path) + @client = UNIXSocket.new(@path) end after do - @sock.close + @client.close + @server.close rm_r(@path) end - it 'returns an Addrinfo' do - @sock.connect_address.should be_an_instance_of(Addrinfo) + it 'raises SocketError' do + -> { @client.connect_address }.should raise_error(SocketError) end + end + end - it 'uses the correct socket path' do - @sock.connect_address.unix_path.should == @path - end + describe 'using a bound UNIX socket' do + before do + @path = SocketSpecs.socket_path + @sock = UNIXServer.new(@path) + end - it 'uses AF_UNIX as the address family' do - @sock.connect_address.afamily.should == Socket::AF_UNIX - end + after do + @sock.close + rm_r(@path) + end - it 'uses PF_UNIX as the protocol family' do - @sock.connect_address.pfamily.should == Socket::PF_UNIX - end + it 'returns an Addrinfo' do + @sock.connect_address.should be_an_instance_of(Addrinfo) + end - it 'uses SOCK_STREAM as the socket type' do - @sock.connect_address.socktype.should == Socket::SOCK_STREAM - end + it 'uses the correct socket path' do + @sock.connect_address.unix_path.should == @path + end - it 'uses 0 as the protocol' do - @sock.connect_address.protocol.should == 0 - end + it 'uses AF_UNIX as the address family' do + @sock.connect_address.afamily.should == Socket::AF_UNIX + end + + it 'uses PF_UNIX as the protocol family' do + @sock.connect_address.pfamily.should == Socket::PF_UNIX + end + + it 'uses SOCK_STREAM as the socket type' do + @sock.connect_address.socktype.should == Socket::SOCK_STREAM + end + + it 'uses 0 as the protocol' do + @sock.connect_address.protocol.should == 0 end end end diff --git a/spec/ruby/library/socket/basicsocket/getpeereid_spec.rb b/spec/ruby/library/socket/basicsocket/getpeereid_spec.rb index 6179211d9617d3..2e03cd3684bd99 100644 --- a/spec/ruby/library/socket/basicsocket/getpeereid_spec.rb +++ b/spec/ruby/library/socket/basicsocket/getpeereid_spec.rb @@ -2,7 +2,7 @@ require_relative '../fixtures/classes' describe 'BasicSocket#getpeereid' do - with_feature :unix_socket do + platform_is_not :windows do describe 'using a UNIXSocket' do before do @path = SocketSpecs.socket_path diff --git a/spec/ruby/library/socket/basicsocket/setsockopt_spec.rb b/spec/ruby/library/socket/basicsocket/setsockopt_spec.rb index 1e8d84e1c9ecd0..f686e673263789 100644 --- a/spec/ruby/library/socket/basicsocket/setsockopt_spec.rb +++ b/spec/ruby/library/socket/basicsocket/setsockopt_spec.rb @@ -315,22 +315,20 @@ end end - with_feature :unix_socket do - describe 'using a UNIX socket' do - before do - @path = SocketSpecs.socket_path - @server = UNIXServer.new(@path) - end + describe 'using a UNIX socket' do + before do + @path = SocketSpecs.socket_path + @server = UNIXServer.new(@path) + end - after do - @server.close - rm_r @path - end + after do + @server.close + rm_r @path + end - it 'sets a boolean option' do - @server.setsockopt(:SOCKET, :REUSEADDR, true) - @server.getsockopt(:SOCKET, :REUSEADDR).bool.should == true - end + it 'sets a boolean option' do + @server.setsockopt(:SOCKET, :REUSEADDR, true) + @server.getsockopt(:SOCKET, :REUSEADDR).bool.should == true end end end diff --git a/spec/ruby/library/socket/shared/address.rb b/spec/ruby/library/socket/shared/address.rb index f3be9cfb9985e0..b548f1eac06464 100644 --- a/spec/ruby/library/socket/shared/address.rb +++ b/spec/ruby/library/socket/shared/address.rb @@ -129,41 +129,51 @@ end end - with_feature :unix_socket do - describe 'using UNIXSocket' do - before :each do - @path = SocketSpecs.socket_path - @s = UNIXServer.new(@path) - @a = UNIXSocket.new(@path) - @b = @s.accept - @addr = @object.call(@a) - end + describe 'using UNIXSocket' do + before :each do + @path = SocketSpecs.socket_path + @s = UNIXServer.new(@path) + @a = UNIXSocket.new(@path) + @b = @s.accept + @addr = @object.call(@a) + end - after :each do - [@b, @a, @s].each(&:close) - rm_r(@path) - end + after :each do + [@b, @a, @s].each(&:close) + rm_r(@path) + end - it 'uses AF_UNIX as the address family' do - @addr.afamily.should == Socket::AF_UNIX - end + it 'uses AF_UNIX as the address family' do + @addr.afamily.should == Socket::AF_UNIX + end - it 'uses PF_UNIX as the protocol family' do - @addr.pfamily.should == Socket::PF_UNIX - end + it 'uses PF_UNIX as the protocol family' do + @addr.pfamily.should == Socket::PF_UNIX + end - it 'uses SOCK_STREAM as the socket type' do - @addr.socktype.should == Socket::SOCK_STREAM + it 'uses SOCK_STREAM as the socket type' do + @addr.socktype.should == Socket::SOCK_STREAM + end + + it 'uses the correct socket path' do + if @method == :local_address + @addr.unix_path.should == "" + else + @addr.unix_path.should == @path end + end - it 'uses the correct socket path' do + platform_is_not :windows do + it 'equals address of peer socket' do if @method == :local_address - @addr.unix_path.should == "" + @addr.to_s.should == @b.remote_address.to_s else - @addr.unix_path.should == @path + @addr.to_s.should == @b.local_address.to_s end end + end + guard -> { platform_is :windows and ruby_bug "#21702", ""..."4.1" } do it 'equals address of peer socket' do if @method == :local_address @addr.to_s.should == @b.remote_address.to_s @@ -171,23 +181,23 @@ @addr.to_s.should == @b.local_address.to_s end end + end - it 'returns an Addrinfo' do - @addr.should be_an_instance_of(Addrinfo) - end + it 'returns an Addrinfo' do + @addr.should be_an_instance_of(Addrinfo) + end - it 'uses 0 as the protocol' do - @addr.protocol.should == 0 - end + it 'uses 0 as the protocol' do + @addr.protocol.should == 0 + end - it 'can be used to connect to the server' do - skip if @method == :local_address - b = @addr.connect - begin - b.remote_address.to_s.should == @addr.to_s - ensure - b.close - end + it 'can be used to connect to the server' do + skip if @method == :local_address + b = @addr.connect + begin + b.remote_address.to_s.should == @addr.to_s + ensure + b.close end end end diff --git a/spec/ruby/library/socket/shared/pack_sockaddr.rb b/spec/ruby/library/socket/shared/pack_sockaddr.rb index f309aa02c7ad03..4bfcf4edb9d908 100644 --- a/spec/ruby/library/socket/shared/pack_sockaddr.rb +++ b/spec/ruby/library/socket/shared/pack_sockaddr.rb @@ -47,23 +47,21 @@ end describe :socket_pack_sockaddr_un, shared: true do - with_feature :unix_socket do - it 'should be idempotent' do - bytes = Socket.public_send(@method, '/tmp/foo').bytes - bytes[2..9].should == [47, 116, 109, 112, 47, 102, 111, 111] - bytes[10..-1].all?(&:zero?).should == true - end + it 'should be idempotent' do + bytes = Socket.public_send(@method, '/tmp/foo').bytes + bytes[2..9].should == [47, 116, 109, 112, 47, 102, 111, 111] + bytes[10..-1].all?(&:zero?).should == true + end - it "packs and unpacks" do - sockaddr_un = Socket.public_send(@method, '/tmp/s') - Socket.unpack_sockaddr_un(sockaddr_un).should == '/tmp/s' - end + it "packs and unpacks" do + sockaddr_un = Socket.public_send(@method, '/tmp/s') + Socket.unpack_sockaddr_un(sockaddr_un).should == '/tmp/s' + end - it "handles correctly paths with multibyte chars" do - sockaddr_un = Socket.public_send(@method, '/home/вася/sock') - path = Socket.unpack_sockaddr_un(sockaddr_un).encode('UTF-8', 'UTF-8') - path.should == '/home/вася/sock' - end + it "handles correctly paths with multibyte chars" do + sockaddr_un = Socket.public_send(@method, '/home/вася/sock') + path = Socket.unpack_sockaddr_un(sockaddr_un).encode('UTF-8', 'UTF-8') + path.should == '/home/вася/sock' end platform_is :linux do @@ -84,7 +82,7 @@ end end - platform_is_not :windows, :aix do + platform_is_not :aix do it "raises ArgumentError for paths that are too long" do # AIX doesn't raise error long_path = 'a' * 110 diff --git a/spec/ruby/library/socket/socket/unix_server_loop_spec.rb b/spec/ruby/library/socket/socket/unix_server_loop_spec.rb index 0f34d4a50baa89..6192bc8bf6d166 100644 --- a/spec/ruby/library/socket/socket/unix_server_loop_spec.rb +++ b/spec/ruby/library/socket/socket/unix_server_loop_spec.rb @@ -1,58 +1,56 @@ require_relative '../spec_helper' require_relative '../fixtures/classes' -with_feature :unix_socket do - describe 'Socket.unix_server_loop' do - before do - @path = SocketSpecs.socket_path - end +describe 'Socket.unix_server_loop' do + before do + @path = SocketSpecs.socket_path + end - after do - rm_r(@path) if File.file?(@path) - end + after do + rm_r(@path) if File.file?(@path) + end - describe 'when no connections are available' do - it 'blocks the caller' do - -> { Socket.unix_server_loop(@path) }.should block_caller - end + describe 'when no connections are available' do + it 'blocks the caller' do + -> { Socket.unix_server_loop(@path) }.should block_caller end + end - describe 'when a connection is available' do - before do - @client = nil - end + describe 'when a connection is available' do + before do + @client = nil + end - after do - @sock.close if @sock - @client.close if @client - end + after do + @sock.close if @sock + @client.close if @client + end - it 'yields a Socket and an Addrinfo' do - @sock, addr = nil + it 'yields a Socket and an Addrinfo' do + @sock, addr = nil - thread = Thread.new do - Socket.unix_server_loop(@path) do |socket, addrinfo| - @sock = socket - addr = addrinfo + thread = Thread.new do + Socket.unix_server_loop(@path) do |socket, addrinfo| + @sock = socket + addr = addrinfo - break - end + break end + end - SocketSpecs.loop_with_timeout do - begin - @client = Socket.unix(@path) - rescue SystemCallError - sleep 0.01 - :retry - end + SocketSpecs.loop_with_timeout do + begin + @client = Socket.unix(@path) + rescue SystemCallError + sleep 0.01 + :retry end + end - thread.join + thread.join - @sock.should be_an_instance_of(Socket) - addr.should be_an_instance_of(Addrinfo) - end + @sock.should be_an_instance_of(Socket) + addr.should be_an_instance_of(Addrinfo) end end end diff --git a/spec/ruby/library/socket/socket/unix_server_socket_spec.rb b/spec/ruby/library/socket/socket/unix_server_socket_spec.rb index fc357740fa79bd..34c3b96d077e7f 100644 --- a/spec/ruby/library/socket/socket/unix_server_socket_spec.rb +++ b/spec/ruby/library/socket/socket/unix_server_socket_spec.rb @@ -1,48 +1,46 @@ require_relative '../spec_helper' require_relative '../fixtures/classes' -with_feature :unix_socket do - describe 'Socket.unix_server_socket' do +describe 'Socket.unix_server_socket' do + before do + @path = SocketSpecs.socket_path + end + + after do + rm_r(@path) + end + + describe 'when no block is given' do before do - @path = SocketSpecs.socket_path + @socket = nil end after do - rm_r(@path) + @socket.close end - describe 'when no block is given' do - before do - @socket = nil - end - - after do - @socket.close - end + it 'returns a Socket' do + @socket = Socket.unix_server_socket(@path) - it 'returns a Socket' do - @socket = Socket.unix_server_socket(@path) - - @socket.should be_an_instance_of(Socket) - end + @socket.should be_an_instance_of(Socket) end + end - describe 'when a block is given' do - it 'yields a Socket' do - Socket.unix_server_socket(@path) do |sock| - sock.should be_an_instance_of(Socket) - end + describe 'when a block is given' do + it 'yields a Socket' do + Socket.unix_server_socket(@path) do |sock| + sock.should be_an_instance_of(Socket) end + end - it 'closes the Socket when the block returns' do - socket = nil - - Socket.unix_server_socket(@path) do |sock| - socket = sock - end + it 'closes the Socket when the block returns' do + socket = nil - socket.should be_an_instance_of(Socket) + Socket.unix_server_socket(@path) do |sock| + socket = sock end + + socket.should be_an_instance_of(Socket) end end end diff --git a/spec/ruby/library/socket/socket/unix_spec.rb b/spec/ruby/library/socket/socket/unix_spec.rb index 4bff59bd4b3d44..2a5d77f96fd34e 100644 --- a/spec/ruby/library/socket/socket/unix_spec.rb +++ b/spec/ruby/library/socket/socket/unix_spec.rb @@ -1,45 +1,43 @@ require_relative '../spec_helper' require_relative '../fixtures/classes' -with_feature :unix_socket do - describe 'Socket.unix' do - before do - @path = SocketSpecs.socket_path - @server = UNIXServer.new(@path) - @socket = nil - end +describe 'Socket.unix' do + before do + @path = SocketSpecs.socket_path + @server = UNIXServer.new(@path) + @socket = nil + end - after do - @server.close - @socket.close if @socket + after do + @server.close + @socket.close if @socket - rm_r(@path) - end + rm_r(@path) + end - describe 'when no block is given' do - it 'returns a Socket' do - @socket = Socket.unix(@path) + describe 'when no block is given' do + it 'returns a Socket' do + @socket = Socket.unix(@path) - @socket.should be_an_instance_of(Socket) - end + @socket.should be_an_instance_of(Socket) end + end - describe 'when a block is given' do - it 'yields a Socket' do - Socket.unix(@path) do |sock| - sock.should be_an_instance_of(Socket) - end + describe 'when a block is given' do + it 'yields a Socket' do + Socket.unix(@path) do |sock| + sock.should be_an_instance_of(Socket) end + end - it 'closes the Socket when the block returns' do - socket = nil - - Socket.unix(@path) do |sock| - socket = sock - end + it 'closes the Socket when the block returns' do + socket = nil - socket.should.closed? + Socket.unix(@path) do |sock| + socket = sock end + + socket.should.closed? end end end diff --git a/spec/ruby/library/socket/socket/unpack_sockaddr_in_spec.rb b/spec/ruby/library/socket/socket/unpack_sockaddr_in_spec.rb index 79ec68cd184391..935b5cb5439c32 100644 --- a/spec/ruby/library/socket/socket/unpack_sockaddr_in_spec.rb +++ b/spec/ruby/library/socket/socket/unpack_sockaddr_in_spec.rb @@ -32,15 +32,13 @@ end end - with_feature :unix_socket do - it "raises an ArgumentError when the sin_family is not AF_INET" do - sockaddr = Socket.sockaddr_un '/tmp/x' - -> { Socket.unpack_sockaddr_in sockaddr }.should raise_error(ArgumentError) - end + it "raises an ArgumentError when the sin_family is not AF_INET" do + sockaddr = Socket.sockaddr_un '/tmp/x' + -> { Socket.unpack_sockaddr_in sockaddr }.should raise_error(ArgumentError) + end - it "raises an ArgumentError when passed addrinfo is not AF_INET/AF_INET6" do - addrinfo = Addrinfo.unix('/tmp/sock') - -> { Socket.unpack_sockaddr_in(addrinfo) }.should raise_error(ArgumentError) - end + it "raises an ArgumentError when passed addrinfo is not AF_INET/AF_INET6" do + addrinfo = Addrinfo.unix('/tmp/sock') + -> { Socket.unpack_sockaddr_in(addrinfo) }.should raise_error(ArgumentError) end end diff --git a/spec/ruby/library/socket/socket/unpack_sockaddr_un_spec.rb b/spec/ruby/library/socket/socket/unpack_sockaddr_un_spec.rb index 12f970f89b4b02..6e0f11de3d2db3 100644 --- a/spec/ruby/library/socket/socket/unpack_sockaddr_un_spec.rb +++ b/spec/ruby/library/socket/socket/unpack_sockaddr_un_spec.rb @@ -1,26 +1,24 @@ require_relative '../spec_helper' require_relative '../fixtures/classes' -with_feature :unix_socket do - describe 'Socket.unpack_sockaddr_un' do - it 'decodes sockaddr to unix path' do - sockaddr = Socket.sockaddr_un('/tmp/sock') - Socket.unpack_sockaddr_un(sockaddr).should == '/tmp/sock' - end +describe 'Socket.unpack_sockaddr_un' do + it 'decodes sockaddr to unix path' do + sockaddr = Socket.sockaddr_un('/tmp/sock') + Socket.unpack_sockaddr_un(sockaddr).should == '/tmp/sock' + end - it 'returns unix path from a passed Addrinfo' do - addrinfo = Addrinfo.unix('/tmp/sock') - Socket.unpack_sockaddr_un(addrinfo).should == '/tmp/sock' - end + it 'returns unix path from a passed Addrinfo' do + addrinfo = Addrinfo.unix('/tmp/sock') + Socket.unpack_sockaddr_un(addrinfo).should == '/tmp/sock' + end - it 'raises an ArgumentError when the sa_family is not AF_UNIX' do - sockaddr = Socket.sockaddr_in(0, '127.0.0.1') - -> { Socket.unpack_sockaddr_un(sockaddr) }.should raise_error(ArgumentError) - end + it 'raises an ArgumentError when the sa_family is not AF_UNIX' do + sockaddr = Socket.sockaddr_in(0, '127.0.0.1') + -> { Socket.unpack_sockaddr_un(sockaddr) }.should raise_error(ArgumentError) + end - it 'raises an ArgumentError when passed addrinfo is not AF_UNIX' do - addrinfo = Addrinfo.tcp('127.0.0.1', 0) - -> { Socket.unpack_sockaddr_un(addrinfo) }.should raise_error(ArgumentError) - end + it 'raises an ArgumentError when passed addrinfo is not AF_UNIX' do + addrinfo = Addrinfo.tcp('127.0.0.1', 0) + -> { Socket.unpack_sockaddr_un(addrinfo) }.should raise_error(ArgumentError) end end diff --git a/spec/ruby/library/socket/spec_helper.rb b/spec/ruby/library/socket/spec_helper.rb index 1121542dd50848..b33663e02da119 100644 --- a/spec/ruby/library/socket/spec_helper.rb +++ b/spec/ruby/library/socket/spec_helper.rb @@ -2,7 +2,6 @@ require 'socket' MSpec.enable_feature :sock_packet if Socket.const_defined?(:SOCK_PACKET) -MSpec.enable_feature :unix_socket unless PlatformGuard.windows? MSpec.enable_feature :udp_cork if Socket.const_defined?(:UDP_CORK) MSpec.enable_feature :tcp_cork if Socket.const_defined?(:TCP_CORK) MSpec.enable_feature :pktinfo if Socket.const_defined?(:IP_PKTINFO) diff --git a/spec/ruby/library/socket/unixserver/accept_nonblock_spec.rb b/spec/ruby/library/socket/unixserver/accept_nonblock_spec.rb index dba3de7359d258..f67941b296dca1 100644 --- a/spec/ruby/library/socket/unixserver/accept_nonblock_spec.rb +++ b/spec/ruby/library/socket/unixserver/accept_nonblock_spec.rb @@ -1,87 +1,85 @@ require_relative '../spec_helper' require_relative '../fixtures/classes' -with_feature :unix_socket do - describe "UNIXServer#accept_nonblock" do - before :each do - @path = SocketSpecs.socket_path - @server = UNIXServer.open(@path) - @client = UNIXSocket.open(@path) +describe "UNIXServer#accept_nonblock" do + before :each do + @path = SocketSpecs.socket_path + @server = UNIXServer.open(@path) + @client = UNIXSocket.open(@path) - @socket = @server.accept_nonblock - @client.send("foobar", 0) - end + @socket = @server.accept_nonblock + @client.send("foobar", 0) + end - after :each do - @socket.close - @client.close - @server.close - SocketSpecs.rm_socket @path - end + after :each do + @socket.close + @client.close + @server.close + SocketSpecs.rm_socket @path + end - it "accepts a connection in a non-blocking way" do - data = @socket.recvfrom(6).first - data.should == "foobar" - end + it "accepts a connection in a non-blocking way" do + data = @socket.recvfrom(6).first + data.should == "foobar" + end - it "returns a UNIXSocket" do - @socket.should be_kind_of(UNIXSocket) - end + it "returns a UNIXSocket" do + @socket.should be_kind_of(UNIXSocket) + end + + it 'returns :wait_readable in exceptionless mode' do + @server.accept_nonblock(exception: false).should == :wait_readable + end +end - it 'returns :wait_readable in exceptionless mode' do - @server.accept_nonblock(exception: false).should == :wait_readable +describe 'UNIXServer#accept_nonblock' do + before do + @path = SocketSpecs.socket_path + @server = UNIXServer.new(@path) + end + + after do + @server.close + rm_r(@path) + end + + describe 'without a client' do + it 'raises IO::WaitReadable' do + -> { @server.accept_nonblock }.should raise_error(IO::WaitReadable) end end - describe 'UNIXServer#accept_nonblock' do + describe 'with a client' do before do - @path = SocketSpecs.socket_path - @server = UNIXServer.new(@path) + @client = UNIXSocket.new(@path) end after do - @server.close - rm_r(@path) + @client.close + @socket.close if @socket end - describe 'without a client' do - it 'raises IO::WaitReadable' do - -> { @server.accept_nonblock }.should raise_error(IO::WaitReadable) + describe 'without any data' do + it 'returns a UNIXSocket' do + @socket = @server.accept_nonblock + @socket.should be_an_instance_of(UNIXSocket) end end - describe 'with a client' do + describe 'with data available' do before do - @client = UNIXSocket.new(@path) - end - - after do - @client.close - @socket.close if @socket + @client.write('hello') end - describe 'without any data' do - it 'returns a UNIXSocket' do - @socket = @server.accept_nonblock - @socket.should be_an_instance_of(UNIXSocket) - end + it 'returns a UNIXSocket' do + @socket = @server.accept_nonblock + @socket.should be_an_instance_of(UNIXSocket) end - describe 'with data available' do - before do - @client.write('hello') - end - - it 'returns a UNIXSocket' do + describe 'the returned UNIXSocket' do + it 'can read the data written' do @socket = @server.accept_nonblock - @socket.should be_an_instance_of(UNIXSocket) - end - - describe 'the returned UNIXSocket' do - it 'can read the data written' do - @socket = @server.accept_nonblock - @socket.recv(5).should == 'hello' - end + @socket.recv(5).should == 'hello' end end end diff --git a/spec/ruby/library/socket/unixserver/accept_spec.rb b/spec/ruby/library/socket/unixserver/accept_spec.rb index 1305bc6220d380..cc2c922b6fca23 100644 --- a/spec/ruby/library/socket/unixserver/accept_spec.rb +++ b/spec/ruby/library/socket/unixserver/accept_spec.rb @@ -1,126 +1,124 @@ require_relative '../spec_helper' require_relative '../fixtures/classes' -with_feature :unix_socket do - describe "UNIXServer#accept" do - before :each do - @path = SocketSpecs.socket_path - @server = UNIXServer.open(@path) - end +describe "UNIXServer#accept" do + before :each do + @path = SocketSpecs.socket_path + @server = UNIXServer.open(@path) + end - after :each do - @server.close if @server - SocketSpecs.rm_socket @path - end + after :each do + @server.close if @server + SocketSpecs.rm_socket @path + end - it "accepts what is written by the client" do - client = UNIXSocket.open(@path) + it "accepts what is written by the client" do + client = UNIXSocket.open(@path) - client.send('hello', 0) + client.send('hello', 0) - sock = @server.accept - begin - data, info = sock.recvfrom(5) + sock = @server.accept + begin + data, info = sock.recvfrom(5) - data.should == 'hello' - info.should_not be_empty - ensure - sock.close - client.close - end + data.should == 'hello' + info.should_not be_empty + ensure + sock.close + client.close end + end - it "can be interrupted by Thread#kill" do - t = Thread.new { - @server.accept - } - Thread.pass while t.status and t.status != "sleep" - - # kill thread, ensure it dies in a reasonable amount of time - t.kill - a = 0 - while t.alive? and a < 5000 - sleep 0.001 - a += 1 - end - a.should < 5000 + it "can be interrupted by Thread#kill" do + t = Thread.new { + @server.accept + } + Thread.pass while t.status and t.status != "sleep" + + # kill thread, ensure it dies in a reasonable amount of time + t.kill + a = 0 + while t.alive? and a < 5000 + sleep 0.001 + a += 1 end + a.should < 5000 + end - it "can be interrupted by Thread#raise" do - t = Thread.new { - -> { - @server.accept - }.should raise_error(Exception, "interrupted") - } + it "can be interrupted by Thread#raise" do + t = Thread.new { + -> { + @server.accept + }.should raise_error(Exception, "interrupted") + } - Thread.pass while t.status and t.status != "sleep" - t.raise Exception, "interrupted" - t.join - end + Thread.pass while t.status and t.status != "sleep" + t.raise Exception, "interrupted" + t.join end end -with_feature :unix_socket do - describe 'UNIXServer#accept' do +describe 'UNIXServer#accept' do + before do + @path = SocketSpecs.socket_path + @server = UNIXServer.new(@path) + end + + after do + @server.close + rm_r(@path) + end + + describe 'without a client' do + it 'blocks the calling thread' do + -> { @server.accept }.should block_caller + end + end + + describe 'with a client' do before do - @path = SocketSpecs.socket_path - @server = UNIXServer.new(@path) + @client = UNIXSocket.new(@path) end after do - @server.close - rm_r(@path) + @client.close + @socket.close if @socket end - describe 'without a client' do - it 'blocks the calling thread' do - -> { @server.accept }.should block_caller + describe 'without any data' do + it 'returns a UNIXSocket' do + @socket = @server.accept + @socket.should be_an_instance_of(UNIXSocket) end end - describe 'with a client' do + describe 'with data available' do before do - @client = UNIXSocket.new(@path) - end - - after do - @client.close - @socket.close if @socket + @client.write('hello') end - describe 'without any data' do - it 'returns a UNIXSocket' do - @socket = @server.accept - @socket.should be_an_instance_of(UNIXSocket) - end + it 'returns a UNIXSocket' do + @socket = @server.accept + @socket.should be_an_instance_of(UNIXSocket) end - describe 'with data available' do - before do - @client.write('hello') - end - - it 'returns a UNIXSocket' do + describe 'the returned UNIXSocket' do + it 'can read the data written' do @socket = @server.accept - @socket.should be_an_instance_of(UNIXSocket) + @socket.recv(5).should == 'hello' end - describe 'the returned UNIXSocket' do - it 'can read the data written' do - @socket = @server.accept - @socket.recv(5).should == 'hello' - end - + platform_is_not :windows do it "is set to nonblocking" do require 'io/nonblock' @socket = @server.accept @socket.should.nonblock? end + end - it "is set to close on exec" do - @socket = @server.accept - @socket.should.close_on_exec? - end + it "is set to close on exec" do + @socket = @server.accept + @socket.should.close_on_exec? 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 8cc55ef391cc98..be1c2df4d72063 100644 --- a/spec/ruby/library/socket/unixserver/for_fd_spec.rb +++ b/spec/ruby/library/socket/unixserver/for_fd_spec.rb @@ -1,23 +1,21 @@ require_relative '../spec_helper' require_relative '../fixtures/classes' -with_feature :unix_socket do - describe "UNIXServer.for_fd" do - before :each do - @unix_path = SocketSpecs.socket_path - @unix = UNIXServer.new(@unix_path) - end +describe "UNIXServer.for_fd" do + before :each do + @unix_path = SocketSpecs.socket_path + @unix = UNIXServer.new(@unix_path) + end - after :each do - @unix.close if @unix - SocketSpecs.rm_socket @unix_path - end + after :each do + @unix.close if @unix + SocketSpecs.rm_socket @unix_path + end - it "can calculate the path" do - b = UNIXServer.for_fd(@unix.fileno) - b.autoclose = false + it "can calculate the path" do + b = UNIXServer.for_fd(@unix.fileno) + b.autoclose = false - b.path.should == @unix_path - end + b.path.should == @unix_path end end diff --git a/spec/ruby/library/socket/unixserver/initialize_spec.rb b/spec/ruby/library/socket/unixserver/initialize_spec.rb index 0cc49ef1ebc768..3728a307b05c2d 100644 --- a/spec/ruby/library/socket/unixserver/initialize_spec.rb +++ b/spec/ruby/library/socket/unixserver/initialize_spec.rb @@ -1,28 +1,26 @@ require_relative '../spec_helper' require_relative '../fixtures/classes' -with_feature :unix_socket do - describe 'UNIXServer#initialize' do - before do - @path = SocketSpecs.socket_path - @server = UNIXServer.new(@path) - end +describe 'UNIXServer#initialize' do + before do + @path = SocketSpecs.socket_path + @server = UNIXServer.new(@path) + end - after do - @server.close if @server - rm_r @path - end + after do + @server.close if @server + rm_r @path + end - it 'returns a new UNIXServer' do - @server.should be_an_instance_of(UNIXServer) - end + it 'returns a new UNIXServer' do + @server.should be_an_instance_of(UNIXServer) + end - it 'sets the socket to binmode' do - @server.binmode?.should be_true - end + it 'sets the socket to binmode' do + @server.binmode?.should be_true + end - it 'raises Errno::EADDRINUSE when the socket is already in use' do - -> { UNIXServer.new(@path) }.should raise_error(Errno::EADDRINUSE) - end + it 'raises Errno::EADDRINUSE when the socket is already in use' do + -> { UNIXServer.new(@path) }.should raise_error(Errno::EADDRINUSE) end end diff --git a/spec/ruby/library/socket/unixserver/listen_spec.rb b/spec/ruby/library/socket/unixserver/listen_spec.rb index b90b3bbb09f061..7938d648c4016e 100644 --- a/spec/ruby/library/socket/unixserver/listen_spec.rb +++ b/spec/ruby/library/socket/unixserver/listen_spec.rb @@ -1,21 +1,19 @@ require_relative '../spec_helper' require_relative '../fixtures/classes' -with_feature :unix_socket do - describe 'UNIXServer#listen' do - before do - @path = SocketSpecs.socket_path - @server = UNIXServer.new(@path) - end +describe 'UNIXServer#listen' do + before do + @path = SocketSpecs.socket_path + @server = UNIXServer.new(@path) + end - after do - @server.close + after do + @server.close - rm_r(@path) - end + rm_r(@path) + end - it 'returns 0' do - @server.listen(1).should == 0 - end + it 'returns 0' do + @server.listen(1).should == 0 end end diff --git a/spec/ruby/library/socket/unixserver/new_spec.rb b/spec/ruby/library/socket/unixserver/new_spec.rb index a160e3ce5c8050..7d0c7bf76ee194 100644 --- a/spec/ruby/library/socket/unixserver/new_spec.rb +++ b/spec/ruby/library/socket/unixserver/new_spec.rb @@ -1,14 +1,12 @@ require_relative '../spec_helper' require_relative 'shared/new' -with_feature :unix_socket do - describe "UNIXServer.new" do - it_behaves_like :unixserver_new, :new +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 + 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 diff --git a/spec/ruby/library/socket/unixserver/open_spec.rb b/spec/ruby/library/socket/unixserver/open_spec.rb index 16453dd3bd877f..c49df802d067e7 100644 --- a/spec/ruby/library/socket/unixserver/open_spec.rb +++ b/spec/ruby/library/socket/unixserver/open_spec.rb @@ -2,25 +2,23 @@ require_relative '../fixtures/classes' require_relative 'shared/new' -with_feature :unix_socket do - describe "UNIXServer.open" do - it_behaves_like :unixserver_new, :open +describe "UNIXServer.open" do + it_behaves_like :unixserver_new, :open - 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 "yields the new UNIXServer object to the block, if given" do - UNIXServer.open(@path) do |unix| - unix.path.should == @path - unix.addr.should == ["AF_UNIX", @path] - end + it "yields the new UNIXServer object to the block, if given" do + UNIXServer.open(@path) do |unix| + unix.path.should == @path + unix.addr.should == ["AF_UNIX", @path] end end end diff --git a/spec/ruby/library/socket/unixserver/sysaccept_spec.rb b/spec/ruby/library/socket/unixserver/sysaccept_spec.rb index e59731878aa419..c4a4ecc824b618 100644 --- a/spec/ruby/library/socket/unixserver/sysaccept_spec.rb +++ b/spec/ruby/library/socket/unixserver/sysaccept_spec.rb @@ -1,51 +1,49 @@ require_relative '../spec_helper' require_relative '../fixtures/classes' -with_feature :unix_socket do - describe 'UNIXServer#sysaccept' do +describe 'UNIXServer#sysaccept' do + before do + @path = SocketSpecs.socket_path + @server = UNIXServer.new(@path) + end + + after do + @server.close + + rm_r(@path) + end + + describe 'without a client' do + it 'blocks the calling thread' do + -> { @server.sysaccept }.should block_caller + end + end + + describe 'with a client' do before do - @path = SocketSpecs.socket_path - @server = UNIXServer.new(@path) + @client = UNIXSocket.new(@path) end after do - @server.close - - rm_r(@path) + Socket.for_fd(@fd).close if @fd + @client.close end - describe 'without a client' do - it 'blocks the calling thread' do - -> { @server.sysaccept }.should block_caller + describe 'without any data' do + it 'returns an Integer' do + @fd = @server.sysaccept + @fd.should be_kind_of(Integer) end end - describe 'with a client' do + describe 'with data available' do before do - @client = UNIXSocket.new(@path) - end - - after do - Socket.for_fd(@fd).close if @fd - @client.close + @client.write('hello') end - describe 'without any data' do - it 'returns an Integer' do - @fd = @server.sysaccept - @fd.should be_kind_of(Integer) - end - end - - describe 'with data available' do - before do - @client.write('hello') - end - - it 'returns an Integer' do - @fd = @server.sysaccept - @fd.should be_kind_of(Integer) - end + it 'returns an Integer' do + @fd = @server.sysaccept + @fd.should be_kind_of(Integer) end end end diff --git a/spec/ruby/library/socket/unixsocket/addr_spec.rb b/spec/ruby/library/socket/unixsocket/addr_spec.rb index d93e06131236ea..1afe9b12dc4477 100644 --- a/spec/ruby/library/socket/unixsocket/addr_spec.rb +++ b/spec/ruby/library/socket/unixsocket/addr_spec.rb @@ -1,35 +1,33 @@ require_relative '../spec_helper' require_relative '../fixtures/classes' -with_feature :unix_socket do - describe "UNIXSocket#addr" do - before :each do - @path = SocketSpecs.socket_path - @server = UNIXServer.open(@path) - @client = UNIXSocket.open(@path) - end +describe "UNIXSocket#addr" do + before :each do + @path = SocketSpecs.socket_path + @server = UNIXServer.open(@path) + @client = UNIXSocket.open(@path) + end - after :each do - @client.close - @server.close - SocketSpecs.rm_socket @path - end + after :each do + @client.close + @server.close + SocketSpecs.rm_socket @path + end - it "returns an array" do - @client.addr.should be_kind_of(Array) - end + it "returns an array" do + @client.addr.should be_kind_of(Array) + end - it "returns the address family of this socket in an array" do - @client.addr[0].should == "AF_UNIX" - @server.addr[0].should == "AF_UNIX" - end + it "returns the address family of this socket in an array" do + @client.addr[0].should == "AF_UNIX" + @server.addr[0].should == "AF_UNIX" + end - it "returns the path of the socket in an array if it's a server" do - @server.addr[1].should == @path - end + it "returns the path of the socket in an array if it's a server" do + @server.addr[1].should == @path + end - it "returns an empty string for path if it's a client" do - @client.addr[1].should == "" - end + it "returns an empty string for path if it's a client" do + @client.addr[1].should == "" end end diff --git a/spec/ruby/library/socket/unixsocket/initialize_spec.rb b/spec/ruby/library/socket/unixsocket/initialize_spec.rb index bf7896ab0eb590..5dccfcc7456d24 100644 --- a/spec/ruby/library/socket/unixsocket/initialize_spec.rb +++ b/spec/ruby/library/socket/unixsocket/initialize_spec.rb @@ -1,48 +1,56 @@ require_relative '../spec_helper' require_relative '../fixtures/classes' -with_feature :unix_socket do - describe 'UNIXSocket#initialize' do - describe 'using a non existing path' do +describe 'UNIXSocket#initialize' do + describe 'using a non existing path' do + platform_is_not :windows do it 'raises Errno::ENOENT' do -> { UNIXSocket.new(SocketSpecs.socket_path) }.should raise_error(Errno::ENOENT) end end - describe 'using an existing socket path' do - before do - @path = SocketSpecs.socket_path - @server = UNIXServer.new(@path) - @socket = UNIXSocket.new(@path) + platform_is :windows do + # Why, Windows, why? + it 'raises Errno::ECONNREFUSED' do + -> { UNIXSocket.new(SocketSpecs.socket_path) }.should raise_error(Errno::ECONNREFUSED) end + end + end - after do - @socket.close - @server.close - rm_r(@path) - end + describe 'using an existing socket path' do + before do + @path = SocketSpecs.socket_path + @server = UNIXServer.new(@path) + @socket = UNIXSocket.new(@path) + end - it 'returns a new UNIXSocket' do - @socket.should be_an_instance_of(UNIXSocket) - end + after do + @socket.close + @server.close + rm_r(@path) + end - it 'sets the socket path to an empty String' do - @socket.path.should == '' - end + it 'returns a new UNIXSocket' do + @socket.should be_an_instance_of(UNIXSocket) + end - it 'sets the socket to binmode' do - @socket.binmode?.should be_true - end + it 'sets the socket path to an empty String' do + @socket.path.should == '' + end + + it 'sets the socket to binmode' do + @socket.binmode?.should be_true + end + platform_is_not :windows do it 'sets the socket to nonblock' do require 'io/nonblock' @socket.should.nonblock? end + end - it 'sets the socket to close on exec' do - @socket.should.close_on_exec? - end - + it 'sets the socket to close on exec' do + @socket.should.close_on_exec? end end end diff --git a/spec/ruby/library/socket/unixsocket/inspect_spec.rb b/spec/ruby/library/socket/unixsocket/inspect_spec.rb index a542ba6db540f1..77bb521069c19d 100644 --- a/spec/ruby/library/socket/unixsocket/inspect_spec.rb +++ b/spec/ruby/library/socket/unixsocket/inspect_spec.rb @@ -1,17 +1,15 @@ require_relative '../spec_helper' require_relative '../fixtures/classes' -with_feature :unix_socket do - describe "UNIXSocket#inspect" do - it "returns sockets fd for unnamed sockets" do - begin - s1, s2 = UNIXSocket.socketpair - s1.inspect.should == "#" - s2.inspect.should == "#" - ensure - s1.close - s2.close - end +describe "UNIXSocket#inspect" do + it "returns sockets fd for unnamed sockets" do + begin + s1, s2 = UNIXSocket.socketpair + s1.inspect.should == "#" + s2.inspect.should == "#" + ensure + s1.close + s2.close end end end diff --git a/spec/ruby/library/socket/unixsocket/local_address_spec.rb b/spec/ruby/library/socket/unixsocket/local_address_spec.rb index 734253e7f5ccbd..0fdec3829305ad 100644 --- a/spec/ruby/library/socket/unixsocket/local_address_spec.rb +++ b/spec/ruby/library/socket/unixsocket/local_address_spec.rb @@ -1,94 +1,92 @@ require_relative '../spec_helper' require_relative '../fixtures/classes' -with_feature :unix_socket do - describe 'UNIXSocket#local_address' do - before do - @path = SocketSpecs.socket_path - @server = UNIXServer.new(@path) - @client = UNIXSocket.new(@path) - end +describe 'UNIXSocket#local_address' do + before do + @path = SocketSpecs.socket_path + @server = UNIXServer.new(@path) + @client = UNIXSocket.new(@path) + end - after do - @client.close - @server.close + after do + @client.close + @server.close - rm_r(@path) - end - - it 'returns an Addrinfo' do - @client.local_address.should be_an_instance_of(Addrinfo) - end + rm_r(@path) + end - describe 'the returned Addrinfo' do - platform_is_not :aix do - it 'uses AF_UNIX as the address family' do - @client.local_address.afamily.should == Socket::AF_UNIX - end + it 'returns an Addrinfo' do + @client.local_address.should be_an_instance_of(Addrinfo) + end - it 'uses PF_UNIX as the protocol family' do - @client.local_address.pfamily.should == Socket::PF_UNIX - end + describe 'the returned Addrinfo' do + platform_is_not :aix do + it 'uses AF_UNIX as the address family' do + @client.local_address.afamily.should == Socket::AF_UNIX end - it 'uses SOCK_STREAM as the socket type' do - @client.local_address.socktype.should == Socket::SOCK_STREAM + it 'uses PF_UNIX as the protocol family' do + @client.local_address.pfamily.should == Socket::PF_UNIX end + end - platform_is_not :aix do - it 'uses an empty socket path' do - @client.local_address.unix_path.should == '' - end - end + it 'uses SOCK_STREAM as the socket type' do + @client.local_address.socktype.should == Socket::SOCK_STREAM + end - it 'uses 0 as the protocol' do - @client.local_address.protocol.should == 0 + platform_is_not :aix do + it 'uses an empty socket path' do + @client.local_address.unix_path.should == '' end end - end - describe 'UNIXSocket#local_address with a UNIX socket pair' do - before :each do - @sock, @sock2 = Socket.pair(Socket::AF_UNIX, Socket::SOCK_STREAM) + it 'uses 0 as the protocol' do + @client.local_address.protocol.should == 0 end + end +end - after :each do - @sock.close - @sock2.close - end +describe 'UNIXSocket#local_address with a UNIX socket pair' do + before :each do + @sock, @sock2 = Socket.pair(Socket::AF_UNIX, Socket::SOCK_STREAM) + end - it 'returns an Addrinfo' do - @sock.local_address.should be_an_instance_of(Addrinfo) - end + after :each do + @sock.close + @sock2.close + end - describe 'the returned Addrinfo' do - it 'uses AF_UNIX as the address family' do - @sock.local_address.afamily.should == Socket::AF_UNIX - end + it 'returns an Addrinfo' do + @sock.local_address.should be_an_instance_of(Addrinfo) + end - it 'uses PF_UNIX as the protocol family' do - @sock.local_address.pfamily.should == Socket::PF_UNIX - end + describe 'the returned Addrinfo' do + it 'uses AF_UNIX as the address family' do + @sock.local_address.afamily.should == Socket::AF_UNIX + end - it 'uses SOCK_STREAM as the socket type' do - @sock.local_address.socktype.should == Socket::SOCK_STREAM - end + it 'uses PF_UNIX as the protocol family' do + @sock.local_address.pfamily.should == Socket::PF_UNIX + end - it 'raises SocketError for #ip_address' do - -> { - @sock.local_address.ip_address - }.should raise_error(SocketError, "need IPv4 or IPv6 address") - end + it 'uses SOCK_STREAM as the socket type' do + @sock.local_address.socktype.should == Socket::SOCK_STREAM + end - it 'raises SocketError for #ip_port' do - -> { - @sock.local_address.ip_port - }.should raise_error(SocketError, "need IPv4 or IPv6 address") - end + it 'raises SocketError for #ip_address' do + -> { + @sock.local_address.ip_address + }.should raise_error(SocketError, "need IPv4 or IPv6 address") + end - it 'uses 0 as the protocol' do - @sock.local_address.protocol.should == 0 - end + it 'raises SocketError for #ip_port' do + -> { + @sock.local_address.ip_port + }.should raise_error(SocketError, "need IPv4 or IPv6 address") + end + + it 'uses 0 as the protocol' do + @sock.local_address.protocol.should == 0 end end end diff --git a/spec/ruby/library/socket/unixsocket/new_spec.rb b/spec/ruby/library/socket/unixsocket/new_spec.rb index 6d8ea6dcfe6c3a..fea2c1e2b79a10 100644 --- a/spec/ruby/library/socket/unixsocket/new_spec.rb +++ b/spec/ruby/library/socket/unixsocket/new_spec.rb @@ -1,14 +1,12 @@ require_relative '../spec_helper' require_relative 'shared/new' -with_feature :unix_socket do - describe "UNIXSocket.new" do - it_behaves_like :unixsocket_new, :new +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 + 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 diff --git a/spec/ruby/library/socket/unixsocket/open_spec.rb b/spec/ruby/library/socket/unixsocket/open_spec.rb index 61def30abbb7ad..b5e8c6c23a45be 100644 --- a/spec/ruby/library/socket/unixsocket/open_spec.rb +++ b/spec/ruby/library/socket/unixsocket/open_spec.rb @@ -2,27 +2,25 @@ require_relative '../fixtures/classes' require_relative 'shared/new' -with_feature :unix_socket do - describe "UNIXSocket.open" do - it_behaves_like :unixsocket_new, :open - end +describe "UNIXSocket.open" do + it_behaves_like :unixsocket_new, :open +end - describe "UNIXSocket.open" do - before :each do - @path = SocketSpecs.socket_path - @server = UNIXServer.open(@path) - end +describe "UNIXSocket.open" do + before :each do + @path = SocketSpecs.socket_path + @server = UNIXServer.open(@path) + end - after :each do - @server.close - SocketSpecs.rm_socket @path - end + after :each do + @server.close + SocketSpecs.rm_socket @path + end - it "opens a unix socket on the specified file and yields it to the block" do - UNIXSocket.open(@path) do |client| - client.addr[0].should == "AF_UNIX" - client.should_not.closed? - end + it "opens a unix socket on the specified file and yields it to the block" do + UNIXSocket.open(@path) do |client| + client.addr[0].should == "AF_UNIX" + client.should_not.closed? end end end diff --git a/spec/ruby/library/socket/unixsocket/pair_spec.rb b/spec/ruby/library/socket/unixsocket/pair_spec.rb index b0a3b2af99da64..9690142668e498 100644 --- a/spec/ruby/library/socket/unixsocket/pair_spec.rb +++ b/spec/ruby/library/socket/unixsocket/pair_spec.rb @@ -3,18 +3,16 @@ require_relative '../shared/partially_closable_sockets' require_relative 'shared/pair' -with_feature :unix_socket do - describe "UNIXSocket.pair" do - it_should_behave_like :unixsocket_pair - it_should_behave_like :partially_closable_sockets +describe "UNIXSocket.pair" do + it_should_behave_like :unixsocket_pair + it_should_behave_like :partially_closable_sockets - before :each do - @s1, @s2 = UNIXSocket.pair - end + before :each do + @s1, @s2 = UNIXSocket.pair + end - after :each do - @s1.close - @s2.close - end + after :each do + @s1.close + @s2.close end end diff --git a/spec/ruby/library/socket/unixsocket/partially_closable_spec.rb b/spec/ruby/library/socket/unixsocket/partially_closable_spec.rb index ef7d0f0b2aad5e..108a6c30637219 100644 --- a/spec/ruby/library/socket/unixsocket/partially_closable_spec.rb +++ b/spec/ruby/library/socket/unixsocket/partially_closable_spec.rb @@ -2,22 +2,20 @@ require_relative '../fixtures/classes' require_relative '../shared/partially_closable_sockets' -with_feature :unix_socket do - describe "UNIXSocket partial closability" do - before :each do - @path = SocketSpecs.socket_path - @server = UNIXServer.open(@path) - @s1 = UNIXSocket.new(@path) - @s2 = @server.accept - end - - after :each do - @server.close - @s1.close - @s2.close - SocketSpecs.rm_socket @path - end +describe "UNIXSocket partial closability" do + before :each do + @path = SocketSpecs.socket_path + @server = UNIXServer.open(@path) + @s1 = UNIXSocket.new(@path) + @s2 = @server.accept + end - it_should_behave_like :partially_closable_sockets + after :each do + @server.close + @s1.close + @s2.close + SocketSpecs.rm_socket @path end + + it_should_behave_like :partially_closable_sockets end diff --git a/spec/ruby/library/socket/unixsocket/path_spec.rb b/spec/ruby/library/socket/unixsocket/path_spec.rb index a608378e4f97a6..ffe7e4bea2cb03 100644 --- a/spec/ruby/library/socket/unixsocket/path_spec.rb +++ b/spec/ruby/library/socket/unixsocket/path_spec.rb @@ -1,26 +1,24 @@ require_relative '../spec_helper' require_relative '../fixtures/classes' -with_feature :unix_socket do - describe "UNIXSocket#path" do - before :each do - @path = SocketSpecs.socket_path - @server = UNIXServer.open(@path) - @client = UNIXSocket.open(@path) - end +describe "UNIXSocket#path" do + before :each do + @path = SocketSpecs.socket_path + @server = UNIXServer.open(@path) + @client = UNIXSocket.open(@path) + end - after :each do - @client.close - @server.close - SocketSpecs.rm_socket @path - end + after :each do + @client.close + @server.close + SocketSpecs.rm_socket @path + end - it "returns the path of the socket if it's a server" do - @server.path.should == @path - end + it "returns the path of the socket if it's a server" do + @server.path.should == @path + end - it "returns an empty string for path if it's a client" do - @client.path.should == "" - end + it "returns an empty string for path if it's a client" do + @client.path.should == "" end end diff --git a/spec/ruby/library/socket/unixsocket/peeraddr_spec.rb b/spec/ruby/library/socket/unixsocket/peeraddr_spec.rb index 72bc96b1fe978f..10cab13b422a73 100644 --- a/spec/ruby/library/socket/unixsocket/peeraddr_spec.rb +++ b/spec/ruby/library/socket/unixsocket/peeraddr_spec.rb @@ -1,28 +1,26 @@ require_relative '../spec_helper' require_relative '../fixtures/classes' -with_feature :unix_socket do - describe "UNIXSocket#peeraddr" do - before :each do - @path = SocketSpecs.socket_path - @server = UNIXServer.open(@path) - @client = UNIXSocket.open(@path) - end +describe "UNIXSocket#peeraddr" do + before :each do + @path = SocketSpecs.socket_path + @server = UNIXServer.open(@path) + @client = UNIXSocket.open(@path) + end - after :each do - @client.close - @server.close - SocketSpecs.rm_socket @path - end + after :each do + @client.close + @server.close + SocketSpecs.rm_socket @path + end - it "returns the address family and path of the server end of the connection" do - @client.peeraddr.should == ["AF_UNIX", @path] - end + it "returns the address family and path of the server end of the connection" do + @client.peeraddr.should == ["AF_UNIX", @path] + end - it "raises an error in server sockets" do - -> { - @server.peeraddr - }.should raise_error(Errno::ENOTCONN) - end + it "raises an error in server sockets" do + -> { + @server.peeraddr + }.should raise_error(Errno::ENOTCONN) 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 1dbc4538e379e6..f0b408f30945fd 100644 --- a/spec/ruby/library/socket/unixsocket/recv_io_spec.rb +++ b/spec/ruby/library/socket/unixsocket/recv_io_spec.rb @@ -1,7 +1,7 @@ require_relative '../spec_helper' require_relative '../fixtures/classes' -with_feature :unix_socket do +platform_is_not :windows do describe "UNIXSocket#recv_io" do before :each do @path = SocketSpecs.socket_path diff --git a/spec/ruby/library/socket/unixsocket/recvfrom_spec.rb b/spec/ruby/library/socket/unixsocket/recvfrom_spec.rb index d849fdc302646b..9bb18047c49a80 100644 --- a/spec/ruby/library/socket/unixsocket/recvfrom_spec.rb +++ b/spec/ruby/library/socket/unixsocket/recvfrom_spec.rb @@ -1,59 +1,105 @@ require_relative '../spec_helper' require_relative '../fixtures/classes' -with_feature :unix_socket do - describe "UNIXSocket#recvfrom" do - before :each do - @path = SocketSpecs.socket_path - @server = UNIXServer.open(@path) - @client = UNIXSocket.open(@path) +describe "UNIXSocket#recvfrom" do + before :each do + @path = SocketSpecs.socket_path + @server = UNIXServer.open(@path) + @client = UNIXSocket.open(@path) + end + + after :each do + @client.close + @server.close + SocketSpecs.rm_socket @path + end + + it "receives len bytes from sock, returning an array containing sent data as first element" do + @client.send("foobar", 0) + sock = @server.accept + sock.recvfrom(6).first.should == "foobar" + sock.close + end + + context "when called on a server's socket" do + platform_is_not :windows do + it "returns an array containing basic information on the client as second element" do + @client.send("foobar", 0) + sock = @server.accept + data = sock.recvfrom(6) + data.last.should == ["AF_UNIX", ""] + sock.close + end end - after :each do - @client.close - @server.close - SocketSpecs.rm_socket @path + guard -> { platform_is :windows and ruby_bug "#21702", ""..."4.1" } do + it "returns an array containing basic information on the client as second element" do + @client.send("foobar", 0) + sock = @server.accept + data = sock.recvfrom(6) + data.last.should == ["AF_UNIX", ""] + sock.close + end end + end - it "receives len bytes from sock" do - @client.send("foobar", 0) - sock = @server.accept - sock.recvfrom(6).first.should == "foobar" - sock.close + context "when called on a client's socket" do + platform_is_not :windows, :darwin do + it "returns an array containing server's address as second element" do + @client.send("", 0) + sock = @server.accept + sock.send("barfoo", 0) + @client.recvfrom(6).last.should == ["AF_UNIX", @server.local_address.unix_path] + sock.close + end end - it "returns an array with data and information on the sender" do - @client.send("foobar", 0) - sock = @server.accept - data = sock.recvfrom(6) - data.first.should == "foobar" - data.last.should == ["AF_UNIX", ""] - sock.close + guard -> { platform_is :windows and ruby_bug "#21702", ""..."4.1" } do + it "returns an array containing server's address as second element" do + @client.send("", 0) + sock = @server.accept + sock.send("barfoo", 0) + # This may not be correct, depends on what underlying recvfrom actually returns. + @client.recvfrom(6).last.should == ["AF_UNIX", @server.local_address.unix_path] + sock.close + end end - it "allows an output buffer as third argument" do - buffer = +'' + platform_is :darwin do + it "returns an array containing basic information on the server as second element" do + @client.send("", 0) + sock = @server.accept + sock.send("barfoo", 0) + @client.recvfrom(6).last.should == ["AF_UNIX", ""] + sock.close + end + end + end - @client.send("foobar", 0) - sock = @server.accept - message, = sock.recvfrom(6, 0, buffer) - sock.close + it "allows an output buffer as third argument" do + buffer = +'' - message.should.equal?(buffer) - buffer.should == "foobar" - end + @client.send("foobar", 0) + sock = @server.accept + message, = sock.recvfrom(6, 0, buffer) + sock.close - it "preserves the encoding of the given buffer" do - buffer = ''.encode(Encoding::ISO_8859_1) + message.should.equal?(buffer) + buffer.should == "foobar" + end - @client.send("foobar", 0) - sock = @server.accept - sock.recvfrom(6, 0, buffer) - sock.close + it "preserves the encoding of the given buffer" do + buffer = ''.encode(Encoding::ISO_8859_1) - buffer.encoding.should == Encoding::ISO_8859_1 - end + @client.send("foobar", 0) + sock = @server.accept + sock.recvfrom(6, 0, buffer) + sock.close + buffer.encoding.should == Encoding::ISO_8859_1 + end + + platform_is_not :windows do it "uses different message options" do @client.send("foobar", Socket::MSG_PEEK) sock = @server.accept @@ -65,24 +111,34 @@ sock.close end end +end - describe 'UNIXSocket#recvfrom' do - describe 'using a socket pair' do - before do - @client, @server = UNIXSocket.socketpair - @client.write('hello') - end +describe 'UNIXSocket#recvfrom' do + describe 'using a socket pair' do + before do + @client, @server = UNIXSocket.socketpair + @client.write('hello') + end - after do - @client.close - @server.close + after do + @client.close + @server.close + end + + platform_is_not :windows do + it 'returns an Array containing the data and address information' do + @server.recvfrom(5).should == ['hello', ['AF_UNIX', '']] end + end + guard -> { platform_is :windows and ruby_bug "#21702", ""..."4.1" } do it 'returns an Array containing the data and address information' do @server.recvfrom(5).should == ['hello', ['AF_UNIX', '']] end end + end + platform_is_not :windows do # These specs are taken from the rdoc examples on UNIXSocket#recvfrom. describe 'using a UNIX socket constructed using UNIXSocket.for_fd' do before do diff --git a/spec/ruby/library/socket/unixsocket/remote_address_spec.rb b/spec/ruby/library/socket/unixsocket/remote_address_spec.rb index 0b416254d06bae..84bdff0a6a7dc5 100644 --- a/spec/ruby/library/socket/unixsocket/remote_address_spec.rb +++ b/spec/ruby/library/socket/unixsocket/remote_address_spec.rb @@ -1,45 +1,43 @@ require_relative '../spec_helper' require_relative '../fixtures/classes' -with_feature :unix_socket do - describe 'UNIXSocket#remote_address' do - before do - @path = SocketSpecs.socket_path - @server = UNIXServer.new(@path) - @client = UNIXSocket.new(@path) - end +describe 'UNIXSocket#remote_address' do + before do + @path = SocketSpecs.socket_path + @server = UNIXServer.new(@path) + @client = UNIXSocket.new(@path) + end - after do - @client.close - @server.close + after do + @client.close + @server.close - rm_r(@path) - end + rm_r(@path) + end - it 'returns an Addrinfo' do - @client.remote_address.should be_an_instance_of(Addrinfo) - end + it 'returns an Addrinfo' do + @client.remote_address.should be_an_instance_of(Addrinfo) + end - describe 'the returned Addrinfo' do - it 'uses AF_UNIX as the address family' do - @client.remote_address.afamily.should == Socket::AF_UNIX - end + describe 'the returned Addrinfo' do + it 'uses AF_UNIX as the address family' do + @client.remote_address.afamily.should == Socket::AF_UNIX + end - it 'uses PF_UNIX as the protocol family' do - @client.remote_address.pfamily.should == Socket::PF_UNIX - end + it 'uses PF_UNIX as the protocol family' do + @client.remote_address.pfamily.should == Socket::PF_UNIX + end - it 'uses SOCK_STREAM as the socket type' do - @client.remote_address.socktype.should == Socket::SOCK_STREAM - end + it 'uses SOCK_STREAM as the socket type' do + @client.remote_address.socktype.should == Socket::SOCK_STREAM + end - it 'uses the correct socket path' do - @client.remote_address.unix_path.should == @path - end + it 'uses the correct socket path' do + @client.remote_address.unix_path.should == @path + end - it 'uses 0 as the protocol' do - @client.remote_address.protocol.should == 0 - end + it 'uses 0 as the protocol' do + @client.remote_address.protocol.should == 0 end end end diff --git a/spec/ruby/library/socket/unixsocket/send_io_spec.rb b/spec/ruby/library/socket/unixsocket/send_io_spec.rb index 80f3550c6d323e..52186ec3cf60f1 100644 --- a/spec/ruby/library/socket/unixsocket/send_io_spec.rb +++ b/spec/ruby/library/socket/unixsocket/send_io_spec.rb @@ -1,7 +1,7 @@ require_relative '../spec_helper' require_relative '../fixtures/classes' -with_feature :unix_socket do +platform_is_not :windows do describe "UNIXSocket#send_io" do before :each do @path = SocketSpecs.socket_path diff --git a/spec/ruby/library/socket/unixsocket/shared/pair.rb b/spec/ruby/library/socket/unixsocket/shared/pair.rb index ade7fc9852388d..0f1af43b251323 100644 --- a/spec/ruby/library/socket/unixsocket/shared/pair.rb +++ b/spec/ruby/library/socket/unixsocket/shared/pair.rb @@ -12,18 +12,37 @@ @s2.gets.should == "foo\n" end - it "sets the socket paths to empty Strings" do - @s1.path.should == "" - @s2.path.should == "" - end + platform_is_not :windows do + it "sets the socket paths to empty Strings" do + @s1.path.should == "" + @s2.path.should == "" + end + + it "sets the socket addresses to empty Strings" do + @s1.addr.should == ["AF_UNIX", ""] + @s2.addr.should == ["AF_UNIX", ""] + end - it "sets the socket addresses to empty Strings" do - @s1.addr.should == ["AF_UNIX", ""] - @s2.addr.should == ["AF_UNIX", ""] + it "sets the socket peer addresses to empty Strings" do + @s1.peeraddr.should == ["AF_UNIX", ""] + @s2.peeraddr.should == ["AF_UNIX", ""] + end end - it "sets the socket peer addresses to empty Strings" do - @s1.peeraddr.should == ["AF_UNIX", ""] - @s2.peeraddr.should == ["AF_UNIX", ""] + platform_is :windows do + it "emulates unnamed sockets with a temporary file with a path" do + @s1.path.match?(/\\AppData\\Local\\Temp\\\d+-\d+\.\(\$\)\z/).should be_true + @s1.addr.should == ["AF_UNIX", @s1.path] + @s2.peeraddr.should == ["AF_UNIX", @s1.path] + end + + it "sets the peer address of first socket to an empty string" do + @s1.peeraddr.should == ["AF_UNIX", ""] + end + + it "sets the address and path of second socket to an empty string" do + @s2.addr.should == ["AF_UNIX", ""] + @s2.path.should == "" + end end end diff --git a/spec/ruby/library/socket/unixsocket/socketpair_spec.rb b/spec/ruby/library/socket/unixsocket/socketpair_spec.rb index 5f34008df3e942..c61fc00be4cce7 100644 --- a/spec/ruby/library/socket/unixsocket/socketpair_spec.rb +++ b/spec/ruby/library/socket/unixsocket/socketpair_spec.rb @@ -3,18 +3,16 @@ require_relative '../shared/partially_closable_sockets' require_relative 'shared/pair' -with_feature :unix_socket do - describe "UNIXSocket.socketpair" do - it_should_behave_like :unixsocket_pair - it_should_behave_like :partially_closable_sockets +describe "UNIXSocket.socketpair" do + it_should_behave_like :unixsocket_pair + it_should_behave_like :partially_closable_sockets - before :each do - @s1, @s2 = UNIXSocket.socketpair - end + before :each do + @s1, @s2 = UNIXSocket.socketpair + end - after :each do - @s1.close - @s2.close - end + after :each do + @s1.close + @s2.close end end diff --git a/spec/ruby/library/stringio/readpartial_spec.rb b/spec/ruby/library/stringio/readpartial_spec.rb index 988c552235d5e6..dadefb783732a1 100644 --- a/spec/ruby/library/stringio/readpartial_spec.rb +++ b/spec/ruby/library/stringio/readpartial_spec.rb @@ -24,6 +24,14 @@ @string.readpartial(3).should == ", l" end + it "reads after ungetc with multibyte characters in the buffer" do + @string = StringIO.new(+"∂φ/∂x = gaîté") + c = @string.getc + @string.ungetc(c) + @string.readpartial(3).should == "\xE2\x88\x82".b + @string.readpartial(3).should == "\xCF\x86/".b + end + it "reads after ungetc without data in the buffer" do @string = StringIO.new @string.write("f").should == 1 diff --git a/spec/ruby/optional/thread_safety/fixtures/classes.rb b/spec/ruby/optional/thread_safety/fixtures/classes.rb new file mode 100644 index 00000000000000..4f0ad030e5c688 --- /dev/null +++ b/spec/ruby/optional/thread_safety/fixtures/classes.rb @@ -0,0 +1,39 @@ +module ThreadSafetySpecs + # Returns the number of processors, rounded up so it's always a multiple of 2 + def self.processors + require 'etc' + n = Etc.nprocessors + raise "expected at least 1 processor" if n < 1 + n += 1 if n.odd? # ensure it's a multiple of 2 + n + end + + class Counter + def initialize + @value = 0 + @mutex = Mutex.new + end + + def get + @mutex.synchronize { @value } + end + + def increment + @mutex.synchronize do + @value += 1 + end + end + end + + class Barrier + def initialize(parties) + @parties = parties + @counter = Counter.new + end + + def wait + @counter.increment + Thread.pass until @counter.get == @parties + end + end +end diff --git a/spec/ruby/optional/thread_safety/hash_spec.rb b/spec/ruby/optional/thread_safety/hash_spec.rb new file mode 100644 index 00000000000000..53127fc97342b2 --- /dev/null +++ b/spec/ruby/optional/thread_safety/hash_spec.rb @@ -0,0 +1,210 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +describe "Hash thread safety" do + it "supports concurrent #[]=" do + n_threads = ThreadSafetySpecs.processors + + n = 1_000 + operations = n * n_threads + + h = {} + barrier = ThreadSafetySpecs::Barrier.new(n_threads + 1) + + threads = n_threads.times.map { |t| + Thread.new { + barrier.wait + base = t * n + n.times do |j| + h[base+j] = t + end + } + } + + barrier.wait + threads.each(&:join) + + h.size.should == operations + h.each_pair { |key, value| + (key / n).should == value + } + end + + # can't add a new key into hash during iteration (RuntimeError) on CRuby. + # Yet it's good to test this for implementations that support it. + guard_not -> { PlatformGuard.standard? } do + it "supports concurrent #[]= and #delete and iteration" do + n_threads = ThreadSafetySpecs.processors + + n = 1_000 + operations = n * n_threads / 2 + + h = {} + barrier1 = ThreadSafetySpecs::Barrier.new(n_threads + 2) + barrier2 = ThreadSafetySpecs::Barrier.new(n_threads + 1) + + threads = n_threads.times.map { |t| + Thread.new { + barrier1.wait + base = t * n + n.times do |j| + h[base+j] = t + end + + barrier2.wait + n.times do |j| + # delete only even keys + h.delete(base+j).should == t if (base+j).even? + end + } + } + + read = true + reader = Thread.new { + barrier1.wait + while read + h.each_pair { |k,v| + k.should.is_a?(Integer) + v.should.is_a?(Integer) + (k / n).should == v + } + end + } + + barrier1.wait + barrier2.wait + threads.each(&:join) + read = false + reader.join + + # odd keys are left + h.size.should == operations + h.each_pair { |key, value| + key.should.odd? + (key / n).should == value + } + end + end + + it "supports concurrent #[]= and #[]" do + n_threads = ThreadSafetySpecs.processors + + n = 1_000 + operations = n * n_threads / 2 + + h = {} + barrier = ThreadSafetySpecs::Barrier.new(n_threads + 1) + + threads = n_threads.times.map { |t| + Thread.new { + barrier.wait + base = (t / 2) * n + + if t.even? + n.times do |j| + k = base + j + h[k] = k + end + else + n.times do |j| + k = base + j + Thread.pass until v = h[k] + v.should == k + end + end + } + } + + barrier.wait + threads.each(&:join) + + h.size.should == operations + h.each_pair { |key, value| + key.should == value + } + end + + it "supports concurrent #[]= and #[] with change to #compare_by_identity in the middle" do + n_threads = ThreadSafetySpecs.processors + + n = 1_000 + operations = n * n_threads / 2 + + h = {} + barrier = ThreadSafetySpecs::Barrier.new(n_threads + 1) + + threads = n_threads.times.map { |t| + Thread.new { + barrier.wait + base = (t / 2) * n + + if t.even? + n.times do |j| + k = base + j + h[k] = k + end + else + n.times do |j| + k = base + j + Thread.pass until v = h[k] + v.should == k + end + end + } + } + + changer = Thread.new { + Thread.pass until h.size >= operations / 2 + h.should_not.compare_by_identity? + h.compare_by_identity + h.should.compare_by_identity? + } + + barrier.wait + threads.each(&:join) + changer.join + + h.size.should == operations + h.each_pair { |key, value| + key.should == value + } + end + + it "supports repeated concurrent #[]= and #delete and always returns a #size >= 0" do + n_threads = ThreadSafetySpecs.processors + + n = 1_000 + operations = n * n_threads / 2 + + h = {} + barrier = ThreadSafetySpecs::Barrier.new(n_threads + 1) + deleted = ThreadSafetySpecs::Counter.new + + threads = n_threads.times.map { |t| + Thread.new { + barrier.wait + key = t / 2 + + if t.even? + n.times { + Thread.pass until h.delete(key) + h.size.should >= 0 + deleted.increment + } + else + n.times { + h[key] = key + Thread.pass while h.key?(key) + } + end + } + } + + barrier.wait + threads.each(&:join) + + deleted.get.should == operations + h.size.should == 0 + h.should.empty? + end +end diff --git a/spec/ruby/shared/file/socket.rb b/spec/ruby/shared/file/socket.rb index 55a1cfd284a743..ef6c482d1cf297 100644 --- a/spec/ruby/shared/file/socket.rb +++ b/spec/ruby/shared/file/socket.rb @@ -1,3 +1,33 @@ describe :file_socket, shared: true do - it "accepts an object that has a #to_path method" + it "returns false if the file is not a socket" do + filename = tmp("i_exist") + touch(filename) + + @object.send(@method, filename).should == false + + rm_r filename + end + + it "returns true if the file is a socket" do + require 'socket' + + # We need a really short name here. + # On Linux the path length is limited to 107, see unix(7). + name = tmp("s") + server = UNIXServer.new(name) + + @object.send(@method, name).should == true + + server.close + rm_r name + end + + it "accepts an object that has a #to_path method" do + obj = Object.new + def obj.to_path + __FILE__ + end + + @object.send(@method, obj).should == false + end end From 6939f03f4cec6c50cbc1d214a38cdcdcf1d3f705 Mon Sep 17 00:00:00 2001 From: Peter Zhu Date: Tue, 30 Dec 2025 16:03:35 -0500 Subject: [PATCH 2/8] Add field handle_weak_references to TypedData This commit adds a field handle_weak_references to rb_data_type_struct for the callback when handling weak references. This avoids TypedData objects from needing to expose their rb_data_type_struct and weak references function. --- cont.c | 41 ++++++------ gc.c | 29 ++------- include/ruby/internal/core/rtypeddata.h | 6 +- weakmap.c | 84 ++++++++++++------------- 4 files changed, 70 insertions(+), 90 deletions(-) diff --git a/cont.c b/cont.c index 463be7400f174c..8af093a3163479 100644 --- a/cont.c +++ b/cont.c @@ -48,8 +48,8 @@ static const int DEBUG = 0; #define RB_PAGE_MASK (~(RB_PAGE_SIZE - 1)) static long pagesize; -const rb_data_type_t rb_cont_data_type; -const rb_data_type_t rb_fiber_data_type; +static const rb_data_type_t rb_cont_data_type; +static const rb_data_type_t rb_fiber_data_type; static VALUE rb_cContinuation; static VALUE rb_cFiber; static VALUE rb_eFiberError; @@ -1239,17 +1239,11 @@ cont_save_machine_stack(rb_thread_t *th, rb_context_t *cont) asan_unpoison_memory_region(cont->machine.stack_src, size, false); MEMCPY(cont->machine.stack, cont->machine.stack_src, VALUE, size); } -const rb_data_type_t rb_cont_data_type = { - "continuation", - {cont_mark, cont_free, cont_memsize, cont_compact}, - 0, 0, RUBY_TYPED_FREE_IMMEDIATELY -}; -void -rb_cont_handle_weak_references(VALUE obj) +static void +cont_handle_weak_references(void *ptr) { - rb_context_t *cont; - TypedData_Get_Struct(obj, rb_context_t, &rb_cont_data_type, cont); + rb_context_t *cont = ptr; if (!cont) return; @@ -1260,6 +1254,12 @@ rb_cont_handle_weak_references(VALUE obj) } } +static const rb_data_type_t rb_cont_data_type = { + "continuation", + {cont_mark, cont_free, cont_memsize, cont_compact, cont_handle_weak_references}, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY +}; + static inline void cont_save_thread(rb_context_t *cont, rb_thread_t *th) { @@ -1996,17 +1996,10 @@ rb_cont_call(int argc, VALUE *argv, VALUE contval) * */ -const rb_data_type_t rb_fiber_data_type = { - "fiber", - {fiber_mark, fiber_free, fiber_memsize, fiber_compact,}, - 0, 0, RUBY_TYPED_FREE_IMMEDIATELY -}; - -void -rb_fiber_handle_weak_references(VALUE obj) +static void +fiber_handle_weak_references(void *ptr) { - rb_fiber_t *fiber; - TypedData_Get_Struct(obj, rb_fiber_t, &rb_fiber_data_type, fiber); + rb_fiber_t *fiber = ptr; if (!fiber) return; @@ -2017,6 +2010,12 @@ rb_fiber_handle_weak_references(VALUE obj) } } +static const rb_data_type_t rb_fiber_data_type = { + "fiber", + {fiber_mark, fiber_free, fiber_memsize, fiber_compact, fiber_handle_weak_references}, + 0, 0, RUBY_TYPED_FREE_IMMEDIATELY +}; + static VALUE fiber_alloc(VALUE klass) { diff --git a/gc.c b/gc.c index 98e5712ca40214..c47f68c50c0047 100644 --- a/gc.c +++ b/gc.c @@ -1204,17 +1204,6 @@ rb_gc_handle_weak_references_alive_p(VALUE obj) return rb_gc_impl_handle_weak_references_alive_p(rb_gc_get_objspace(), obj); } -extern const rb_data_type_t rb_weakmap_type; -void rb_wmap_handle_weak_references(VALUE obj); -extern const rb_data_type_t rb_weakkeymap_type; -void rb_wkmap_handle_weak_references(VALUE obj); - -extern const rb_data_type_t rb_fiber_data_type; -void rb_fiber_handle_weak_references(VALUE obj); - -extern const rb_data_type_t rb_cont_data_type; -void rb_cont_handle_weak_references(VALUE obj); - void rb_gc_handle_weak_references(VALUE obj) { @@ -1223,20 +1212,14 @@ rb_gc_handle_weak_references(VALUE obj) if (RTYPEDDATA_P(obj)) { const rb_data_type_t *type = RTYPEDDATA_TYPE(obj); - if (type == &rb_fiber_data_type) { - rb_fiber_handle_weak_references(obj); - } - else if (type == &rb_cont_data_type) { - rb_cont_handle_weak_references(obj); - } - else if (type == &rb_weakmap_type) { - rb_wmap_handle_weak_references(obj); - } - else if (type == &rb_weakkeymap_type) { - rb_wkmap_handle_weak_references(obj); + if (type->function.handle_weak_references) { + (type->function.handle_weak_references)(RTYPEDDATA_GET_DATA(obj)); } else { - rb_bug("rb_gc_handle_weak_references: unknown TypedData %s", RTYPEDDATA_TYPE(obj)->wrap_struct_name); + rb_bug( + "rb_gc_handle_weak_references: TypedData %s does not implement handle_weak_references", + RTYPEDDATA_TYPE(obj)->wrap_struct_name + ); } } else { diff --git a/include/ruby/internal/core/rtypeddata.h b/include/ruby/internal/core/rtypeddata.h index aadccc238ba1fc..bf6423f8d230f0 100644 --- a/include/ruby/internal/core/rtypeddata.h +++ b/include/ruby/internal/core/rtypeddata.h @@ -262,11 +262,9 @@ struct rb_data_type_struct { RUBY_DATA_FUNC dcompact; /** - * This field is reserved for future extension. For now, it must be - * filled with zeros. + * @internal */ - void *reserved[1]; /* For future extension. - This array *must* be filled with ZERO. */ + void (*handle_weak_references)(void *); } function; /** diff --git a/weakmap.c b/weakmap.c index 7b6f27ce2bbbed..b027604f5e83fe 100644 --- a/weakmap.c +++ b/weakmap.c @@ -112,6 +112,26 @@ wmap_compact(void *ptr) } } +static int +rb_wmap_handle_weak_references_i(st_data_t key, st_data_t val, st_data_t arg) +{ + if (rb_gc_handle_weak_references_alive_p(key) && + rb_gc_handle_weak_references_alive_p(val)) { + return ST_CONTINUE; + } + else { + return ST_DELETE; + } +} + +static void +wmap_handle_weak_references(void *ptr) +{ + struct weakmap *w = ptr; + + st_foreach(w->table, rb_wmap_handle_weak_references_i, (st_data_t)0); +} + const rb_data_type_t rb_weakmap_type = { "weakmap", { @@ -119,6 +139,7 @@ const rb_data_type_t rb_weakmap_type = { wmap_free, wmap_memsize, wmap_compact, + wmap_handle_weak_references, }, 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE }; @@ -140,27 +161,6 @@ static const struct st_hash_type wmap_hash_type = { wmap_hash, }; -static int -rb_wmap_handle_weak_references_i(st_data_t key, st_data_t val, st_data_t arg) -{ - if (rb_gc_handle_weak_references_alive_p(key) && - rb_gc_handle_weak_references_alive_p(val)) { - return ST_CONTINUE; - } - else { - return ST_DELETE; - } -} - -void -rb_wmap_handle_weak_references(VALUE self) -{ - struct weakmap *w; - TypedData_Get_Struct(self, struct weakmap, &rb_weakmap_type, w); - - st_foreach(w->table, rb_wmap_handle_weak_references_i, (st_data_t)0); -} - static VALUE wmap_allocate(VALUE klass) { @@ -588,13 +588,33 @@ wkmap_compact(void *ptr) } } -const rb_data_type_t rb_weakkeymap_type = { +static int +rb_wkmap_handle_weak_references_i(st_data_t key, st_data_t val, st_data_t arg) +{ + if (rb_gc_handle_weak_references_alive_p(key)) { + return ST_CONTINUE; + } + else { + return ST_DELETE; + } +} + +static void +wkmap_handle_weak_references(void *ptr) +{ + struct weakkeymap *w = ptr; + + st_foreach(w->table, rb_wkmap_handle_weak_references_i, (st_data_t)0); +} + +static const rb_data_type_t rb_weakkeymap_type = { "weakkeymap", { wkmap_mark, wkmap_free, wkmap_memsize, wkmap_compact, + wkmap_handle_weak_references, }, 0, 0, RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_EMBEDDABLE }; @@ -621,26 +641,6 @@ static const struct st_hash_type wkmap_hash_type = { wkmap_hash, }; -static int -rb_wkmap_handle_weak_references_i(st_data_t key, st_data_t val, st_data_t arg) -{ - if (rb_gc_handle_weak_references_alive_p(key)) { - return ST_CONTINUE; - } - else { - return ST_DELETE; - } -} - -void -rb_wkmap_handle_weak_references(VALUE self) -{ - struct weakkeymap *w; - TypedData_Get_Struct(self, struct weakkeymap, &rb_weakkeymap_type, w); - - st_foreach(w->table, rb_wkmap_handle_weak_references_i, (st_data_t)0); -} - static VALUE wkmap_allocate(VALUE klass) { From 29e7973e055cc82622cdd4511d78d74ad784c80e Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Sun, 4 Jan 2026 15:36:02 +0100 Subject: [PATCH 3/8] Update to ruby/spec@94dbd55 --- spec/ruby/library/socket/shared/address.rb | 2 +- spec/ruby/library/socket/unixsocket/recvfrom_spec.rb | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/spec/ruby/library/socket/shared/address.rb b/spec/ruby/library/socket/shared/address.rb index b548f1eac06464..49ba17c400061e 100644 --- a/spec/ruby/library/socket/shared/address.rb +++ b/spec/ruby/library/socket/shared/address.rb @@ -173,7 +173,7 @@ end end - guard -> { platform_is :windows and ruby_bug "#21702", ""..."4.1" } do + guard -> { platform_is :windows and ruby_bug "#21702", ""..."4.2" } do it 'equals address of peer socket' do if @method == :local_address @addr.to_s.should == @b.remote_address.to_s diff --git a/spec/ruby/library/socket/unixsocket/recvfrom_spec.rb b/spec/ruby/library/socket/unixsocket/recvfrom_spec.rb index 9bb18047c49a80..5e61cd9a90f998 100644 --- a/spec/ruby/library/socket/unixsocket/recvfrom_spec.rb +++ b/spec/ruby/library/socket/unixsocket/recvfrom_spec.rb @@ -32,7 +32,7 @@ end end - guard -> { platform_is :windows and ruby_bug "#21702", ""..."4.1" } do + guard -> { platform_is :windows and ruby_bug "#21702", ""..."4.2" } do it "returns an array containing basic information on the client as second element" do @client.send("foobar", 0) sock = @server.accept @@ -54,7 +54,7 @@ end end - guard -> { platform_is :windows and ruby_bug "#21702", ""..."4.1" } do + guard -> { platform_is :windows and ruby_bug "#21702", ""..."4.2" } do it "returns an array containing server's address as second element" do @client.send("", 0) sock = @server.accept @@ -131,7 +131,7 @@ end end - guard -> { platform_is :windows and ruby_bug "#21702", ""..."4.1" } do + guard -> { platform_is :windows and ruby_bug "#21702", ""..."4.2" } do it 'returns an Array containing the data and address information' do @server.recvfrom(5).should == ['hello', ['AF_UNIX', '']] end From e79f8974b55de2ef8135c3fad03860e8ad36dfb0 Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Sun, 4 Jan 2026 15:39:31 +0100 Subject: [PATCH 4/8] Get better error if UNIXSocket.socketpair spec fails --- spec/ruby/library/socket/unixsocket/shared/pair.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/ruby/library/socket/unixsocket/shared/pair.rb b/spec/ruby/library/socket/unixsocket/shared/pair.rb index 0f1af43b251323..006863777a1733 100644 --- a/spec/ruby/library/socket/unixsocket/shared/pair.rb +++ b/spec/ruby/library/socket/unixsocket/shared/pair.rb @@ -31,7 +31,7 @@ platform_is :windows do it "emulates unnamed sockets with a temporary file with a path" do - @s1.path.match?(/\\AppData\\Local\\Temp\\\d+-\d+\.\(\$\)\z/).should be_true + @s1.path.should.match?(/\\AppData\\Local\\Temp\\\d+-\d+\.\(\$\)\z/) @s1.addr.should == ["AF_UNIX", @s1.path] @s2.peeraddr.should == ["AF_UNIX", @s1.path] end From 2bf954305323857418b917f4a987c300245ee0eb Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Sun, 4 Jan 2026 16:04:02 +0100 Subject: [PATCH 5/8] Remove assertion which does not hold * https://github.com/ruby/ruby/actions/runs/20694508956/job/59407571754 1) UNIXSocket.pair emulates unnamed sockets with a temporary file with a path FAILED Expected "C:\\a\\_temp\\102424668889-2384.($)".match? /\\AppData\\Local\\Temp\\\d+-\d+\.\(\$\)\z/ to be truthy but was false --- spec/ruby/library/socket/unixsocket/shared/pair.rb | 1 - 1 file changed, 1 deletion(-) diff --git a/spec/ruby/library/socket/unixsocket/shared/pair.rb b/spec/ruby/library/socket/unixsocket/shared/pair.rb index 006863777a1733..d68ee466bf1d61 100644 --- a/spec/ruby/library/socket/unixsocket/shared/pair.rb +++ b/spec/ruby/library/socket/unixsocket/shared/pair.rb @@ -31,7 +31,6 @@ platform_is :windows do it "emulates unnamed sockets with a temporary file with a path" do - @s1.path.should.match?(/\\AppData\\Local\\Temp\\\d+-\d+\.\(\$\)\z/) @s1.addr.should == ["AF_UNIX", @s1.path] @s2.peeraddr.should == ["AF_UNIX", @s1.path] end From 9888a3e8bda75a417f15e3936d5d9a16051c9256 Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Sun, 4 Jan 2026 18:10:42 +0100 Subject: [PATCH 6/8] UNIXSocket#recvfrom only returns the path on Linux * Notably it does not on BSD, macOS and Windows. --- spec/ruby/library/socket/unixsocket/recvfrom_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/ruby/library/socket/unixsocket/recvfrom_spec.rb b/spec/ruby/library/socket/unixsocket/recvfrom_spec.rb index 5e61cd9a90f998..9ae37779616b41 100644 --- a/spec/ruby/library/socket/unixsocket/recvfrom_spec.rb +++ b/spec/ruby/library/socket/unixsocket/recvfrom_spec.rb @@ -44,7 +44,7 @@ end context "when called on a client's socket" do - platform_is_not :windows, :darwin do + platform_is :linux do it "returns an array containing server's address as second element" do @client.send("", 0) sock = @server.accept From 6eadc01cdaa70895d464843de5b6c4d35cab2e27 Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Sun, 4 Jan 2026 18:13:08 +0100 Subject: [PATCH 7/8] Fix condition for UTF-8 default in magic_comment_spec.rb --- spec/ruby/language/magic_comment_spec.rb | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/spec/ruby/language/magic_comment_spec.rb b/spec/ruby/language/magic_comment_spec.rb index 90bb83e279be8a..af9c9dbfd0c8d6 100644 --- a/spec/ruby/language/magic_comment_spec.rb +++ b/spec/ruby/language/magic_comment_spec.rb @@ -45,19 +45,11 @@ describe "Magic comments" do describe "in stdin" do - ruby_version_is ""..."4.0" do - it_behaves_like :magic_comments, :locale, -> file { - print_at_exit = fixture(__FILE__, "print_magic_comment_result_at_exit.rb") - ruby_exe(nil, args: "< #{fixture(__FILE__, file)}", options: "-r#{print_at_exit}") - } - end - - ruby_version_is "4.0" do - it_behaves_like :magic_comments, :UTF8, -> file { - print_at_exit = fixture(__FILE__, "print_magic_comment_result_at_exit.rb") - ruby_exe(nil, args: "< #{fixture(__FILE__, file)}", options: "-r#{print_at_exit}") - } - end + default = (platform_is :windows and ruby_version_is "4.0") ? :UTF8 : :locale + it_behaves_like :magic_comments, default, -> file { + print_at_exit = fixture(__FILE__, "print_magic_comment_result_at_exit.rb") + ruby_exe(nil, args: "< #{fixture(__FILE__, file)}", options: "-r#{print_at_exit}") + } end platform_is_not :windows do From 7d5c0247eb2fb67bb0ac2fd6060bf2996c8c4c46 Mon Sep 17 00:00:00 2001 From: Peter Zhu Date: Sun, 4 Jan 2026 09:33:39 -0500 Subject: [PATCH 8/8] Dump fstr and frozen status in rb_raw_obj_info_buitin_type --- gc.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/gc.c b/gc.c index c47f68c50c0047..9ac68ccb40e09d 100644 --- a/gc.c +++ b/gc.c @@ -4844,6 +4844,10 @@ rb_raw_obj_info_buitin_type(char *const buff, const size_t buff_size, const VALU } break; case T_STRING: { + APPEND_F("[%s%s] ", + C(FL_TEST(obj, RSTRING_FSTR), "F"), + C(RB_OBJ_FROZEN(obj), "R")); + if (STR_SHARED_P(obj)) { APPEND_F(" [shared] len: %ld", RSTRING_LEN(obj)); }