diff options
| author | Benoit Daloze <eregontp@gmail.com> | 2026-01-04 14:53:24 +0100 |
|---|---|---|
| committer | Benoit Daloze <eregontp@gmail.com> | 2026-01-04 14:53:24 +0100 |
| commit | 1b3382cbab83f0dbf21b0d3683d4ab5335f6c342 (patch) | |
| tree | 4837fe96c9c4cffbcfed9d9af2fcde010ebb424d /spec | |
| parent | 18672b392b7164c783381979ad34d550955d0416 (diff) | |
Update to ruby/spec@f54296d
Diffstat (limited to 'spec')
111 files changed, 2752 insertions, 1236 deletions
diff --git a/spec/ruby/.rubocop.yml b/spec/ruby/.rubocop.yml index 68cce31280..0b59a11512 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 014153e0b4..8acab5bc1d 100644 --- a/spec/ruby/command_line/frozen_strings_spec.rb +++ b/spec/ruby/command_line/frozen_strings_spec.rb @@ -42,8 +42,28 @@ describe "With neither --enable-frozen-string-literal nor --disable-frozen-strin 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 ebd9f75d9d..a63f64d296 100644 --- a/spec/ruby/core/array/pack/shared/basic.rb +++ b/spec/ruby/core/array/pack/shared/basic.rb @@ -33,19 +33,15 @@ describe :array_pack_basic_non_float, shared: true do 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 eaf311783a..13e066cc7f 100644 --- a/spec/ruby/core/builtin_constants/builtin_constants_spec.rb +++ b/spec/ruby/core/builtin_constants/builtin_constants_spec.rb @@ -46,6 +46,16 @@ describe "RUBY_ENGINE" do end end +describe "RUBY_ENGINE_VERSION" do + it "is a String" do + RUBY_ENGINE_VERSION.should be_kind_of(String) + end + + it "is frozen" do + RUBY_ENGINE_VERSION.should.frozen? + end +end + describe "RUBY_PLATFORM" do it "is a String" do RUBY_PLATFORM.should be_kind_of(String) @@ -75,3 +85,67 @@ describe "RUBY_REVISION" do RUBY_REVISION.should.frozen? end end + +ruby_version_is "4.0" do + context "The constant" do + describe "Ruby" do + it "is a Module" do + Ruby.should.instance_of?(Module) + end + end + + describe "Ruby::VERSION" do + it "is equal to RUBY_VERSION" do + Ruby::VERSION.should equal(RUBY_VERSION) + end + end + + describe "RUBY::PATCHLEVEL" do + it "is equal to RUBY_PATCHLEVEL" do + Ruby::PATCHLEVEL.should equal(RUBY_PATCHLEVEL) + end + end + + describe "Ruby::COPYRIGHT" do + it "is equal to RUBY_COPYRIGHT" do + Ruby::COPYRIGHT.should equal(RUBY_COPYRIGHT) + end + end + + describe "Ruby::DESCRIPTION" do + it "is equal to RUBY_DESCRIPTION" do + Ruby::DESCRIPTION.should equal(RUBY_DESCRIPTION) + end + end + + describe "Ruby::ENGINE" do + it "is equal to RUBY_ENGINE" do + Ruby::ENGINE.should equal(RUBY_ENGINE) + end + end + + describe "Ruby::ENGINE_VERSION" do + it "is equal to RUBY_ENGINE_VERSION" do + Ruby::ENGINE_VERSION.should equal(RUBY_ENGINE_VERSION) + end + end + + describe "Ruby::PLATFORM" do + it "is equal to RUBY_PLATFORM" do + Ruby::PLATFORM.should equal(RUBY_PLATFORM) + end + end + + describe "Ruby::RELEASE_DATE" do + it "is equal to RUBY_RELEASE_DATE" do + Ruby::RELEASE_DATE.should equal(RUBY_RELEASE_DATE) + end + end + + describe "Ruby::REVISION" do + it "is equal to RUBY_REVISION" do + Ruby::REVISION.should equal(RUBY_REVISION) + end + end + end +end diff --git a/spec/ruby/core/comparable/clamp_spec.rb b/spec/ruby/core/comparable/clamp_spec.rb index cc1df977e2..18f616a997 100644 --- a/spec/ruby/core/comparable/clamp_spec.rb +++ b/spec/ruby/core/comparable/clamp_spec.rb @@ -40,6 +40,39 @@ describe 'Comparable#clamp' do c.clamp(one, two).should equal(two) end + context 'max is nil' do + it 'returns min if less than it' do + one = ComparableSpecs::WithOnlyCompareDefined.new(1) + c = ComparableSpecs::Weird.new(0) + c.clamp(one, nil).should equal(one) + end + + it 'always returns self if greater than min' do + one = ComparableSpecs::WithOnlyCompareDefined.new(1) + c = ComparableSpecs::Weird.new(2) + c.clamp(one, nil).should equal(c) + end + end + + context 'min is nil' do + it 'returns max if greater than it' do + one = ComparableSpecs::WithOnlyCompareDefined.new(1) + c = ComparableSpecs::Weird.new(2) + c.clamp(nil, one).should equal(one) + end + + it 'always returns self if less than max' do + one = ComparableSpecs::WithOnlyCompareDefined.new(1) + c = ComparableSpecs::Weird.new(0) + c.clamp(nil, one).should equal(c) + end + end + + it 'always returns self when min is nil and max is nil' do + c = ComparableSpecs::Weird.new(1) + c.clamp(nil, nil).should equal(c) + end + it 'returns self if within the given range parameters' do one = ComparableSpecs::WithOnlyCompareDefined.new(1) two = ComparableSpecs::WithOnlyCompareDefined.new(2) @@ -76,6 +109,26 @@ describe 'Comparable#clamp' do -> { c.clamp(one...two) }.should raise_error(ArgumentError) end + context 'with nil as the max argument' do + it 'returns min argument if less than it' do + one = ComparableSpecs::WithOnlyCompareDefined.new(1) + zero = ComparableSpecs::WithOnlyCompareDefined.new(0) + c = ComparableSpecs::Weird.new(0) + + c.clamp(one, nil).should equal(one) + c.clamp(zero, nil).should equal(c) + end + + it 'always returns self if greater than min argument' do + one = ComparableSpecs::WithOnlyCompareDefined.new(1) + two = ComparableSpecs::WithOnlyCompareDefined.new(2) + c = ComparableSpecs::Weird.new(2) + + c.clamp(one, nil).should equal(c) + c.clamp(two, nil).should equal(c) + end + end + context 'with endless range' do it 'returns minimum value of the range parameters if less than it' do one = ComparableSpecs::WithOnlyCompareDefined.new(1) @@ -103,6 +156,24 @@ describe 'Comparable#clamp' do 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 @@ describe 'Comparable#clamp' do 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 4239a47d2f..2bdabbf014 100644 --- a/spec/ruby/core/comparable/fixtures/classes.rb +++ b/spec/ruby/core/comparable/fixtures/classes.rb @@ -7,6 +7,7 @@ module ComparableSpecs end def <=>(other) + return nil if other.nil? self.value <=> other.value end end diff --git a/spec/ruby/core/data/fixtures/classes.rb b/spec/ruby/core/data/fixtures/classes.rb index ffd361d781..650c0b2a62 100644 --- a/spec/ruby/core/data/fixtures/classes.rb +++ b/spec/ruby/core/data/fixtures/classes.rb @@ -24,5 +24,11 @@ module DataSpecs 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 9d272780a8..010c73b91b 100644 --- a/spec/ruby/core/data/initialize_spec.rb +++ b/spec/ruby/core/data/initialize_spec.rb @@ -110,5 +110,15 @@ describe "Data#initialize" do 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 8a0873070f..9c34fe0e77 100644 --- a/spec/ruby/core/encoding/find_spec.rb +++ b/spec/ruby/core/encoding/find_spec.rb @@ -50,7 +50,7 @@ describe "Encoding.find" do end it "raises an ArgumentError if the given encoding does not exist" do - -> { Encoding.find('dh2dh278d') }.should raise_error(ArgumentError) + -> { Encoding.find('dh2dh278d') }.should raise_error(ArgumentError, 'unknown encoding name - dh2dh278d') end # Not sure how to do a better test, since locale depends on weird platform-specific stuff diff --git a/spec/ruby/core/enumerable/to_set_spec.rb b/spec/ruby/core/enumerable/to_set_spec.rb index 91499aeb5b..c02ead11fa 100644 --- a/spec/ruby/core/enumerable/to_set_spec.rb +++ b/spec/ruby/core/enumerable/to_set_spec.rb @@ -27,12 +27,4 @@ describe "Enumerable#to_set" do 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 0000000000..16bd2f6b44 --- /dev/null +++ b/spec/ruby/core/fiber/fixtures/scheduler.rb @@ -0,0 +1,35 @@ +module FiberSpecs + + class LoggingScheduler + attr_reader :events + def initialize + @events = [] + end + + def block(*args) + @events << { event: :block, fiber: Fiber.current, args: args } + Fiber.yield + end + + def io_wait(*args) + @events << { event: :io_wait, fiber: Fiber.current, args: args } + Fiber.yield + end + + def kernel_sleep(*args) + @events << { event: :kernel_sleep, fiber: Fiber.current, args: args } + Fiber.yield + end + + def unblock(*args) + @events << { event: :unblock, fiber: Fiber.current, args: args } + Fiber.yield + end + + def fiber_interrupt(*args) + @events << { event: :fiber_interrupt, fiber: Fiber.current, args: args } + Fiber.yield + end + end + +end diff --git a/spec/ruby/core/fiber/scheduler_spec.rb b/spec/ruby/core/fiber/scheduler_spec.rb new file mode 100644 index 0000000000..15a03c1479 --- /dev/null +++ b/spec/ruby/core/fiber/scheduler_spec.rb @@ -0,0 +1,8 @@ +require_relative '../../spec_helper' +require_relative 'shared/scheduler' + +require "fiber" + +describe "Fiber.scheduler" do + it_behaves_like :scheduler, :scheduler +end diff --git a/spec/ruby/core/fiber/set_scheduler_spec.rb b/spec/ruby/core/fiber/set_scheduler_spec.rb new file mode 100644 index 0000000000..82f6acbe86 --- /dev/null +++ b/spec/ruby/core/fiber/set_scheduler_spec.rb @@ -0,0 +1,8 @@ +require_relative '../../spec_helper' +require_relative 'shared/scheduler' + +require "fiber" + +describe "Fiber.scheduler" do + it_behaves_like :scheduler, :set_scheduler +end diff --git a/spec/ruby/core/fiber/shared/scheduler.rb b/spec/ruby/core/fiber/shared/scheduler.rb new file mode 100644 index 0000000000..19bfb75e3e --- /dev/null +++ b/spec/ruby/core/fiber/shared/scheduler.rb @@ -0,0 +1,51 @@ +describe :scheduler, shared: true do + it "validates the scheduler for required methods" do + required_methods = [:block, :unblock, :kernel_sleep, :io_wait] + required_methods.each do |missing_method| + scheduler = Object.new + required_methods.difference([missing_method]).each do |method| + scheduler.define_singleton_method(method) {} + end + -> { + suppress_warning { Fiber.set_scheduler(scheduler) } + }.should raise_error(ArgumentError, /Scheduler must implement ##{missing_method}/) + end + end + + it "can set and get the scheduler" do + required_methods = [:block, :unblock, :kernel_sleep, :io_wait] + scheduler = Object.new + required_methods.each do |method| + scheduler.define_singleton_method(method) {} + end + suppress_warning { Fiber.set_scheduler(scheduler) } + Fiber.scheduler.should == scheduler + end + + it "returns the scheduler after setting it" do + required_methods = [:block, :unblock, :kernel_sleep, :io_wait] + scheduler = Object.new + required_methods.each do |method| + scheduler.define_singleton_method(method) {} + end + result = suppress_warning { Fiber.set_scheduler(scheduler) } + result.should == scheduler + end + + it "can remove the scheduler" do + required_methods = [:block, :unblock, :kernel_sleep, :io_wait] + scheduler = Object.new + required_methods.each do |method| + scheduler.define_singleton_method(method) {} + end + suppress_warning { Fiber.set_scheduler(scheduler) } + Fiber.set_scheduler(nil) + Fiber.scheduler.should be_nil + end + + it "can assign a nil scheduler multiple times" do + Fiber.set_scheduler(nil) + Fiber.set_scheduler(nil) + Fiber.scheduler.should be_nil + end +end diff --git a/spec/ruby/core/file/socket_spec.rb b/spec/ruby/core/file/socket_spec.rb index 5d12e21f55..d3f4eb013a 100644 --- a/spec/ruby/core/file/socket_spec.rb +++ b/spec/ruby/core/file/socket_spec.rb @@ -1,42 +1,10 @@ require_relative '../../spec_helper' require_relative '../../shared/file/socket' -require 'socket' describe "File.socket?" do it_behaves_like :file_socket, :socket?, File -end -describe "File.socket?" do it "returns false if file does not exist" do File.socket?("I_am_a_bogus_file").should == false end - - it "returns false if the file is not a socket" do - filename = tmp("i_exist") - touch(filename) - - File.socket?(filename).should == false - - rm_r filename - end -end - -platform_is_not :windows do - describe "File.socket?" do - before :each do - # We need a really short name here. - # On Linux the path length is limited to 107, see unix(7). - @name = tmp("s") - @server = UNIXServer.new @name - end - - after :each do - @server.close - rm_r @name - end - - it "returns true if the file is a socket" do - File.socket?(@name).should == true - end - end end diff --git a/spec/ruby/core/filetest/socket_spec.rb b/spec/ruby/core/filetest/socket_spec.rb index 63a6a31ecb..f274be6318 100644 --- a/spec/ruby/core/filetest/socket_spec.rb +++ b/spec/ruby/core/filetest/socket_spec.rb @@ -3,4 +3,8 @@ require_relative '../../shared/file/socket' describe "FileTest.socket?" do it_behaves_like :file_socket, :socket?, FileTest + + it "returns false if file does not exist" do + FileTest.socket?("I_am_a_bogus_file").should == false + end end diff --git a/spec/ruby/core/gc/config_spec.rb b/spec/ruby/core/gc/config_spec.rb new file mode 100644 index 0000000000..e20e8e4a16 --- /dev/null +++ b/spec/ruby/core/gc/config_spec.rb @@ -0,0 +1,83 @@ +require_relative '../../spec_helper' + +ruby_version_is "3.4" do + describe "GC.config" do + context "without arguments" do + it "returns a hash of current settings" do + GC.config.should be_kind_of(Hash) + end + + it "includes the name of currently loaded GC implementation as a global key" do + GC.config.should include(:implementation) + GC.config[:implementation].should be_kind_of(String) + end + end + + context "with a hash of options" do + it "allows to set GC implementation's options, returning the new config" do + config = GC.config({}) + # Try to find a boolean setting to reliably test changing it. + key, _value = config.find { |_k, v| v == true } + skip unless key + + GC.config(key => false).should == config.merge(key => false) + GC.config[key].should == false + GC.config(key => true).should == config + GC.config[key].should == true + ensure + GC.config(config.except(:implementation)) + end + + it "does not change settings that aren't present in the hash" do + previous = GC.config + GC.config({}) + GC.config.should == previous + end + + it "ignores unknown keys" do + previous = GC.config + GC.config(foo: "bar") + GC.config.should == previous + end + + it "raises an ArgumentError if options include global keys" do + -> { GC.config(implementation: "default") }.should raise_error(ArgumentError, 'Attempting to set read-only key "Implementation"') + end + end + + context "with a non-hash argument" do + it "returns current settings if argument is nil" do + GC.config(nil).should == GC.config + end + + it "raises ArgumentError for all other arguments" do + -> { GC.config([]) }.should raise_error(ArgumentError) + -> { GC.config("default") }.should raise_error(ArgumentError) + -> { GC.config(1) }.should raise_error(ArgumentError) + end + end + + guard -> { PlatformGuard.standard? && GC.config[:implementation] == "default" } do + context "with default GC implementation on MRI" do + before do + @default_config = GC.config({}) + end + + after do + GC.config(@default_config.except(:implementation)) + end + + it "includes :rgengc_allow_full_mark option, true by default" do + GC.config.should include(:rgengc_allow_full_mark) + GC.config[:rgengc_allow_full_mark].should be_true + end + + it "allows to set :rgengc_allow_full_mark" do + # This key maps truthy and falsey values to true and false. + GC.config(rgengc_allow_full_mark: nil).should == @default_config.merge(rgengc_allow_full_mark: false) + GC.config(rgengc_allow_full_mark: 1.23).should == @default_config.merge(rgengc_allow_full_mark: true) + end + end + end + end +end diff --git a/spec/ruby/core/integer/shared/modulo.rb b/spec/ruby/core/integer/shared/modulo.rb index f678a10806..d91af1e924 100644 --- a/spec/ruby/core/integer/shared/modulo.rb +++ b/spec/ruby/core/integer/shared/modulo.rb @@ -1,6 +1,12 @@ describe :integer_modulo, shared: true do context "fixnum" do it "returns the modulus obtained from dividing self by the given argument" do + # test all possible combinations: + # - integer/double/bignum argument + # - positive/negative argument + # - positive/negative self + # - self greater/smaller than argument + 13.send(@method, 4).should == 1 4.send(@method, 13).should == 4 @@ -16,8 +22,22 @@ describe :integer_modulo, shared: true do (200).send(@method, -256).should == -56 (1000).send(@method, -512).should == -24 + 13.send(@method, -4.0).should == -3.0 + 4.send(@method, -13.0).should == -9.0 + + -13.send(@method, -4.0).should == -1.0 + -4.send(@method, -13.0).should == -4.0 + + -13.send(@method, 4.0).should == 3.0 + -4.send(@method, 13.0).should == 9.0 + 1.send(@method, 2.0).should == 1.0 200.send(@method, bignum_value).should == 200 + + 4.send(@method, bignum_value(10)).should == 4 + 4.send(@method, -bignum_value(10)).should == -18446744073709551622 + -4.send(@method, bignum_value(10)).should == 18446744073709551622 + -4.send(@method, -bignum_value(10)).should == -4 end it "raises a ZeroDivisionError when the given argument is 0" do @@ -44,15 +64,35 @@ describe :integer_modulo, shared: true do context "bignum" do before :each do - @bignum = bignum_value + @bignum = bignum_value(10) end it "returns the modulus obtained from dividing self by the given argument" do + # test all possible combinations: + # - integer/double/bignum argument + # - positive/negative argument + # - positive/negative self + # - self greater/smaller than argument + @bignum.send(@method, 5).should == 1 @bignum.send(@method, -5).should == -4 - @bignum.send(@method, -100).should == -84 + (-@bignum).send(@method, 5).should == 4 + (-@bignum).send(@method, -5).should == -1 + @bignum.send(@method, 2.22).should be_close(1.5603603603605034, TOLERANCE) - @bignum.send(@method, bignum_value(10)).should == 18446744073709551616 + @bignum.send(@method, -2.22).should be_close(-0.6596396396394968, TOLERANCE) + (-@bignum).send(@method, 2.22).should be_close(0.6596396396394968, TOLERANCE) + (-@bignum).send(@method, -2.22).should be_close(-1.5603603603605034, TOLERANCE) + + @bignum.send(@method, @bignum + 10).should == 18446744073709551626 + @bignum.send(@method, -(@bignum + 10)).should == -10 + (-@bignum).send(@method, @bignum + 10).should == 10 + (-@bignum).send(@method, -(@bignum + 10)).should == -18446744073709551626 + + (@bignum + 10).send(@method, @bignum).should == 10 + (@bignum + 10).send(@method, -@bignum).should == -18446744073709551616 + (-(@bignum + 10)).send(@method, @bignum).should == 18446744073709551616 + (-(@bignum + 10)).send(@method, -@bignum).should == -10 end it "raises a ZeroDivisionError when the given argument is 0" do diff --git a/spec/ruby/core/io/shared/new.rb b/spec/ruby/core/io/shared/new.rb index cba5f33ebf..e84133493c 100644 --- a/spec/ruby/core/io/shared/new.rb +++ b/spec/ruby/core/io/shared/new.rb @@ -208,6 +208,26 @@ describe :io_new, shared: true do @io.internal_encoding.to_s.should == 'IBM866' end + it "does not use binary encoding when mode encoding is specified along with binmode: true option" do + @io = IO.send(@method, @fd, 'w:iso-8859-1', binmode: true) + @io.external_encoding.to_s.should == 'ISO-8859-1' + end + + it "does not use textmode argument when mode encoding is specified" do + @io = IO.send(@method, @fd, 'w:ascii-8bit', textmode: true) + @io.external_encoding.to_s.should == 'ASCII-8BIT' + end + + it "does not use binmode argument when external encoding is specified via the :external_encoding option" do + @io = IO.send(@method, @fd, 'w', binmode: true, external_encoding: 'iso-8859-1') + @io.external_encoding.to_s.should == 'ISO-8859-1' + end + + it "does not use textmode argument when external encoding is specified via the :external_encoding option" do + @io = IO.send(@method, @fd, 'w', textmode: true, external_encoding: 'ascii-8bit') + @io.external_encoding.to_s.should == 'ASCII-8BIT' + end + it "raises ArgumentError for nil options" do -> { IO.send(@method, @fd, 'w', nil) @@ -325,6 +345,9 @@ describe :io_new_errors, shared: true do @io = IO.send(@method, @fd, 'w:ISO-8859-1', external_encoding: 'ISO-8859-1') }.should raise_error(ArgumentError) -> { + @io = IO.send(@method, @fd, 'w:ISO-8859-1', internal_encoding: 'ISO-8859-1') + }.should raise_error(ArgumentError) + -> { @io = IO.send(@method, @fd, 'w:ISO-8859-1:UTF-8', internal_encoding: 'ISO-8859-1') }.should raise_error(ArgumentError) end diff --git a/spec/ruby/core/kernel/Float_spec.rb b/spec/ruby/core/kernel/Float_spec.rb index 74f6f1b0bd..9c436b05f7 100644 --- a/spec/ruby/core/kernel/Float_spec.rb +++ b/spec/ruby/core/kernel/Float_spec.rb @@ -261,6 +261,10 @@ describe :kernel_float, shared: true do @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 841c8e8c64..cc11a35451 100644 --- a/spec/ruby/core/kernel/Rational_spec.rb +++ b/spec/ruby/core/kernel/Rational_spec.rb @@ -76,12 +76,62 @@ describe "Kernel.Rational" do 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 @@ describe "Kernel.Rational" do 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 @@ describe "Kernel.Rational" do Rational(:sym, exception: false).should == nil Rational("abc", exception: false).should == nil end + + it "swallows an exception raised in #to_r" do + obj = Object.new + def obj.to_r; raise; end + Rational(obj, exception: false).should == nil + end + + it "swallows an exception raised in #to_int" do + obj = Object.new + def obj.to_int; raise; end + Rational(obj, exception: false).should == nil + end end describe "and [non-Numeric, Numeric]" do @@ -119,6 +181,18 @@ describe "Kernel.Rational" do Rational(:sym, 1, exception: false).should == nil Rational("abc", 1, exception: false).should == nil end + + it "swallows an exception raised in #to_r" do + obj = Object.new + def obj.to_r; raise; end + Rational(obj, 1, exception: false).should == nil + end + + it "swallows an exception raised in #to_int" do + obj = Object.new + def obj.to_int; raise; end + Rational(obj, 1, exception: false).should == nil + end end describe "and [anything, non-Numeric]" do @@ -126,6 +200,18 @@ describe "Kernel.Rational" do Rational(:sym, :sym, exception: false).should == nil Rational("abc", :sym, exception: false).should == nil end + + it "swallows an exception raised in #to_r" do + obj = Object.new + def obj.to_r; raise; end + Rational(obj, obj, exception: false).should == nil + end + + it "swallows an exception raised in #to_int" do + obj = Object.new + def obj.to_int; raise; end + Rational(obj, obj, exception: false).should == nil + end end describe "and non-Numeric String arguments" do diff --git a/spec/ruby/core/kernel/raise_spec.rb b/spec/ruby/core/kernel/raise_spec.rb index a4ab963fa3..fcd011d4e6 100644 --- a/spec/ruby/core/kernel/raise_spec.rb +++ b/spec/ruby/core/kernel/raise_spec.rb @@ -51,11 +51,11 @@ describe "Kernel#raise" do -> { 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 4401e54256..e9c600aac4 100644 --- a/spec/ruby/core/kernel/sleep_spec.rb +++ b/spec/ruby/core/kernel/sleep_spec.rb @@ -1,4 +1,5 @@ require_relative '../../spec_helper' +require_relative '../fiber/fixtures/scheduler' describe "Kernel#sleep" do it "is a private method" do @@ -84,6 +85,40 @@ describe "Kernel#sleep" do t.value.should == 5 end end + + context "Kernel.sleep with Fiber scheduler" do + before :each do + Fiber.set_scheduler(FiberSpecs::LoggingScheduler.new) + end + + after :each do + Fiber.set_scheduler(nil) + end + + it "calls the scheduler without arguments when no duration is given" do + sleeper = Fiber.new(blocking: false) do + sleep + end + sleeper.resume + Fiber.scheduler.events.should == [{ event: :kernel_sleep, fiber: sleeper, args: [] }] + end + + it "calls the scheduler with the given duration" do + sleeper = Fiber.new(blocking: false) do + sleep(0.01) + end + sleeper.resume + Fiber.scheduler.events.should == [{ event: :kernel_sleep, fiber: sleeper, args: [0.01] }] + end + + it "does not call the scheduler if the fiber is blocking" do + sleeper = Fiber.new(blocking: true) do + sleep(0.01) + end + sleeper.resume + Fiber.scheduler.events.should == [] + end + end end describe "Kernel.sleep" do diff --git a/spec/ruby/core/math/expm1_spec.rb b/spec/ruby/core/math/expm1_spec.rb new file mode 100644 index 0000000000..5725319abb --- /dev/null +++ b/spec/ruby/core/math/expm1_spec.rb @@ -0,0 +1,37 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +ruby_version_is "4.0" do + describe "Math.expm1" do + it "calculates Math.exp(arg) - 1" do + Math.expm1(3).should == Math.exp(3) - 1 + end + + it "preserves precision that can be lost otherwise" do + Math.expm1(1.0e-16).should be_close(1.0e-16, TOLERANCE) + Math.expm1(1.0e-16).should != 0.0 + end + + it "raises a TypeError if the argument cannot be coerced with Float()" do + -> { Math.expm1("test") }.should raise_error(TypeError, "can't convert String into Float") + end + + it "returns NaN given NaN" do + Math.expm1(nan_value).nan?.should be_true + end + + it "raises a TypeError if the argument is nil" do + -> { Math.expm1(nil) }.should raise_error(TypeError, "can't convert nil into Float") + end + + it "accepts any argument that can be coerced with Float()" do + Math.expm1(MathSpecs::Float.new).should be_close(Math::E - 1, TOLERANCE) + end + end + + describe "Math#expm1" do + it "is accessible as a private instance method" do + IncludesMath.new.send(:expm1, 23.1415).should be_close(11226018483.0012, TOLERANCE) + end + end +end diff --git a/spec/ruby/core/math/log1p_spec.rb b/spec/ruby/core/math/log1p_spec.rb new file mode 100644 index 0000000000..216358a3c4 --- /dev/null +++ b/spec/ruby/core/math/log1p_spec.rb @@ -0,0 +1,49 @@ +require_relative '../../spec_helper' +require_relative 'fixtures/classes' + +ruby_version_is "4.0" do + describe "Math.log1p" do + it "calculates Math.log(1 + arg)" do + Math.log1p(3).should == Math.log(1 + 3) + end + + it "preserves precision that can be lost otherwise" do + Math.log1p(1e-16).should be_close(1.0e-16, TOLERANCE) + Math.log1p(1e-16).should != 0.0 + end + + it "raises an Math::DomainError if the argument is less than 1" do + -> { Math.log1p(-1-1e-15) }.should raise_error(Math::DomainError, "Numerical argument is out of domain - log1p") + end + + it "raises a TypeError if the argument cannot be coerced with Float()" do + -> { Math.log1p("test") }.should raise_error(TypeError, "can't convert String into Float") + end + + it "raises a TypeError for numerical values passed as string" do + -> { Math.log1p("10") }.should raise_error(TypeError, "can't convert String into Float") + end + + it "does not accept a second argument for the base" do + -> { Math.log1p(9, 3) }.should raise_error(ArgumentError, "wrong number of arguments (given 2, expected 1)") + end + + it "returns NaN given NaN" do + Math.log1p(nan_value).nan?.should be_true + end + + it "raises a TypeError if the argument is nil" do + -> { Math.log1p(nil) }.should raise_error(TypeError, "can't convert nil into Float") + end + + it "accepts any argument that can be coerced with Float()" do + Math.log1p(MathSpecs::Float.new).should be_close(0.6931471805599453, TOLERANCE) + end + end + + describe "Math#log1p" do + it "is accessible as a private instance method" do + IncludesMath.new.send(:log1p, 4.21).should be_close(1.65057985576528, TOLERANCE) + end + end +end diff --git a/spec/ruby/core/module/fixtures/classes.rb b/spec/ruby/core/module/fixtures/classes.rb index a434e7b0b8..964f64c593 100644 --- a/spec/ruby/core/module/fixtures/classes.rb +++ b/spec/ruby/core/module/fixtures/classes.rb @@ -1,6 +1,6 @@ module ModuleSpecs def self.without_test_modules(modules) - ignore = %w[MSpecRSpecAdapter PP::ObjectMixin ModuleSpecs::IncludedInObject MainSpecs::Module ConstantSpecs::ModuleA] + ignore = %w[MSpecRSpecAdapter PP::ObjectMixin MainSpecs::Module ConstantSpecs::ModuleA] modules.reject { |k| ignore.include?(k.name) } end diff --git a/spec/ruby/core/proc/parameters_spec.rb b/spec/ruby/core/proc/parameters_spec.rb index e9bc9a1c57..cf8a8f5b12 100644 --- a/spec/ruby/core/proc/parameters_spec.rb +++ b/spec/ruby/core/proc/parameters_spec.rb @@ -158,4 +158,18 @@ describe "Proc#parameters" do it "returns :nokey for **nil parameter" do proc { |**nil| }.parameters.should == [[:nokey]] end + + ruby_version_is "3.4"..."4.0" do + it "handles the usage of `it` as a parameter" do + eval("proc { it }").parameters.should == [[:opt, nil]] + eval("lambda { it }").parameters.should == [[:req]] + end + end + + ruby_version_is "4.0" do + it "handles the usage of `it` as a parameter" do + eval("proc { it }").parameters.should == [[:opt]] + eval("lambda { it }").parameters.should == [[:req]] + end + end end diff --git a/spec/ruby/core/range/to_set_spec.rb b/spec/ruby/core/range/to_set_spec.rb new file mode 100644 index 0000000000..589c0e9aed --- /dev/null +++ b/spec/ruby/core/range/to_set_spec.rb @@ -0,0 +1,55 @@ +require_relative '../../spec_helper' +require_relative '../enumerable/fixtures/classes' + +describe "Enumerable#to_set" do + it "returns a new Set created from self" do + (1..4).to_set.should == Set[1, 2, 3, 4] + (1...4).to_set.should == Set[1, 2, 3] + end + + it "passes down passed blocks" do + (1..3).to_set { |x| x * x }.should == Set[1, 4, 9] + end + + ruby_version_is "4.0" do + it "raises a RangeError if the range is infinite" do + -> { (1..).to_set }.should raise_error(RangeError, "cannot convert endless range to a set") + -> { (1...).to_set }.should raise_error(RangeError, "cannot convert endless range to a set") + end + end + + ruby_version_is ""..."4.0" do + it "instantiates an object of provided as the first argument set class" do + set = (1..3).to_set(EnumerableSpecs::SetSubclass) + set.should be_kind_of(EnumerableSpecs::SetSubclass) + set.to_a.sort.should == [1, 2, 3] + end + end + + ruby_version_is "4.0"..."4.1" do + it "instantiates an object of provided as the first argument set class and warns" do + set = nil + proc { + set = (1..3).to_set(EnumerableSpecs::SetSubclass) + }.should complain(/Enumerable#to_set/) + set.should be_kind_of(EnumerableSpecs::SetSubclass) + set.to_a.sort.should == [1, 2, 3] + end + end + + ruby_version_is "4.1" do + it "does not accept any positional argument" do + -> { + (1..3).to_set(EnumerableSpecs::SetSubclass) + }.should raise_error(ArgumentError, 'wrong number of arguments (given 1, expected 0)') + end + end + + it "does not need explicit `require 'set'`" do + output = ruby_exe(<<~RUBY, options: '--disable-gems', args: '2>&1') + puts (1..3).to_set.to_a.inspect + RUBY + + output.chomp.should == "[1, 2, 3]" + end +end diff --git a/spec/ruby/core/regexp/linear_time_spec.rb b/spec/ruby/core/regexp/linear_time_spec.rb index c3b3500549..cf9e73c37c 100644 --- a/spec/ruby/core/regexp/linear_time_spec.rb +++ b/spec/ruby/core/regexp/linear_time_spec.rb @@ -24,4 +24,10 @@ describe "Regexp.linear_time?" do 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 b37a447683..734630bda0 100644 --- a/spec/ruby/core/string/unpack/shared/basic.rb +++ b/spec/ruby/core/string/unpack/shared/basic.rb @@ -9,12 +9,19 @@ describe :string_unpack_basic, shared: true do "abc".unpack(d).should be_an_instance_of(Array) end + ruby_version_is ""..."3.3" do + it "warns about using an unknown directive" do + -> { "abcdefgh".unpack("a R" + unpack_format) }.should complain(/unknown unpack directive 'R' in 'a R#{unpack_format}'/) + -> { "abcdefgh".unpack("a 0" + unpack_format) }.should complain(/unknown unpack directive '0' in 'a 0#{unpack_format}'/) + -> { "abcdefgh".unpack("a :" + unpack_format) }.should complain(/unknown unpack directive ':' in 'a :#{unpack_format}'/) + end + end + ruby_version_is "3.3" do - # https://bugs.ruby-lang.org/issues/19150 - it 'raise ArgumentError when a directive is unknown' do - -> { "abcdefgh".unpack("a R" + unpack_format) }.should raise_error(ArgumentError, /unknown unpack directive 'R'/) - -> { "abcdefgh".unpack("a 0" + unpack_format) }.should raise_error(ArgumentError, /unknown unpack directive '0'/) - -> { "abcdefgh".unpack("a :" + unpack_format) }.should raise_error(ArgumentError, /unknown unpack directive ':'/) + it "raises ArgumentError when a directive is unknown" do + -> { "abcdefgh".unpack("a K" + unpack_format) }.should raise_error(ArgumentError, "unknown unpack directive 'K' in 'a K#{unpack_format}'") + -> { "abcdefgh".unpack("a 0" + unpack_format) }.should raise_error(ArgumentError, "unknown unpack directive '0' in 'a 0#{unpack_format}'") + -> { "abcdefgh".unpack("a :" + unpack_format) }.should raise_error(ArgumentError, "unknown unpack directive ':' in 'a :#{unpack_format}'") end end end diff --git a/spec/ruby/core/string/uplus_spec.rb b/spec/ruby/core/string/uplus_spec.rb index c0b0c49ede..20767bcc01 100644 --- a/spec/ruby/core/string/uplus_spec.rb +++ b/spec/ruby/core/string/uplus_spec.rb @@ -13,14 +13,48 @@ describe 'String#+@' do output.should == 'foobar' end - it 'returns self if the String is not frozen' do - input = 'foo' + it 'returns a mutable String itself' do + input = String.new("foo") output = +input - output.equal?(input).should == true + output.should.equal?(input) + + input << "bar" + output.should == "foobar" + end + + context 'if file has "frozen_string_literal: true" magic comment' do + it 'returns mutable copy of a literal' do + ruby_exe(fixture(__FILE__, "freeze_magic_comment.rb")).should == 'mutable' + end end - it 'returns mutable copy despite freeze-magic-comment in file' do - ruby_exe(fixture(__FILE__, "freeze_magic_comment.rb")).should == 'mutable' + context 'if file has "frozen_string_literal: false" magic comment' do + it 'returns literal string itself' do + input = 'foo' + output = +input + + output.equal?(input).should == true + end + end + + context 'if file has no frozen_string_literal magic comment' do + ruby_version_is ''...'3.4' do + it 'returns literal string itself' do + eval(<<~RUBY).should == true + s = "foo" + s.equal?(+s) + RUBY + end + end + + ruby_version_is '3.4' do + it 'returns mutable copy of a literal' do + eval(<<~RUBY).should == false + s = "foo" + s.equal?(+s) + RUBY + end + end end end diff --git a/spec/ruby/core/symbol/shared/id2name.rb b/spec/ruby/core/symbol/shared/id2name.rb index d012b7634e..00a9c7d7dc 100644 --- a/spec/ruby/core/symbol/shared/id2name.rb +++ b/spec/ruby/core/symbol/shared/id2name.rb @@ -13,4 +13,18 @@ describe :symbol_id2name, shared: true do symbol.send(@method).encoding.should == Encoding::US_ASCII end + + ruby_version_is "3.4" do + it "warns about mutating returned string" do + -> { :bad!.send(@method).upcase! }.should complain(/warning: string returned by :bad!.to_s will be frozen in the future/) + end + + it "does not warn about mutation when Warning[:deprecated] is false" do + deprecated = Warning[:deprecated] + Warning[:deprecated] = false + -> { :bad!.send(@method).upcase! }.should_not complain + ensure + Warning[:deprecated] = deprecated + end + end end diff --git a/spec/ruby/core/unboundmethod/equal_value_spec.rb b/spec/ruby/core/unboundmethod/equal_value_spec.rb index 4d4fc66504..b2d78c50af 100644 --- a/spec/ruby/core/unboundmethod/equal_value_spec.rb +++ b/spec/ruby/core/unboundmethod/equal_value_spec.rb @@ -81,7 +81,7 @@ describe "UnboundMethod#==" do (@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 0000000000..1e310ef38b --- /dev/null +++ b/spec/ruby/core/warning/categories_spec.rb @@ -0,0 +1,12 @@ +require_relative '../../spec_helper' + +ruby_version_is "3.4" do + describe "Warning.categories" do + # There might be more, but these are standard across Ruby implementations + it "returns the list of possible warning categories" do + Warning.categories.should.include? :deprecated + Warning.categories.should.include? :experimental + Warning.categories.should.include? :performance + end + end +end diff --git a/spec/ruby/core/warning/warn_spec.rb b/spec/ruby/core/warning/warn_spec.rb index 1267734987..2e4a822e02 100644 --- a/spec/ruby/core/warning/warn_spec.rb +++ b/spec/ruby/core/warning/warn_spec.rb @@ -99,14 +99,14 @@ describe "Warning.warn" do 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 @@ describe "Warning.warn" do 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 1e8f8893aa..c8b1215f56 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 e1e4a363c8..cc003b8946 100644 --- a/spec/ruby/language/block_spec.rb +++ b/spec/ruby/language/block_spec.rb @@ -1049,6 +1049,12 @@ describe "`it` calls without arguments in a block with no ordinary parameters" d }.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 @@ describe "`it` calls without arguments in a block with no ordinary parameters" d -> { 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 0b770d69b5..6fb785fd56 100644 --- a/spec/ruby/language/class_spec.rb +++ b/spec/ruby/language/class_spec.rb @@ -46,7 +46,14 @@ describe "A class definition" do -> { 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 @@ describe "Reopening a class" do 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 33d323846e..75eee77791 100644 --- a/spec/ruby/language/fixtures/module.rb +++ b/spec/ruby/language/fixtures/module.rb @@ -12,13 +12,4 @@ module ModuleSpecs 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 0000000000..72023180d9 --- /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 f2bf3a08e5..90bb83e279 100644 --- a/spec/ruby/language/magic_comment_spec.rb +++ b/spec/ruby/language/magic_comment_spec.rb @@ -45,10 +45,19 @@ end 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 39b245fe2a..8f72bd45ed 100644 --- a/spec/ruby/language/method_spec.rb +++ b/spec/ruby/language/method_spec.rb @@ -1621,12 +1621,12 @@ describe "warning about not used block argument" do # 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 @@ describe "warning about not used block argument" do 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 4db00bd7fb..fba4aa8c6e 100644 --- a/spec/ruby/language/module_spec.rb +++ b/spec/ruby/language/module_spec.rb @@ -31,10 +31,34 @@ describe "The module keyword" do 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 0000000000..6c40e34ccc --- /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 02921ab8bf..1cea2b786a 100644 --- a/spec/ruby/library/cgi/escapeURIComponent_spec.rb +++ b/spec/ruby/library/cgi/escapeURIComponent_spec.rb @@ -6,48 +6,67 @@ rescue LoadError 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 0000000000..f80eb1626b --- /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 == "Ò<<ABC".encode("ISO-8859-1") + end + + it "accepts a string name of an Encoding" do + CGI.unescapeURIComponent("%D2%3C%3CABC", "ISO-8859-1").should == "Ò<<ABC".encode("ISO-8859-1") + end + + it "raises ArgumentError if specified encoding is unknown" do + -> { 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 == "Ò<<ABC".encode("ISO-8859-1") + decoded.encoding.should == Encoding::ISO_8859_1 + ensure + CGI.accept_charset = original_charset + end + + it "has CGI.accept_charset as UTF-8 by default" do + decoded = CGI.unescapeURIComponent("%CE%B2ABC") + decoded.should == "βABC" + decoded.encoding.should == Encoding::UTF_8 + end + end + + ruby_version_is "4.0" do + # "cgi/escape" does not have methods to access @@accept_charset. + # Full "cgi" gem provides them, allowing to possibly change it. + it "uses CGI's @@accept_charset as the default target encoding" do + original_charset = CGI.class_variable_get(:@@accept_charset) + CGI.class_variable_set(:@@accept_charset, "ISO-8859-1") + decoded = CGI.unescapeURIComponent("%D2%3C%3CABC") + decoded.should == "Ò<<ABC".encode("ISO-8859-1") + decoded.encoding.should == Encoding::ISO_8859_1 + ensure + CGI.class_variable_set(:@@accept_charset, original_charset) + end + + it "has CGI's @@accept_charset as UTF-8 by default" do + decoded = CGI.unescapeURIComponent("%CE%B2ABC") + decoded.should == "βABC" + decoded.encoding.should == Encoding::UTF_8 + end + end + + context "when source string specifies octets invalid in target encoding" do + it "uses source string's encoding" do + string = "%A2%A6%A3".encode(Encoding::SHIFT_JIS) + decoded = CGI.unescapeURIComponent(string, Encoding::US_ASCII) + decoded.encoding.should == Encoding::SHIFT_JIS + decoded.should == "「ヲ」".encode(Encoding::SHIFT_JIS) + decoded.valid_encoding?.should be_true + end + + it "uses source string's encoding even if it's also invalid" do + string = "%FF".encode(Encoding::US_ASCII) + decoded = CGI.unescapeURIComponent(string, Encoding::SHIFT_JIS) + decoded.encoding.should == Encoding::US_ASCII + decoded.should == "\xFF".dup.force_encoding(Encoding::US_ASCII) + decoded.valid_encoding?.should be_false + end + end + + it "decodes an empty string as an empty string with target encoding" do + string = "".encode(Encoding::BINARY) + decoded = CGI.unescapeURIComponent(string, "UTF-8") + decoded.should == "" + decoded.encoding.should == Encoding::UTF_8 + string.should_not.equal?(decoded) + end + + it "raises a TypeError with nil" do + -> { + 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 7229dab9de..5d075be057 100644 --- a/spec/ruby/library/socket/addrinfo/afamily_spec.rb +++ b/spec/ruby/library/socket/addrinfo/afamily_spec.rb @@ -23,15 +23,13 @@ describe "Addrinfo#afamily" do 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 2bc3b6a2e3..3c2f9f73d8 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 @@ describe 'Addrinfo#family_addrinfo' do 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 76579de74c..43b5a2000a 100644 --- a/spec/ruby/library/socket/addrinfo/getnameinfo_spec.rb +++ b/spec/ruby/library/socket/addrinfo/getnameinfo_spec.rb @@ -22,19 +22,17 @@ describe 'Addrinfo#getnameinfo' do 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 b7477efc79..1f16531aaa 100644 --- a/spec/ruby/library/socket/addrinfo/initialize_spec.rb +++ b/spec/ruby/library/socket/addrinfo/initialize_spec.rb @@ -17,7 +17,7 @@ describe "Addrinfo#initialize" do @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 @@ describe "Addrinfo#initialize" do @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 @@ describe "Addrinfo#initialize" do @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 @@ describe "Addrinfo#initialize" do @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 @@ describe "Addrinfo#initialize" do @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 @@ describe "Addrinfo#initialize" do @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 @@ describe "Addrinfo#initialize" do @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 @@ describe "Addrinfo#initialize" do @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 @@ describe "Addrinfo#initialize" do @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 @@ describe "Addrinfo#initialize" do @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 @@ describe "Addrinfo#initialize" do 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 70ca4dd4d7..6b18c79469 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 @@ describe 'Addrinfo#inspect_sockaddr' do 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 98e1e83ffa..1442af6162 100644 --- a/spec/ruby/library/socket/addrinfo/inspect_spec.rb +++ b/spec/ruby/library/socket/addrinfo/inspect_spec.rb @@ -41,25 +41,23 @@ describe 'Addrinfo#inspect' do 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 == '#<Addrinfo: /foo SOCK_STREAM>' - end + addr.inspect.should == '#<Addrinfo: /foo SOCK_STREAM>' + 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 == '#<Addrinfo: UNIX foo SOCK_STREAM>' - end + addr.inspect.should == '#<Addrinfo: UNIX foo SOCK_STREAM>' + 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 == '#<Addrinfo: /foo SOCK_DGRAM>' - end + addr.inspect.should == '#<Addrinfo: /foo SOCK_DGRAM>' 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 4522cf5cfd..193432e861 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 @@ describe "Addrinfo#ip_address" do 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 4118607db0..f10ce35143 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 @@ describe "Addrinfo#ip_port" do 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 80e7a62df7..09b9341605 100644 --- a/spec/ruby/library/socket/addrinfo/ip_spec.rb +++ b/spec/ruby/library/socket/addrinfo/ip_spec.rb @@ -22,15 +22,13 @@ describe "Addrinfo#ip?" do 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 6c81c48d1c..58260c4557 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 @@ describe "Addrinfo#ip_unpack" do 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 10ad084fc9..3a584d4f52 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 @@ describe "Addrinfo#ipv4_loopback?" do 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 f7fead8640..e4b4cfcc84 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 @@ describe "Addrinfo#ipv4_multicast?" do 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 e5a33b4953..97218b5ba3 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 @@ describe "Addrinfo#ipv4_private?" do 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 7cba8209b6..61f7759b10 100644 --- a/spec/ruby/library/socket/addrinfo/ipv4_spec.rb +++ b/spec/ruby/library/socket/addrinfo/ipv4_spec.rb @@ -21,15 +21,13 @@ describe "Addrinfo#ipv4?" do 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 9ff8f107bf..ffc75185ea 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 @@ describe "Addrinfo#ipv6_loopback?" do 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 2c987b5921..99d4e8cf4d 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 @@ describe "Addrinfo#ipv6_multicast?" do 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 131e38849c..436d5e930b 100644 --- a/spec/ruby/library/socket/addrinfo/ipv6_spec.rb +++ b/spec/ruby/library/socket/addrinfo/ipv6_spec.rb @@ -21,15 +21,13 @@ describe "Addrinfo#ipv6?" do 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 6dfaf531ae..29050bec20 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 @@ guard -> { SocketSpecs.ipv6_available? } do 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 2d69a33b53..e2c3497f7f 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 @@ describe 'Addrinfo#marshal_dump' do 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 aa20865224..02cef90115 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 @@ describe 'Addrinfo#marshal_load' do 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 984744a964..da530b7fdc 100644 --- a/spec/ruby/library/socket/addrinfo/pfamily_spec.rb +++ b/spec/ruby/library/socket/addrinfo/pfamily_spec.rb @@ -29,15 +29,13 @@ describe "Addrinfo#pfamily" do 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 ea143fc4a8..f6ffc9acf9 100644 --- a/spec/ruby/library/socket/addrinfo/protocol_spec.rb +++ b/spec/ruby/library/socket/addrinfo/protocol_spec.rb @@ -10,15 +10,13 @@ describe "Addrinfo#protocol" do 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 4f7cf439a0..70d6bfbbfe 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 @@ describe :socket_addrinfo_to_sockaddr, shared: true do 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 b994bea140..e5f02cd759 100644 --- a/spec/ruby/library/socket/addrinfo/socktype_spec.rb +++ b/spec/ruby/library/socket/addrinfo/socktype_spec.rb @@ -9,15 +9,13 @@ describe "Addrinfo#socktype" do 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 6bfb56a4ac..2a9076a354 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 4596ece17e..7597533a76 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 1a1c9982d9..2e318fcb85 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 @@ describe 'Socket#connect_address' do 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 6179211d96..2e03cd3684 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 '../spec_helper' 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 1e8d84e1c9..f686e67326 100644 --- a/spec/ruby/library/socket/basicsocket/setsockopt_spec.rb +++ b/spec/ruby/library/socket/basicsocket/setsockopt_spec.rb @@ -315,22 +315,20 @@ describe 'BasicSocket#setsockopt' do 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 f3be9cfb99..b548f1eac0 100644 --- a/spec/ruby/library/socket/shared/address.rb +++ b/spec/ruby/library/socket/shared/address.rb @@ -129,41 +129,51 @@ describe :socket_local_remote_address, shared: true do 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 @@ describe :socket_local_remote_address, shared: true do @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 f309aa02c7..4bfcf4edb9 100644 --- a/spec/ruby/library/socket/shared/pack_sockaddr.rb +++ b/spec/ruby/library/socket/shared/pack_sockaddr.rb @@ -47,23 +47,21 @@ describe :socket_pack_sockaddr_in, shared: true do 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 @@ describe :socket_pack_sockaddr_un, shared: true do 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 0f34d4a50b..6192bc8bf6 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 fc357740fa..34c3b96d07 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 4bff59bd4b..2a5d77f96f 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 79ec68cd18..935b5cb543 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 @@ describe "Socket.unpack_sockaddr_in" do 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 12f970f89b..6e0f11de3d 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 1121542dd5..b33663e02d 100644 --- a/spec/ruby/library/socket/spec_helper.rb +++ b/spec/ruby/library/socket/spec_helper.rb @@ -2,7 +2,6 @@ require_relative '../../spec_helper' 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 dba3de7359..f67941b296 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 1305bc6220..cc2c922b6f 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 8cc55ef391..be1c2df4d7 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 0cc49ef1eb..3728a307b0 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 b90b3bbb09..7938d648c4 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 a160e3ce5c..7d0c7bf76e 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 16453dd3bd..c49df802d0 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 '../spec_helper' 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 e59731878a..c4a4ecc824 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 d93e061312..1afe9b12dc 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 bf7896ab0e..5dccfcc745 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 a542ba6db5..77bb521069 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 == "#<UNIXSocket:fd #{s1.fileno}>" - s2.inspect.should == "#<UNIXSocket:fd #{s2.fileno}>" - 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 == "#<UNIXSocket:fd #{s1.fileno}>" + s2.inspect.should == "#<UNIXSocket:fd #{s2.fileno}>" + 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 734253e7f5..0fdec38293 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 6d8ea6dcfe..fea2c1e2b7 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 61def30abb..b5e8c6c23a 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 '../spec_helper' 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 b0a3b2af99..9690142668 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 '../fixtures/classes' 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 ef7d0f0b2a..108a6c3063 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 '../spec_helper' 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 a608378e4f..ffe7e4bea2 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 72bc96b1fe..10cab13b42 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 1dbc4538e3..f0b408f309 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 d849fdc302..9bb18047c4 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 @@ with_feature :unix_socket do 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 0b416254d0..84bdff0a6a 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 80f3550c6d..52186ec3cf 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 ade7fc9852..0f1af43b25 100644 --- a/spec/ruby/library/socket/unixsocket/shared/pair.rb +++ b/spec/ruby/library/socket/unixsocket/shared/pair.rb @@ -12,18 +12,37 @@ describe :unixsocket_pair, shared: true do @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 5f34008df3..c61fc00be4 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 '../fixtures/classes' 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 988c552235..dadefb7837 100644 --- a/spec/ruby/library/stringio/readpartial_spec.rb +++ b/spec/ruby/library/stringio/readpartial_spec.rb @@ -24,6 +24,14 @@ describe "StringIO#readpartial" do @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 0000000000..4f0ad030e5 --- /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 0000000000..53127fc973 --- /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 55a1cfd284..ef6c482d1c 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 |
