1
0
Fork 0
mirror of https://github.com/ruby/ruby.git synced 2022-11-09 12:17:21 -05:00
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@64180 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
eregon 2018-08-03 16:19:40 +00:00
parent aeeaadaad0
commit b53cf149ad
246 changed files with 9108 additions and 548 deletions

View file

@ -92,6 +92,13 @@ In similar fashion, the following commands run the respective specs:
See [CONTRIBUTING.md](https://github.com/ruby/spec/blob/master/CONTRIBUTING.md). See [CONTRIBUTING.md](https://github.com/ruby/spec/blob/master/CONTRIBUTING.md).
### Socket specs from rubysl-socket
Most specs under `library/socket` were imported from [the rubysl-socket project](https://github.com/rubysl/rubysl-socket).
The 3 copyright holders of rubysl-socket, Yorick Peterse, Chuck Remes and
Brian Shirai, [agreed to relicense those specs](https://github.com/rubysl/rubysl-socket/issues/15)
under the MIT license in ruby/spec.
### History and RubySpec ### History and RubySpec
This project was originally born from [Rubinius](https://github.com/rubinius/rubinius) tests being converted to the spec style. This project was originally born from [Rubinius](https://github.com/rubinius/rubinius) tests being converted to the spec style.

View file

@ -22,7 +22,7 @@ describe "Processing RUBYOPT" do
result.should =~ /value of \$DEBUG is true/ result.should =~ /value of \$DEBUG is true/
end end
unless CROSS_COMPILING guard -> { not CROSS_COMPILING } do
it "prints the version number for '-v'" do it "prints the version number for '-v'" do
ENV["RUBYOPT"] = '-v' ENV["RUBYOPT"] = '-v'
ruby_exe("")[/\A.*/].should == RUBY_DESCRIPTION ruby_exe("")[/\A.*/].should == RUBY_DESCRIPTION

View file

@ -111,6 +111,31 @@ describe "Array#reject!" do
lambda { ArraySpecs.empty_frozen_array.reject! {} }.should raise_error(frozen_error_class) lambda { ArraySpecs.empty_frozen_array.reject! {} }.should raise_error(frozen_error_class)
end end
it "does not truncate the array is the block raises an exception" do
a = [1, 2, 3]
begin
a.reject! { raise StandardError, 'Oops' }
rescue
end
a.should == [1, 2, 3]
end
ruby_version_is "2.4" do
it "only removes elements for which the block returns true, keeping the element which raised an error." do
a = [1, 2, 3, 4]
begin
a.reject! do |x|
return true if x == 2
raise raise StandardError, 'Oops' if x == 3
end
rescue
end
a.should == [1, 3, 4]
end
end
it_behaves_like :enumeratorize, :reject! it_behaves_like :enumeratorize, :reject!
it_behaves_like :enumeratorized_with_origin_size, :reject!, [1,2,3] it_behaves_like :enumeratorized_with_origin_size, :reject!, [1,2,3]
it_behaves_like :delete_if, :reject! it_behaves_like :delete_if, :reject!

View file

@ -23,6 +23,54 @@ describe "Binding#eval" do
bind2.local_variables.should == [] bind2.local_variables.should == []
end end
it "inherits __LINE__ from the enclosing scope" do
obj = BindingSpecs::Demo.new(1)
bind = obj.get_binding
bind.eval("__LINE__").should == obj.get_line_of_binding
end
it "preserves __LINE__ across multiple calls to eval" do
obj = BindingSpecs::Demo.new(1)
bind = obj.get_binding
bind.eval("__LINE__").should == obj.get_line_of_binding
bind.eval("__LINE__").should == obj.get_line_of_binding
end
it "increments __LINE__ on each line of a multiline eval" do
obj = BindingSpecs::Demo.new(1)
bind = obj.get_binding
bind.eval("#foo\n__LINE__").should == obj.get_line_of_binding + 1
end
it "inherits __LINE__ from the enclosing scope even if the Binding is created with #send" do
obj = BindingSpecs::Demo.new(1)
bind, line = obj.get_binding_with_send_and_line
bind.eval("__LINE__").should == line
end
it "starts with a __LINE__ of 1 if a filename is passed" do
bind = BindingSpecs::Demo.new(1).get_binding
bind.eval("__LINE__", "(test)").should == 1
bind.eval("#foo\n__LINE__", "(test)").should == 2
end
it "starts with a __LINE__ from the third argument if passed" do
bind = BindingSpecs::Demo.new(1).get_binding
bind.eval("__LINE__", "(test)", 88).should == 88
bind.eval("#foo\n__LINE__", "(test)", 88).should == 89
end
it "inherits __FILE__ from the enclosing scope" do
obj = BindingSpecs::Demo.new(1)
bind = obj.get_binding
bind.eval("__FILE__").should == obj.get_file_of_binding
end
it "uses the __FILE__ that is passed in" do
bind = BindingSpecs::Demo.new(1).get_binding
bind.eval("__FILE__", "(test)").should == "(test)"
end
describe "with a file given" do describe "with a file given" do
it "does not store the filename permanently" do it "does not store the filename permanently" do
obj = BindingSpecs::Demo.new(1) obj = BindingSpecs::Demo.new(1)
@ -33,5 +81,15 @@ describe "Binding#eval" do
end end
end end
it "needs to be reviewed for spec completeness" it "with __method__ returns the method where the Binding was created" do
obj = BindingSpecs::Demo.new(1)
bind, meth = obj.get_binding_and_method
bind.eval("__method__").should == meth
end
it "with __method__ returns the method where the Binding was created, ignoring #send" do
obj = BindingSpecs::Demo.new(1)
bind, meth = obj.get_binding_with_send_and_method
bind.eval("__method__").should == meth
end
end end

View file

@ -25,6 +25,18 @@ module BindingSpecs
__FILE__ __FILE__
end end
def get_binding_with_send_and_line
[send(:binding), __LINE__]
end
def get_binding_and_method
[binding, :get_binding_and_method]
end
def get_binding_with_send_and_method
[send(:binding), :get_binding_with_send_and_method]
end
def get_empty_binding def get_empty_binding
binding binding
end end

View file

@ -1,46 +0,0 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
describe "Binding#eval" do
it "inherits __LINE__ from the enclosing scope" do
obj = BindingSpecs::Demo.new(1)
bind = obj.get_binding
bind.eval("__LINE__").should == obj.get_line_of_binding
end
it "preserves __LINE__ across multiple calls to eval" do
obj = BindingSpecs::Demo.new(1)
bind = obj.get_binding
bind.eval("__LINE__").should == obj.get_line_of_binding
bind.eval("__LINE__").should == obj.get_line_of_binding
end
it "increments __LINE__ on each line of a multiline eval" do
obj = BindingSpecs::Demo.new(1)
bind = obj.get_binding
bind.eval("#foo\n__LINE__").should == obj.get_line_of_binding + 1
end
it "starts with a __LINE__ of 1 if a filename is passed" do
bind = BindingSpecs::Demo.new(1).get_binding
bind.eval("__LINE__", "(test)").should == 1
bind.eval("#foo\n__LINE__", "(test)").should == 2
end
it "starts with a __LINE__ from the third argument if passed" do
bind = BindingSpecs::Demo.new(1).get_binding
bind.eval("__LINE__", "(test)", 88).should == 88
bind.eval("#foo\n__LINE__", "(test)", 88).should == 89
end
it "inherits __FILE__ from the enclosing scope" do
obj = BindingSpecs::Demo.new(1)
bind = obj.get_binding
bind.eval("__FILE__").should == obj.get_file_of_binding
end
it "uses the __FILE__ that is passed in" do
bind = BindingSpecs::Demo.new(1).get_binding
bind.eval("__FILE__", "(test)").should == "(test)"
end
end

View file

@ -32,5 +32,12 @@ describe "Enumerable#sort_by" do
b.sort_by{ |x| -x }.should == [3, 2, 1] b.sort_by{ |x| -x }.should == [3, 2, 1]
end end
it "calls #each to iterate over the elements to be sorted" do
b = EnumerableSpecs::Numerous.new( 1, 2, 3 )
b.should_receive(:each).once.and_yield(1).and_yield(2).and_yield(3)
b.should_not_receive :map
b.sort_by { |x| -x }.should == [3, 2, 1]
end
it_behaves_like :enumerable_enumeratorized_with_origin_size, :sort_by it_behaves_like :enumerable_enumeratorized_with_origin_size, :sort_by
end end

View file

@ -27,6 +27,10 @@ describe "IO.read" do
IO.read(@fname, {}).should == @contents IO.read(@fname, {}).should == @contents
end end
it "accepts a length, and empty options Hash" do
IO.read(@fname, 3, {}).should == @contents[0, 3]
end
it "accepts a length, offset, and empty options Hash" do it "accepts a length, offset, and empty options Hash" do
IO.read(@fname, 3, 0, {}).should == @contents[0, 3] IO.read(@fname, 3, 0, {}).should == @contents[0, 3]
end end

View file

@ -85,9 +85,9 @@ describe :io_write, shared: true do
@r.read.should == "foo" @r.read.should == "foo"
end end
it "raises Errno::EPIPE if the read end is closed" do it "raises Errno::EPIPE if the read end is closed and does not die from SIGPIPE" do
@r.close @r.close
-> { @w.send(@method, "foo") }.should raise_error(Errno::EPIPE, "Broken pipe") -> { @w.send(@method, "foo") }.should raise_error(Errno::EPIPE, /Broken pipe/)
end end
end end
end end

View file

@ -5,6 +5,13 @@ describe "Kernel#__dir__" do
__dir__.should == File.realpath(File.dirname(__FILE__)) __dir__.should == File.realpath(File.dirname(__FILE__))
end end
context "when used in eval with a given filename" do
it "returns File.dirname(filename)" do
eval("__dir__", nil, "foo.rb").should == "."
eval("__dir__", nil, "foo/bar.rb").should == "foo"
end
end
context "when used in eval with top level binding" do context "when used in eval with top level binding" do
it "returns the real name of the directory containing the currently-executing file" do it "returns the real name of the directory containing the currently-executing file" do
eval("__dir__", binding).should == File.realpath(File.dirname(__FILE__)) eval("__dir__", binding).should == File.realpath(File.dirname(__FILE__))

View file

@ -7,7 +7,7 @@ require_relative 'fixtures/classes'
autoload :KSAutoloadA, "autoload_a.rb" autoload :KSAutoloadA, "autoload_a.rb"
autoload :KSAutoloadB, fixture(__FILE__, "autoload_b.rb") autoload :KSAutoloadB, fixture(__FILE__, "autoload_b.rb")
autoload :KSAutoloadC, fixture(__FILE__, "autoload_c.rb") autoload :KSAutoloadCallsRequire, "main_autoload_not_exist.rb"
def check_autoload(const) def check_autoload(const)
autoload? const autoload? const
@ -42,10 +42,11 @@ describe "Kernel#autoload" do
KSAutoloadB.loaded.should == :ksautoload_b KSAutoloadB.loaded.should == :ksautoload_b
end end
it "does not call Kernel.require or Kernel.load to load the file" do it "calls main.require(path) to load the file" do
Kernel.should_not_receive(:require) main = TOPLEVEL_BINDING.eval("self")
Kernel.should_not_receive(:load) main.should_receive(:require).with("main_autoload_not_exist.rb")
KSAutoloadC.loaded.should == :ksautoload_c # The constant won't be defined since require is mocked to do nothing
-> { KSAutoloadCallsRequire }.should raise_error(NameError)
end end
it "can autoload in instance_eval" do it "can autoload in instance_eval" do

View file

@ -1,5 +0,0 @@
module KSAutoloadC
def self.loaded
:ksautoload_c
end
end

View file

@ -199,6 +199,46 @@ describe "Kernel#require_relative with a relative path" do
$LOADED_FEATURES.should include(@abs_path) $LOADED_FEATURES.should include(@abs_path)
end end
platform_is_not :windows do
describe "with symlinks" do
before :each do
@symlink_to_code_dir = tmp("codesymlink")
File.symlink(CODE_LOADING_DIR, @symlink_to_code_dir)
@symlink_basename = File.basename(@symlink_to_code_dir)
@requiring_file = tmp("requiring")
end
after :each do
rm_r @symlink_to_code_dir, @requiring_file
end
it "does not canonicalize the path and stores a path with symlinks" do
symlink_path = "#{@symlink_basename}/load_fixture.rb"
absolute_path = "#{tmp("")}#{symlink_path}"
canonical_path = "#{CODE_LOADING_DIR}/load_fixture.rb"
touch(@requiring_file) { |f|
f.puts "require_relative #{symlink_path.inspect}"
}
load(@requiring_file)
ScratchPad.recorded.should == [:loaded]
features = $LOADED_FEATURES.select { |path| path.end_with?('load_fixture.rb') }
features.should include(absolute_path)
features.should_not include(canonical_path)
end
it "stores the same path that __FILE__ returns in the required file" do
symlink_path = "#{@symlink_basename}/load_fixture_and__FILE__.rb"
touch(@requiring_file) { |f|
f.puts "require_relative #{symlink_path.inspect}"
}
load(@requiring_file)
loaded_feature = $LOADED_FEATURES.last
ScratchPad.recorded.should == [loaded_feature]
end
end
end
it "does not store the path if the load fails" do it "does not store the path if the load fails" do
saved_loaded_features = $LOADED_FEATURES.dup saved_loaded_features = $LOADED_FEATURES.dup
lambda { require_relative("#{@dir}/raise_fixture.rb") }.should raise_error(RuntimeError) lambda { require_relative("#{@dir}/raise_fixture.rb") }.should raise_error(RuntimeError)

View file

@ -17,7 +17,6 @@ describe "Kernel#require" do
end end
it_behaves_like :kernel_require_basic, :require, CodeLoadingSpecs::Method.new it_behaves_like :kernel_require_basic, :require, CodeLoadingSpecs::Method.new
it_behaves_like :kernel_require, :require, CodeLoadingSpecs::Method.new it_behaves_like :kernel_require, :require, CodeLoadingSpecs::Method.new
end end
@ -31,6 +30,5 @@ describe "Kernel.require" do
end end
it_behaves_like :kernel_require_basic, :require, Kernel it_behaves_like :kernel_require_basic, :require, Kernel
it_behaves_like :kernel_require, :require, Kernel it_behaves_like :kernel_require, :require, Kernel
end end

View file

@ -305,6 +305,80 @@ describe :kernel_require, shared: true do
$LOADED_FEATURES.should include(@path) $LOADED_FEATURES.should include(@path)
end end
platform_is_not :windows do
describe "with symlinks" do
before :each do
@symlink_to_code_dir = tmp("codesymlink")
File.symlink(CODE_LOADING_DIR, @symlink_to_code_dir)
$LOAD_PATH.delete(CODE_LOADING_DIR)
$LOAD_PATH.unshift(@symlink_to_code_dir)
end
after :each do
rm_r @symlink_to_code_dir
end
it "does not canonicalize the path and stores a path with symlinks" do
symlink_path = "#{@symlink_to_code_dir}/load_fixture.rb"
canonical_path = "#{CODE_LOADING_DIR}/load_fixture.rb"
@object.require(symlink_path).should be_true
ScratchPad.recorded.should == [:loaded]
features = $LOADED_FEATURES.select { |path| path.end_with?('load_fixture.rb') }
features.should include(symlink_path)
features.should_not include(canonical_path)
end
it "stores the same path that __FILE__ returns in the required file" do
symlink_path = "#{@symlink_to_code_dir}/load_fixture_and__FILE__.rb"
@object.require(symlink_path).should be_true
loaded_feature = $LOADED_FEATURES.last
ScratchPad.recorded.should == [loaded_feature]
end
end
describe "with symlinks in the required feature and $LOAD_PATH" do
before :each do
@dir = tmp("realdir")
mkdir_p @dir
@file = "#{@dir}/realfile.rb"
touch(@file) { |f| f.puts 'ScratchPad << __FILE__' }
@symlink_to_dir = tmp("symdir").freeze
File.symlink(@dir, @symlink_to_dir)
@symlink_to_file = "#{@dir}/symfile.rb"
File.symlink("realfile.rb", @symlink_to_file)
end
after :each do
rm_r @dir, @symlink_to_dir
end
ruby_version_is ""..."2.4.4" do
it "canonicalizes neither the entry in $LOAD_PATH nor the filename passed to #require" do
$LOAD_PATH.unshift(@symlink_to_dir)
@object.require("symfile").should be_true
loaded_feature = "#{@symlink_to_dir}/symfile.rb"
ScratchPad.recorded.should == [loaded_feature]
$".last.should == loaded_feature
$LOAD_PATH[0].should == @symlink_to_dir
end
end
ruby_version_is "2.4.4" do
it "canonicalizes the entry in $LOAD_PATH but not the filename passed to #require" do
$LOAD_PATH.unshift(@symlink_to_dir)
@object.require("symfile").should be_true
loaded_feature = "#{@dir}/symfile.rb"
ScratchPad.recorded.should == [loaded_feature]
$".last.should == loaded_feature
$LOAD_PATH[0].should == @symlink_to_dir
end
end
end
end
it "does not store the path if the load fails" do it "does not store the path if the load fails" do
$LOAD_PATH << CODE_LOADING_DIR $LOAD_PATH << CODE_LOADING_DIR
saved_loaded_features = $LOADED_FEATURES.dup saved_loaded_features = $LOADED_FEATURES.dup
@ -417,7 +491,7 @@ describe :kernel_require, shared: true do
$LOADED_FEATURES.should include(@path) $LOADED_FEATURES.should include(@path)
end end
it "canonicalizes non-unique absolute paths" do it "expands absolute paths containing .." do
path = File.join CODE_LOADING_DIR, "..", "code", "load_fixture.rb" path = File.join CODE_LOADING_DIR, "..", "code", "load_fixture.rb"
@object.require(path).should be_true @object.require(path).should be_true
$LOADED_FEATURES.should include(@path) $LOADED_FEATURES.should include(@path)

View file

@ -105,6 +105,14 @@ describe "Module#autoload" do
ModuleSpecs::Autoload::J.should == :autoload_j ModuleSpecs::Autoload::J.should == :autoload_j
end end
it "calls main.require(path) to load the file" do
ModuleSpecs::Autoload.autoload :ModuleAutoloadCallsRequire, "module_autoload_not_exist.rb"
main = TOPLEVEL_BINDING.eval("self")
main.should_receive(:require).with("module_autoload_not_exist.rb")
# The constant won't be defined since require is mocked to do nothing
-> { ModuleSpecs::Autoload::ModuleAutoloadCallsRequire }.should raise_error(NameError)
end
it "does not load the file if the file is manually required" do it "does not load the file if the file is manually required" do
filename = fixture(__FILE__, "autoload_k.rb") filename = fixture(__FILE__, "autoload_k.rb")
ModuleSpecs::Autoload.autoload :KHash, filename ModuleSpecs::Autoload.autoload :KHash, filename
@ -158,28 +166,169 @@ describe "Module#autoload" do
ModuleSpecs::Autoload.use_ex1.should == :good ModuleSpecs::Autoload.use_ex1.should == :good
end end
it "does not load the file when referring to the constant in defined?" do describe "interacting with defined?" do
module ModuleSpecs::Autoload::Q it "does not load the file when referring to the constant in defined?" do
autoload :R, fixture(__FILE__, "autoload.rb") module ModuleSpecs::Autoload::Dog
defined?(R).should == "constant" autoload :R, fixture(__FILE__, "autoload_exception.rb")
end
defined?(ModuleSpecs::Autoload::Dog::R).should == "constant"
ScratchPad.recorded.should be_nil
ModuleSpecs::Autoload::Dog.should have_constant(:R)
end
it "loads an autoloaded parent when referencing a nested constant" do
module ModuleSpecs::Autoload
autoload :GoodParent, fixture(__FILE__, "autoload_nested.rb")
end
defined?(ModuleSpecs::Autoload::GoodParent::Nested).should == 'constant'
ScratchPad.recorded.should == :loaded
ModuleSpecs::Autoload.send(:remove_const, :GoodParent)
end
it "returns nil when it fails to load an autoloaded parent when referencing a nested constant" do
module ModuleSpecs::Autoload
autoload :BadParent, fixture(__FILE__, "autoload_exception.rb")
end
defined?(ModuleSpecs::Autoload::BadParent::Nested).should be_nil
ScratchPad.recorded.should == :exception
end end
ModuleSpecs::Autoload::Q.should have_constant(:R)
end end
it "does not remove the constant from the constant table if load fails" do describe "during the autoload before the constant is assigned" do
before :each do
@path = fixture(__FILE__, "autoload_during_autoload.rb")
ModuleSpecs::Autoload.autoload :DuringAutoload, @path
raise unless ModuleSpecs::Autoload.autoload?(:DuringAutoload) == @path
end
after :each do
ModuleSpecs::Autoload.send(:remove_const, :DuringAutoload)
end
def check_before_during_thread_after(&check)
before = check.call
to_autoload_thread, from_autoload_thread = Queue.new, Queue.new
ScratchPad.record -> {
from_autoload_thread.push check.call
to_autoload_thread.pop
}
t = Thread.new {
in_loading_thread = from_autoload_thread.pop
in_other_thread = check.call
to_autoload_thread.push :done
[in_loading_thread, in_other_thread]
}
in_loading_thread, in_other_thread = nil
begin
ModuleSpecs::Autoload::DuringAutoload
ensure
in_loading_thread, in_other_thread = t.value
end
after = check.call
[before, in_loading_thread, in_other_thread, after]
end
it "returns nil in autoload thread and 'constant' otherwise for defined?" do
results = check_before_during_thread_after {
defined?(ModuleSpecs::Autoload::DuringAutoload)
}
results.should == ['constant', nil, 'constant', 'constant']
end
it "keeps the constant in Module#constants" do
results = check_before_during_thread_after {
ModuleSpecs::Autoload.constants(false).include?(:DuringAutoload)
}
results.should == [true, true, true, true]
end
it "returns false in autoload thread and true otherwise for Module#const_defined?" do
results = check_before_during_thread_after {
ModuleSpecs::Autoload.const_defined?(:DuringAutoload, false)
}
results.should == [true, false, true, true]
end
it "returns nil in autoload thread and returns the path in other threads for Module#autoload?" do
results = check_before_during_thread_after {
ModuleSpecs::Autoload.autoload?(:DuringAutoload)
}
results.should == [@path, nil, @path, nil]
end
end
it "does not remove the constant from Module#constants if load fails and keeps it as an autoload" do
ModuleSpecs::Autoload.autoload :Fail, @non_existent ModuleSpecs::Autoload.autoload :Fail, @non_existent
ModuleSpecs::Autoload.const_defined?(:Fail).should == true
ModuleSpecs::Autoload.should have_constant(:Fail) ModuleSpecs::Autoload.should have_constant(:Fail)
ModuleSpecs::Autoload.autoload?(:Fail).should == @non_existent
lambda { ModuleSpecs::Autoload::Fail }.should raise_error(LoadError) lambda { ModuleSpecs::Autoload::Fail }.should raise_error(LoadError)
ModuleSpecs::Autoload.should have_constant(:Fail) ModuleSpecs::Autoload.should have_constant(:Fail)
ModuleSpecs::Autoload.const_defined?(:Fail).should == true
ModuleSpecs::Autoload.autoload?(:Fail).should == @non_existent
lambda { ModuleSpecs::Autoload::Fail }.should raise_error(LoadError)
end end
it "does not remove the constant from the constant table if the loaded files does not define it" do it "does not remove the constant from Module#constants if load raises a RuntimeError and keeps it as an autoload" do
ModuleSpecs::Autoload.autoload :O, fixture(__FILE__, "autoload_o.rb") path = fixture(__FILE__, "autoload_raise.rb")
ScratchPad.record []
ModuleSpecs::Autoload.autoload :Raise, path
ModuleSpecs::Autoload.const_defined?(:Raise).should == true
ModuleSpecs::Autoload.should have_constant(:Raise)
ModuleSpecs::Autoload.autoload?(:Raise).should == path
lambda { ModuleSpecs::Autoload::Raise }.should raise_error(RuntimeError)
ScratchPad.recorded.should == [:raise]
ModuleSpecs::Autoload.should have_constant(:Raise)
ModuleSpecs::Autoload.const_defined?(:Raise).should == true
ModuleSpecs::Autoload.autoload?(:Raise).should == path
lambda { ModuleSpecs::Autoload::Raise }.should raise_error(RuntimeError)
ScratchPad.recorded.should == [:raise, :raise]
end
it "does not remove the constant from Module#constants if the loaded file does not define it, but leaves it as 'undefined'" do
path = fixture(__FILE__, "autoload_o.rb")
ScratchPad.record []
ModuleSpecs::Autoload.autoload :O, path
ModuleSpecs::Autoload.const_defined?(:O).should == true
ModuleSpecs::Autoload.should have_constant(:O) ModuleSpecs::Autoload.should have_constant(:O)
ModuleSpecs::Autoload.autoload?(:O).should == path
lambda { ModuleSpecs::Autoload::O }.should raise_error(NameError) lambda { ModuleSpecs::Autoload::O }.should raise_error(NameError)
ModuleSpecs::Autoload.should have_constant(:O) ModuleSpecs::Autoload.should have_constant(:O)
ModuleSpecs::Autoload.const_defined?(:O).should == false
ModuleSpecs::Autoload.autoload?(:O).should == nil
-> { ModuleSpecs::Autoload.const_get(:O) }.should raise_error(NameError)
end
it "does not try to load the file again if the loaded file did not define the constant" do
path = fixture(__FILE__, "autoload_o.rb")
ScratchPad.record []
ModuleSpecs::Autoload.autoload :NotDefinedByFile, path
-> { ModuleSpecs::Autoload::NotDefinedByFile }.should raise_error(NameError)
ScratchPad.recorded.should == [:loaded]
-> { ModuleSpecs::Autoload::NotDefinedByFile }.should raise_error(NameError)
ScratchPad.recorded.should == [:loaded]
Thread.new {
-> { ModuleSpecs::Autoload::NotDefinedByFile }.should raise_error(NameError)
}.join
ScratchPad.recorded.should == [:loaded]
end end
it "returns 'constant' on referring the constant with defined?()" do it "returns 'constant' on referring the constant with defined?()" do
@ -216,7 +365,6 @@ describe "Module#autoload" do
end end
it "loads the file that defines subclass XX::YY < YY and YY is a top level constant" do it "loads the file that defines subclass XX::YY < YY and YY is a top level constant" do
module ModuleSpecs::Autoload::XX module ModuleSpecs::Autoload::XX
autoload :YY, fixture(__FILE__, "autoload_subclass.rb") autoload :YY, fixture(__FILE__, "autoload_subclass.rb")
end end
@ -224,30 +372,130 @@ describe "Module#autoload" do
ModuleSpecs::Autoload::XX::YY.superclass.should == YY ModuleSpecs::Autoload::XX::YY.superclass.should == YY
end end
describe "after autoloading searches for the constant like the original lookup" do
it "in lexical scopes if both declared and defined in parent" do
module ModuleSpecs::Autoload
ScratchPad.record -> {
DeclaredAndDefinedInParent = :declared_and_defined_in_parent
}
autoload :DeclaredAndDefinedInParent, fixture(__FILE__, "autoload_callback.rb")
class LexicalScope
DeclaredAndDefinedInParent.should == :declared_and_defined_in_parent
it "looks up the constant in the scope where it is referred" do # The constant is really in Autoload, not Autoload::LexicalScope
module ModuleSpecs self.should_not have_constant(:DeclaredAndDefinedInParent)
module Autoload -> { const_get(:DeclaredAndDefinedInParent) }.should raise_error(NameError)
autoload :QQ, fixture(__FILE__, "autoload_scope.rb") end
class PP DeclaredAndDefinedInParent.should == :declared_and_defined_in_parent
QQ.new.should be_kind_of(ModuleSpecs::Autoload::PP::QQ) end
end
it "in lexical scopes if declared in parent and defined in current" do
module ModuleSpecs::Autoload
ScratchPad.record -> {
class LexicalScope
DeclaredInParentDefinedInCurrent = :declared_in_parent_defined_in_current
end
}
autoload :DeclaredInParentDefinedInCurrent, fixture(__FILE__, "autoload_callback.rb")
class LexicalScope
DeclaredInParentDefinedInCurrent.should == :declared_in_parent_defined_in_current
LexicalScope::DeclaredInParentDefinedInCurrent.should == :declared_in_parent_defined_in_current
end
# Basically, the parent autoload constant remains in a "undefined" state
self.autoload?(:DeclaredInParentDefinedInCurrent).should == nil
const_defined?(:DeclaredInParentDefinedInCurrent).should == false
self.should have_constant(:DeclaredInParentDefinedInCurrent)
-> { DeclaredInParentDefinedInCurrent }.should raise_error(NameError)
ModuleSpecs::Autoload::LexicalScope.send(:remove_const, :DeclaredInParentDefinedInCurrent)
end
end
it "and fails when finding the undefined autoload constant in the the current scope when declared in current and defined in parent" do
module ModuleSpecs::Autoload
ScratchPad.record -> {
DeclaredInCurrentDefinedInParent = :declared_in_current_defined_in_parent
}
class LexicalScope
autoload :DeclaredInCurrentDefinedInParent, fixture(__FILE__, "autoload_callback.rb")
-> { DeclaredInCurrentDefinedInParent }.should raise_error(NameError)
# Basically, the autoload constant remains in a "undefined" state
self.autoload?(:DeclaredInCurrentDefinedInParent).should == nil
const_defined?(:DeclaredInCurrentDefinedInParent).should == false
self.should have_constant(:DeclaredInCurrentDefinedInParent)
-> { const_get(:DeclaredInCurrentDefinedInParent) }.should raise_error(NameError)
end
DeclaredInCurrentDefinedInParent.should == :declared_in_current_defined_in_parent
end
end
it "in the included modules" do
module ModuleSpecs::Autoload
ScratchPad.record -> {
module DefinedInIncludedModule
Incl = :defined_in_included_module
end
include DefinedInIncludedModule
}
autoload :Incl, fixture(__FILE__, "autoload_callback.rb")
Incl.should == :defined_in_included_module
end
end
it "in the included modules of the superclass" do
module ModuleSpecs::Autoload
class LookupAfterAutoloadSuper
end
class LookupAfterAutoloadChild < LookupAfterAutoloadSuper
end
ScratchPad.record -> {
module DefinedInSuperclassIncludedModule
InclS = :defined_in_superclass_included_module
end
LookupAfterAutoloadSuper.include DefinedInSuperclassIncludedModule
}
class LookupAfterAutoloadChild
autoload :InclS, fixture(__FILE__, "autoload_callback.rb")
InclS.should == :defined_in_superclass_included_module
end end
end end
end end
end
it "looks up the constant when in a meta class scope" do it "in the prepended modules" do
module ModuleSpecs module ModuleSpecs::Autoload
module Autoload ScratchPad.record -> {
autoload :R, fixture(__FILE__, "autoload_r.rb") module DefinedInPrependedModule
Prep = :defined_in_prepended_module
end
include DefinedInPrependedModule
}
autoload :Prep, fixture(__FILE__, "autoload_callback.rb")
Prep.should == :defined_in_prepended_module
end
end
it "in a meta class scope" do
module ModuleSpecs::Autoload
ScratchPad.record -> {
class MetaScope
end
}
autoload :MetaScope, fixture(__FILE__, "autoload_callback.rb")
class << self class << self
def r def r
R.new MetaScope.new
end end
end end
end end
ModuleSpecs::Autoload.r.should be_kind_of(ModuleSpecs::Autoload::MetaScope)
end end
ModuleSpecs::Autoload.r.should be_kind_of(ModuleSpecs::Autoload::R)
end end
# [ruby-core:19127] [ruby-core:29941] # [ruby-core:19127] [ruby-core:29941]
@ -266,6 +514,21 @@ describe "Module#autoload" do
ModuleSpecs::Autoload::W.send(:remove_const, :Y) ModuleSpecs::Autoload::W.send(:remove_const, :Y)
end end
it "does not call #require a second time and does not warn if already loading the same feature with #require" do
main = TOPLEVEL_BINDING.eval("self")
main.should_not_receive(:require)
module ModuleSpecs::Autoload
autoload :AutoloadDuringRequire, fixture(__FILE__, "autoload_during_require.rb")
end
-> {
$VERBOSE = true
Kernel.require fixture(__FILE__, "autoload_during_require.rb")
}.should_not complain
ModuleSpecs::Autoload::AutoloadDuringRequire.should be_kind_of(Class)
end
it "calls #to_path on non-string filenames" do it "calls #to_path on non-string filenames" do
p = mock('path') p = mock('path')
p.should_receive(:to_path).and_return @non_existent p.should_receive(:to_path).and_return @non_existent

View file

@ -1,5 +1,6 @@
require_relative '../../spec_helper' require_relative '../../spec_helper'
require_relative '../../fixtures/constants' require_relative '../../fixtures/constants'
require_relative 'fixtures/constants_autoload'
describe "Module#const_get" do describe "Module#const_get" do
it "accepts a String or Symbol name" do it "accepts a String or Symbol name" do
@ -95,6 +96,10 @@ describe "Module#const_get" do
ConstantSpecs.const_get("ClassA::CS_CONST10").should == :const10_10 ConstantSpecs.const_get("ClassA::CS_CONST10").should == :const10_10
end end
it "raises a NameError if the name includes two successive scope separators" do
lambda { ConstantSpecs.const_get("ClassA::::CS_CONST10") }.should raise_error(NameError)
end
it "raises a NameError if only '::' is passed" do it "raises a NameError if only '::' is passed" do
lambda { ConstantSpecs.const_get("::") }.should raise_error(NameError) lambda { ConstantSpecs.const_get("::") }.should raise_error(NameError)
end end
@ -111,6 +116,22 @@ describe "Module#const_get" do
ConstantSpecs.const_get(:CS_PRIVATE).should == :cs_private ConstantSpecs.const_get(:CS_PRIVATE).should == :cs_private
end end
it 'does autoload a constant' do
Object.const_get('CSAutoloadA').name.should == 'CSAutoloadA'
end
it 'does autoload a constant with a toplevel scope qualifier' do
Object.const_get('::CSAutoloadB').name.should == 'CSAutoloadB'
end
it 'does autoload a module and resolve a constant within' do
Object.const_get('CSAutoloadC::CONST').should == 7
end
it 'does autoload a non-toplevel module' do
Object.const_get('CSAutoloadD::InnerModule').name.should == 'CSAutoloadD::InnerModule'
end
describe "with statically assigned constants" do describe "with statically assigned constants" do
it "searches the immediate class or module first" do it "searches the immediate class or module first" do
ConstantSpecs::ClassA.const_get(:CS_CONST10).should == :const10_10 ConstantSpecs::ClassA.const_get(:CS_CONST10).should == :const10_10

View file

@ -0,0 +1,2 @@
block = ScratchPad.recorded
block.call

View file

@ -0,0 +1,7 @@
block = ScratchPad.recorded
ScratchPad.record(block.call)
module ModuleSpecs::Autoload
class DuringAutoload
end
end

View file

@ -0,0 +1,4 @@
module ModuleSpecs::Autoload
class AutoloadDuringRequire
end
end

View file

@ -0,0 +1,3 @@
ScratchPad.record(:exception)
raise 'intentional error to test failure conditions during autoloading'

View file

@ -0,0 +1,8 @@
module ModuleSpecs::Autoload
module GoodParent
class Nested
end
end
end
ScratchPad.record(:loaded)

View file

@ -1 +1,2 @@
# does not define ModuleSpecs::Autoload::O # does not define ModuleSpecs::Autoload::O
ScratchPad << :loaded

View file

@ -0,0 +1,2 @@
ScratchPad << :raise
raise "exception during autoload"

View file

@ -1,8 +0,0 @@
module ModuleSpecs
module Autoload
class PP
class QQ
end
end
end
end

View file

@ -0,0 +1,6 @@
autoload :CSAutoloadA, fixture(__FILE__, 'constants_autoload_a.rb')
autoload :CSAutoloadB, fixture(__FILE__, 'constants_autoload_b.rb')
autoload :CSAutoloadC, fixture(__FILE__, 'constants_autoload_c.rb')
module CSAutoloadD
autoload :InnerModule, fixture(__FILE__, 'constants_autoload_d.rb')
end

View file

@ -0,0 +1,2 @@
module CSAutoloadA
end

View file

@ -0,0 +1,2 @@
module CSAutoloadB
end

View file

@ -0,0 +1,3 @@
module CSAutoloadC
CONST = 7
end

View file

@ -0,0 +1,4 @@
module CSAutoloadD
module InnerModule
end
end

View file

@ -7,4 +7,12 @@ describe "Module#initialize_copy" do
end end
mod.dup.methods(false).should == [:hello] mod.dup.methods(false).should == [:hello]
end end
# jruby/jruby#5245, https://bugs.ruby-lang.org/issues/3461
it "should produce a duped module with inspectable class methods" do
mod = Module.new
def mod.hello
end
mod.dup.method(:hello).inspect.should =~ /Module.*hello/
end
end end

View file

@ -0,0 +1,8 @@
reserved_signals = ARGV
(Signal.list.keys - reserved_signals).each do |signal|
Signal.trap(signal, -> {})
Signal.trap(signal, "DEFAULT")
end
puts "OK"

View file

@ -115,6 +115,49 @@ platform_is_not :windows do
end end
describe "Signal.trap" do describe "Signal.trap" do
cannot_be_trapped = %w[KILL STOP] # See man 2 signal
reserved_signals = %w[VTALRM]
if PlatformGuard.implementation?(:ruby)
reserved_signals += %w[SEGV ILL FPE BUS]
end
if PlatformGuard.implementation?(:truffleruby)
if !TruffleRuby.native?
reserved_signals += %w[SEGV ILL FPE USR1 QUIT]
end
end
if PlatformGuard.implementation?(:jruby)
reserved_signals += %w[SEGV ILL FPE BUS USR1 QUIT]
end
cannot_be_trapped.each do |signal|
it "raises ArgumentError or Errno::EINVAL for SIG#{signal}" do
-> {
trap(signal, -> {})
}.should raise_error(StandardError) { |e|
[ArgumentError, Errno::EINVAL].should include(e.class)
e.message.should =~ /Invalid argument|Signal already used by VM or OS/
}
end
end
reserved_signals.each do |signal|
it "raises ArgumentError for reserved signal SIG#{signal}" do
-> {
trap(signal, -> {})
}.should raise_error(ArgumentError, /can't trap reserved signal|Signal already used by VM or OS/)
end
end
it "allows to register a handler for all known signals, except reserved signals" do
excluded = cannot_be_trapped + reserved_signals
out = ruby_exe(fixture(__FILE__, "trap_all.rb"), args: [*excluded, "2>&1"])
out.should == "OK\n"
$?.exitstatus.should == 0
end
it "returns SYSTEM_DEFAULT if passed DEFAULT and no handler was ever set" do it "returns SYSTEM_DEFAULT if passed DEFAULT and no handler was ever set" do
Signal.trap("PROF", "DEFAULT").should == "SYSTEM_DEFAULT" Signal.trap("PROF", "DEFAULT").should == "SYSTEM_DEFAULT"
end end

View file

@ -6,6 +6,26 @@ with_feature :encoding do
"abc".force_encoding('shift_jis').encoding.should == Encoding::Shift_JIS "abc".force_encoding('shift_jis').encoding.should == Encoding::Shift_JIS
end end
describe "with a special encoding name" do
before :each do
@original_encoding = Encoding.default_internal
end
after :each do
Encoding.default_internal = @original_encoding
end
it "accepts valid special encoding names" do
Encoding.default_internal = "US-ASCII"
"abc".force_encoding("internal").encoding.should == Encoding::US_ASCII
end
it "defaults to ASCII-8BIT if special encoding name is not set" do
Encoding.default_internal = nil
"abc".force_encoding("internal").encoding.should == Encoding::ASCII_8BIT
end
end
it "accepts an Encoding instance" do it "accepts an Encoding instance" do
"abc".force_encoding(Encoding::SHIFT_JIS).encoding.should == Encoding::Shift_JIS "abc".force_encoding(Encoding::SHIFT_JIS).encoding.should == Encoding::Shift_JIS
end end

View file

@ -9,4 +9,42 @@ describe 'Thread::Backtrace::Location#absolute_path' do
it 'returns the absolute path of the call frame' do it 'returns the absolute path of the call frame' do
@frame.absolute_path.should == File.realpath(__FILE__) @frame.absolute_path.should == File.realpath(__FILE__)
end end
context "when used in eval with a given filename" do
it "returns filename" do
code = "caller_locations(0)[0].absolute_path"
eval(code, nil, "foo.rb").should == "foo.rb"
eval(code, nil, "foo/bar.rb").should == "foo/bar.rb"
end
end
platform_is_not :windows do
before :each do
@file = fixture(__FILE__, "absolute_path.rb")
@symlink = tmp("symlink.rb")
File.symlink(@file, @symlink)
ScratchPad.record []
end
after :each do
rm_r @symlink
end
it "returns a canonical path without symlinks, even when __FILE__ does not" do
realpath = File.realpath(@symlink)
realpath.should_not == @symlink
load @symlink
ScratchPad.recorded.should == [@symlink, realpath]
end
it "returns a canonical path without symlinks, even when __FILE__ is removed" do
realpath = File.realpath(@symlink)
realpath.should_not == @symlink
ScratchPad << -> { rm_r(@symlink) }
load @symlink
ScratchPad.recorded.should == [@symlink, realpath]
end
end
end end

View file

@ -0,0 +1,4 @@
action = ScratchPad.recorded.pop
ScratchPad << __FILE__
action.call if action
ScratchPad << caller_locations(0)[0].absolute_path

View file

@ -93,7 +93,7 @@ describe "Time#localtime" do
it "does nothing if already in a local time zone" do it "does nothing if already in a local time zone" do
time = with_timezone("America/New_York") do time = with_timezone("America/New_York") do
break Time.new(2005, 2, 27, 22, 50, 0) Time.new(2005, 2, 27, 22, 50, 0)
end end
zone = time.zone zone = time.zone

View file

@ -0,0 +1 @@
ScratchPad << __FILE__

View file

@ -36,6 +36,13 @@ describe "Array literals" do
[1, *nil, 3].should == [1, 3] [1, *nil, 3].should == [1, 3]
[*nil, *nil, *nil].should == [] [*nil, *nil, *nil].should == []
end end
it "evaluates each argument exactly once" do
se = ArraySpec::SideEffect.new
se.array_result(true)
se.array_result(false)
se.call_count.should == 4
end
end end
describe "Bareword array literal" do describe "Bareword array literal" do

View file

@ -458,16 +458,17 @@ describe "Module#private_constant marked constants" do
lambda {mod::Foo}.should raise_error(NameError) lambda {mod::Foo}.should raise_error(NameError)
end end
it "sends #const_missing to the original class or module" do ruby_version_is "2.6" do
mod = Module.new it "sends #const_missing to the original class or module" do
mod.const_set :Foo, true mod = Module.new
mod.send :private_constant, :Foo mod.const_set :Foo, true
def mod.const_missing(name) mod.send :private_constant, :Foo
@const_missing_arg = name def mod.const_missing(name)
name == :Foo ? name : super name == :Foo ? name : super
end end
mod::Foo.should == :Foo mod::Foo.should == :Foo
end
end end
describe "in a module" do describe "in a module" do

View file

@ -8,4 +8,25 @@ module ArraySpec
[a, b, c, d] [a, b, c, d]
end end
end end
class SideEffect
def initialize()
@call_count = 0
end
attr_reader :call_count
def array_result(a_number)
[result(a_number), result(a_number)]
end
def result(a_number)
@call_count += 1
if a_number
1
else
:thing
end
end
end
end end

View file

@ -185,6 +185,19 @@ describe 'Optional variable assignments' do
describe 'using a #[]' do describe 'using a #[]' do
before do before do
@a = {} @a = {}
klass = Class.new do
def [](k)
@hash ||= {}
@hash[k]
end
def []=(k, v)
@hash ||= {}
@hash[k] = v
7
end
end
@b = klass.new
end end
it 'leaves new variable unassigned' do it 'leaves new variable unassigned' do
@ -226,6 +239,15 @@ describe 'Optional variable assignments' do
@a[:k].should == 20 @a[:k].should == 20
end end
it 'returns the assigned value, not the result of the []= method with ||=' do
(@b[:k] ||= 12).should == 12
end
it 'returns the assigned value, not the result of the []= method with +=' do
@b[:k] = 17
(@b[:k] += 12).should == 29
end
end end
end end

View file

@ -0,0 +1,37 @@
require_relative '../../spec_helper'
require 'date'
describe "Date.iso8601" do
it "parses YYYY-MM-DD into a Date object" do
d = Date.iso8601("2018-01-01")
d.should == Date.civil(2018, 1, 1)
end
it "parses YYYYMMDD into a Date object" do
d = Date.iso8601("20180715")
d.should == Date.civil(2018, 7, 15)
end
it "parses a negative Date" do
d = Date.iso8601("-4712-01-01")
d.should == Date.civil(-4712, 1, 1)
end
it "parses a Symbol into a Date object" do
d = Date.iso8601(:'2015-10-15')
d.should == Date.civil(2015, 10, 15)
end
it "parses a StringSubclass into a Date object" do
d = Date.iso8601(Class.new(String).new("-4712-01-01"))
d.should == Date.civil(-4712, 1, 1)
end
it "raises an ArgumentError when passed a Symbol without a valid Date" do
lambda { Date.iso8601(:test) }.should raise_error(ArgumentError)
end
it "raises a TypeError when passed an Object" do
lambda { Date.iso8601(Object.new) }.should raise_error(TypeError)
end
end

View file

@ -64,6 +64,11 @@ describe "Date#parse" do
d = Date.parse("19101101") d = Date.parse("19101101")
d.should == Date.civil(1910, 11, 1) d.should == Date.civil(1910, 11, 1)
end end
it "raises a TypeError trying to parse non-String-like object" do
lambda { Date.parse(1) }.should raise_error(TypeError)
lambda { Date.parse(:invalid) }.should raise_error(TypeError)
end
end end
describe "Date#parse with '.' separator" do describe "Date#parse with '.' separator" do

View file

@ -1,5 +1,4 @@
require_relative '../../../spec_helper' require_relative '../spec_helper'
require 'socket'
describe "Addrinfo#afamily" do describe "Addrinfo#afamily" do
describe "for an ipv4 socket" do describe "for an ipv4 socket" do
@ -24,7 +23,7 @@ describe "Addrinfo#afamily" do
end end
end end
platform_is_not :windows do with_feature :unix_socket do
describe "for a unix socket" do describe "for a unix socket" do
before :each do before :each do
@addrinfo = Addrinfo.unix("/tmp/sock") @addrinfo = Addrinfo.unix("/tmp/sock")

View file

@ -1,6 +1,5 @@
require_relative '../../../spec_helper' require_relative '../spec_helper'
require_relative '../fixtures/classes' require_relative '../fixtures/classes'
require 'socket'
describe "Addrinfo#bind" do describe "Addrinfo#bind" do

View file

@ -1,6 +1,5 @@
require_relative '../../../spec_helper' require_relative '../spec_helper'
require_relative '../fixtures/classes' require_relative '../fixtures/classes'
require 'socket'
describe "Addrinfo#canonname" do describe "Addrinfo#canonname" do
@ -16,4 +15,13 @@ describe "Addrinfo#canonname" do
canonname.should == nil canonname.should == nil
end end
end end
describe 'when the canonical name is not available' do
it 'returns nil' do
addr = Addrinfo.new(Socket.sockaddr_in(0, '127.0.0.1'))
addr.canonname.should be_nil
end
end
end end

View file

@ -0,0 +1,75 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
describe 'Addrinfo#connect_from' do
SocketSpecs.each_ip_protocol do |family, ip_address|
before do
@server = TCPServer.new(ip_address, 0)
@port = @server.connect_address.ip_port
@addr = Addrinfo.tcp(ip_address, @port)
end
after do
@socket.close if @socket
@server.close
end
describe 'using separate arguments' do
it 'returns a Socket when no block is given' do
@socket = @addr.connect_from(ip_address, 0)
@socket.should be_an_instance_of(Socket)
end
it 'yields the Socket when a block is given' do
@addr.connect_from(ip_address, 0) do |socket|
socket.should be_an_instance_of(Socket)
end
end
it 'treats the last argument as a set of options if it is a Hash' do
@socket = @addr.connect_from(ip_address, 0, timeout: 2)
@socket.should be_an_instance_of(Socket)
end
it 'binds the socket to the local address' do
@socket = @addr.connect_from(ip_address, 0)
@socket.local_address.ip_address.should == ip_address
@socket.local_address.ip_port.should > 0
@socket.local_address.ip_port.should_not == @port
end
end
describe 'using an Addrinfo as the 1st argument' do
before do
@from_addr = Addrinfo.tcp(ip_address, 0)
end
it 'returns a Socket when no block is given' do
@socket = @addr.connect_from(@from_addr)
@socket.should be_an_instance_of(Socket)
end
it 'yields the Socket when a block is given' do
@addr.connect_from(@from_addr) do |socket|
socket.should be_an_instance_of(Socket)
end
end
it 'treats the last argument as a set of options if it is a Hash' do
@socket = @addr.connect_from(@from_addr, timeout: 2)
@socket.should be_an_instance_of(Socket)
end
it 'binds the socket to the local address' do
@socket = @addr.connect_from(@from_addr)
@socket.local_address.ip_address.should == ip_address
@socket.local_address.ip_port.should > 0
@socket.local_address.ip_port.should_not == @port
end
end
end
end

View file

@ -0,0 +1,35 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
describe 'Addrinfo#connect' do
SocketSpecs.each_ip_protocol do |family, ip_address|
before do
@server = TCPServer.new(ip_address, 0)
@port = @server.connect_address.ip_port
end
after do
@socket.close if @socket
@server.close
end
it 'returns a Socket when no block is given' do
addr = Addrinfo.tcp(ip_address, @port)
@socket = addr.connect
@socket.should be_an_instance_of(Socket)
end
it 'yields a Socket when a block is given' do
addr = Addrinfo.tcp(ip_address, @port)
addr.connect do |socket|
socket.should be_an_instance_of(Socket)
end
end
it 'accepts a Hash of options' do
addr = Addrinfo.tcp(ip_address, @port)
@socket = addr.connect(timeout: 2)
@socket.should be_an_instance_of(Socket)
end
end
end

View file

@ -0,0 +1,75 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
describe 'Addrinfo#connect_to' do
SocketSpecs.each_ip_protocol do |family, ip_address|
before do
@server = TCPServer.new(ip_address, 0)
@port = @server.connect_address.ip_port
@addr = Addrinfo.tcp(ip_address, 0)
end
after do
@socket.close if @socket
@server.close
end
describe 'using separate arguments' do
it 'returns a Socket when no block is given' do
@socket = @addr.connect_to(ip_address, @port)
@socket.should be_an_instance_of(Socket)
end
it 'yields the Socket when a block is given' do
@addr.connect_to(ip_address, @port) do |socket|
socket.should be_an_instance_of(Socket)
end
end
it 'treats the last argument as a set of options if it is a Hash' do
@socket = @addr.connect_to(ip_address, @port, timeout: 2)
@socket.should be_an_instance_of(Socket)
end
it 'binds the Addrinfo to the local address' do
@socket = @addr.connect_to(ip_address, @port)
@socket.local_address.ip_address.should == ip_address
@socket.local_address.ip_port.should > 0
@socket.local_address.ip_port.should_not == @port
end
end
describe 'using an Addrinfo as the 1st argument' do
before do
@to_addr = Addrinfo.tcp(ip_address, @port)
end
it 'returns a Socket when no block is given' do
@socket = @addr.connect_to(@to_addr)
@socket.should be_an_instance_of(Socket)
end
it 'yields the Socket when a block is given' do
@addr.connect_to(@to_addr) do |socket|
socket.should be_an_instance_of(Socket)
end
end
it 'treats the last argument as a set of options if it is a Hash' do
@socket = @addr.connect_to(@to_addr, timeout: 2)
@socket.should be_an_instance_of(Socket)
end
it 'binds the socket to the local address' do
@socket = @addr.connect_to(@to_addr)
@socket.local_address.ip_address.should == ip_address
@socket.local_address.ip_port.should > 0
@socket.local_address.ip_port.should_not == @port
end
end
end
end

View file

@ -0,0 +1,115 @@
require_relative '../spec_helper'
describe 'Addrinfo#family_addrinfo' do
it 'raises ArgumentError if no arguments are given' do
addr = Addrinfo.tcp('127.0.0.1', 0)
lambda { addr.family_addrinfo }.should raise_error(ArgumentError)
end
describe 'using multiple arguments' do
describe 'with an IP Addrinfo' do
before do
@source = Addrinfo.tcp('127.0.0.1', 0)
end
it 'raises ArgumentError if only 1 argument is given' do
lambda { @source.family_addrinfo('127.0.0.1') }.should raise_error(ArgumentError)
end
it 'raises ArgumentError if more than 2 arguments are given' do
lambda { @source.family_addrinfo('127.0.0.1', 0, 666) }.should raise_error(ArgumentError)
end
it 'returns an Addrinfo when a host and port are given' do
addr = @source.family_addrinfo('127.0.0.1', 0)
addr.should be_an_instance_of(Addrinfo)
end
describe 'the returned Addrinfo' do
before do
@addr = @source.family_addrinfo('127.0.0.1', 0)
end
it 'uses the same address family as the source Addrinfo' do
@addr.afamily.should == @source.afamily
end
it 'uses the same protocol family as the source Addrinfo' do
@addr.pfamily.should == @source.pfamily
end
it 'uses the same socket type as the source Addrinfo' do
@addr.socktype.should == @source.socktype
end
it 'uses the same protocol as the source Addrinfo' do
@addr.protocol.should == @source.protocol
end
end
end
with_feature :unix_socket do
describe 'with a UNIX Addrinfo' do
before do
@source = Addrinfo.unix('cats')
end
it 'raises ArgumentError if more than 1 argument is given' do
lambda { @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')
addr.should be_an_instance_of(Addrinfo)
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 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
end
end
end
end
describe 'using an Addrinfo as the 1st argument' do
before do
@source = Addrinfo.tcp('127.0.0.1', 0)
end
it 'returns the input Addrinfo' do
input = Addrinfo.tcp('127.0.0.2', 0)
@source.family_addrinfo(input).should == input
end
it 'raises ArgumentError if more than 1 argument is given' do
input = Addrinfo.tcp('127.0.0.2', 0)
lambda { @source.family_addrinfo(input, 666) }.should raise_error(ArgumentError)
end
it "raises ArgumentError if the protocol families don't match" do
input = Addrinfo.tcp('::1', 0)
lambda { @source.family_addrinfo(input) }.should raise_error(ArgumentError)
end
it "raises ArgumentError if the socket types don't match" do
input = Addrinfo.udp('127.0.0.1', 0)
lambda { @source.family_addrinfo(input) }.should raise_error(ArgumentError)
end
end
end

View file

@ -0,0 +1,9 @@
require_relative '../spec_helper'
describe 'Addrinfo.foreach' do
it 'yields Addrinfo instances to the supplied block' do
Addrinfo.foreach('localhost', 80) do |addr|
addr.should be_an_instance_of(Addrinfo)
end
end
end

View file

@ -0,0 +1,88 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
describe 'Addrinfo.getaddrinfo' do
it 'returns an Array of Addrinfo instances' do
array = Addrinfo.getaddrinfo('localhost', 80)
array.should be_an_instance_of(Array)
array[0].should be_an_instance_of(Addrinfo)
end
SocketSpecs.each_ip_protocol do |family, ip_address|
it 'sets the IP address of the Addrinfo instances' do
array = Addrinfo.getaddrinfo(ip_address, 80)
array[0].ip_address.should == ip_address
end
it 'sets the port of the Addrinfo instances' do
array = Addrinfo.getaddrinfo(ip_address, 80)
array[0].ip_port.should == 80
end
it 'sets the address family of the Addrinfo instances' do
array = Addrinfo.getaddrinfo(ip_address, 80)
array[0].afamily.should == family
end
it 'sets the protocol family of the Addrinfo instances' do
array = Addrinfo.getaddrinfo(ip_address, 80)
array[0].pfamily.should == family
end
end
guard -> { SocketSpecs.ipv6_available? } do
it 'sets a custom protocol family of the Addrinfo instances' do
array = Addrinfo.getaddrinfo('localhost', 80, Socket::PF_INET6)
array[0].pfamily.should == Socket::PF_INET6
end
it 'sets a corresponding address family based on a custom protocol family' do
array = Addrinfo.getaddrinfo('localhost', 80, Socket::PF_INET6)
array[0].afamily.should == Socket::AF_INET6
end
end
platform_is_not :windows do
it 'sets the default socket type of the Addrinfo instances' do
array = Addrinfo.getaddrinfo('localhost', 80)
possible = [Socket::SOCK_STREAM, Socket::SOCK_DGRAM]
possible.should include(array[0].socktype)
end
end
it 'sets a custom socket type of the Addrinfo instances' do
array = Addrinfo.getaddrinfo('localhost', 80, nil, Socket::SOCK_DGRAM)
array[0].socktype.should == Socket::SOCK_DGRAM
end
platform_is_not :windows do
it 'sets the default socket protocol of the Addrinfo instances' do
array = Addrinfo.getaddrinfo('localhost', 80)
possible = [Socket::IPPROTO_TCP, Socket::IPPROTO_UDP]
possible.should include(array[0].protocol)
end
end
it 'sets a custom socket protocol of the Addrinfo instances' do
array = Addrinfo.getaddrinfo('localhost', 80, nil, nil, Socket::IPPROTO_UDP)
array[0].protocol.should == Socket::IPPROTO_UDP
end
it 'sets the canonical name when AI_CANONNAME is given as a flag' do
array = Addrinfo
.getaddrinfo('localhost', 80, nil, nil, nil, Socket::AI_CANONNAME)
array[0].canonname.should be_an_instance_of(String)
end
end

View file

@ -0,0 +1,44 @@
require_relative '../spec_helper'
require_relative '../fixtures/classes'
describe 'Addrinfo#getnameinfo' do
describe 'using an IP Addrinfo' do
SocketSpecs.each_ip_protocol do |family, ip_address|
before do
@addr = Addrinfo.tcp(ip_address, 80)
end
it 'returns the node and service names' do
host, service = @addr.getnameinfo
host.should be_an_instance_of(String)
service.should == 'http'
end
it 'accepts flags as a Fixnum as the first argument' do
host, service = @addr.getnameinfo(Socket::NI_NUMERICSERV)
host.should be_an_instance_of(String)
service.should == '80'
end
end
end
platform_is :linux do
with_feature :unix_socket do
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
host.should == @host
path.should == 'cats'
end
end
end
end
end

View file

@ -1,5 +1,4 @@
require_relative '../../../spec_helper' require_relative '../spec_helper'
require 'socket'
describe "Addrinfo#initialize" do describe "Addrinfo#initialize" do
@ -22,6 +21,12 @@ describe "Addrinfo#initialize" do
@addrinfo.pfamily.should == Socket::PF_UNSPEC @addrinfo.pfamily.should == Socket::PF_UNSPEC
end end
it 'returns AF_INET as the default address family' do
addr = Addrinfo.new(Socket.sockaddr_in(80, '127.0.0.1'))
addr.afamily.should == Socket::AF_INET
end
it "returns the INET6 afamily" do it "returns the INET6 afamily" do
@addrinfo.afamily.should == Socket::AF_INET6 @addrinfo.afamily.should == Socket::AF_INET6
end end
@ -142,7 +147,7 @@ describe "Addrinfo#initialize" do
@addrinfo.ip_port.should == 46102 @addrinfo.ip_port.should == 46102
end end
it "returns the Socket::UNSPEC pfamily" do it "returns the Socket::PF_INET pfamily" do
@addrinfo.pfamily.should == Socket::PF_INET @addrinfo.pfamily.should == Socket::PF_INET
end end
@ -159,6 +164,46 @@ describe "Addrinfo#initialize" do
end end
end end
describe 'with a valid IP address' do
# Uses AF_INET6 since AF_INET is the default, making it a better test
# that Addrinfo actually sets the family correctly.
before do
@sockaddr = ['AF_INET6', 80, 'hostname', '::1']
end
it 'returns an Addrinfo with the correct IP' do
addr = Addrinfo.new(@sockaddr)
addr.ip_address.should == '::1'
end
it 'returns an Addrinfo with the correct address family' do
addr = Addrinfo.new(@sockaddr)
addr.afamily.should == Socket::AF_INET6
end
it 'returns an Addrinfo with the correct protocol family' do
addr = Addrinfo.new(@sockaddr)
addr.pfamily.should == Socket::PF_INET6
end
it 'returns an Addrinfo with the correct port' do
addr = Addrinfo.new(@sockaddr)
addr.ip_port.should == 80
end
end
describe 'with an invalid IP address' do
it 'raises SocketError' do
block = lambda { Addrinfo.new(['AF_INET6', 80, 'hostname', '127.0.0.1']) }
block.should raise_error(SocketError)
end
end
describe "with a family given" do describe "with a family given" do
before :each do before :each do
@addrinfo = Addrinfo.new(["AF_INET", 46102, "localhost", "127.0.0.1"], Socket::PF_INET) @addrinfo = Addrinfo.new(["AF_INET", 46102, "localhost", "127.0.0.1"], Socket::PF_INET)
@ -217,6 +262,38 @@ describe "Addrinfo#initialize" do
it "returns the 0 protocol" do it "returns the 0 protocol" do
@addrinfo.protocol.should == 0 @addrinfo.protocol.should == 0
end end
[:SOCK_STREAM, :SOCK_DGRAM, :SOCK_RAW].each do |type|
it "overwrites the socket type #{type}" do
sockaddr = ['AF_INET', 80, 'hostname', '127.0.0.1']
value = Socket.const_get(type)
addr = Addrinfo.new(sockaddr, nil, value)
addr.socktype.should == value
end
end
with_feature :sock_packet do
[:SOCK_SEQPACKET].each do |type|
it "overwrites the socket type #{type}" do
sockaddr = ['AF_INET', 80, 'hostname', '127.0.0.1']
value = Socket.const_get(type)
addr = Addrinfo.new(sockaddr, nil, value)
addr.socktype.should == value
end
end
end
it "raises SocketError when using SOCK_RDM" do
sockaddr = ['AF_INET', 80, 'hostname', '127.0.0.1']
value = Socket::SOCK_RDM
block = lambda { Addrinfo.new(sockaddr, nil, value) }
block.should raise_error(SocketError)
end
end end
describe "with a family, socket type and protocol" do describe "with a family, socket type and protocol" do
@ -250,4 +327,261 @@ describe "Addrinfo#initialize" do
end end
end end
describe 'using an Array with extra arguments' do
describe 'with the AF_INET6 address family and an explicit protocol family' do
before do
@sockaddr = ['AF_INET6', 80, 'hostname', '127.0.0.1']
end
it "raises SocketError when using any Socket constant except except AF_INET(6)/PF_INET(6)" do
Socket.constants.grep(/(^AF_|^PF_)(?!INET)/).each do |constant|
value = Socket.const_get(constant)
-> {
Addrinfo.new(@sockaddr, value)
}.should raise_error(SocketError)
end
end
end
describe 'with the AF_INET address family and an explicit socket protocol' do
before do
@sockaddr = ['AF_INET', 80, 'hostname', '127.0.0.1']
end
describe 'and no socket type is given' do
valid = [:IPPROTO_IP, :IPPROTO_UDP, :IPPROTO_HOPOPTS]
valid.each do |type|
it "overwrites the protocol when using #{type}" do
value = Socket.const_get(type)
addr = Addrinfo.new(@sockaddr, nil, nil, value)
addr.protocol.should == value
end
end
platform_is_not :windows do
(Socket.constants.grep(/^IPPROTO/) - valid).each do |type|
it "raises SocketError when using #{type}" do
value = Socket.const_get(type)
block = lambda { Addrinfo.new(@sockaddr, nil, nil, value) }
block.should raise_error(SocketError)
end
end
end
end
describe 'and the socket type is set to SOCK_DGRAM' do
before do
@socktype = Socket::SOCK_DGRAM
end
valid = [:IPPROTO_IP, :IPPROTO_UDP, :IPPROTO_HOPOPTS]
valid.each do |type|
it "overwrites the protocol when using #{type}" do
value = Socket.const_get(type)
addr = Addrinfo.new(@sockaddr, nil, @socktype, value)
addr.protocol.should == value
end
end
platform_is_not :windows do
(Socket.constants.grep(/^IPPROTO/) - valid).each do |type|
it "raises SocketError when using #{type}" do
value = Socket.const_get(type)
block = lambda { Addrinfo.new(@sockaddr, nil, @socktype, value) }
block.should raise_error(SocketError)
end
end
end
end
with_feature :sock_packet do
describe 'and the socket type is set to SOCK_PACKET' do
before do
@socktype = Socket::SOCK_PACKET
end
Socket.constants.grep(/^IPPROTO/).each do |type|
it "raises SocketError when using #{type}" do
value = Socket.const_get(type)
block = lambda { Addrinfo.new(@sockaddr, nil, @socktype, value) }
block.should raise_error(SocketError)
end
end
end
end
describe 'and the socket type is set to SOCK_RAW' do
before do
@socktype = Socket::SOCK_RAW
end
Socket.constants.grep(/^IPPROTO/).each do |type|
it "overwrites the protocol when using #{type}" do
value = Socket.const_get(type)
addr = Addrinfo.new(@sockaddr, nil, @socktype, value)
addr.protocol.should == value
end
end
end
describe 'and the socket type is set to SOCK_RDM' do
before do
@socktype = Socket::SOCK_RDM
end
Socket.constants.grep(/^IPPROTO/).each do |type|
it "raises SocketError when using #{type}" do
value = Socket.const_get(type)
block = lambda { Addrinfo.new(@sockaddr, nil, @socktype, value) }
block.should raise_error(SocketError)
end
end
end
platform_is_not :windows do
describe 'and the socket type is set to SOCK_SEQPACKET' do
before do
@socktype = Socket::SOCK_SEQPACKET
end
valid = [:IPPROTO_IP, :IPPROTO_HOPOPTS]
valid.each do |type|
it "overwrites the protocol when using #{type}" do
value = Socket.const_get(type)
addr = Addrinfo.new(@sockaddr, nil, @socktype, value)
addr.protocol.should == value
end
end
(Socket.constants.grep(/^IPPROTO/) - valid).each do |type|
it "raises SocketError when using #{type}" do
value = Socket.const_get(type)
block = lambda { Addrinfo.new(@sockaddr, nil, @socktype, value) }
block.should raise_error(SocketError)
end
end
end
end
describe 'and the socket type is set to SOCK_STREAM' do
before do
@socktype = Socket::SOCK_STREAM
end
valid = [:IPPROTO_IP, :IPPROTO_TCP, :IPPROTO_HOPOPTS]
valid.each do |type|
it "overwrites the protocol when using #{type}" do
value = Socket.const_get(type)
addr = Addrinfo.new(@sockaddr, nil, @socktype, value)
addr.protocol.should == value
end
end
platform_is_not :windows do
(Socket.constants.grep(/^IPPROTO/) - valid).each do |type|
it "raises SocketError when using #{type}" do
value = Socket.const_get(type)
block = lambda { Addrinfo.new(@sockaddr, nil, @socktype, value) }
block.should raise_error(SocketError)
end
end
end
end
end
end
describe 'with Symbols' do
before do
@sockaddr = Socket.sockaddr_in(80, '127.0.0.1')
end
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
addr = Addrinfo.new(@sockaddr, :INET)
addr.pfamily.should == Socket::PF_INET
end
it 'returns an Addrinfo with :SOCK_STREAM as the socket type' do
addr = Addrinfo.new(@sockaddr, nil, :SOCK_STREAM)
addr.socktype.should == Socket::SOCK_STREAM
end
it 'returns an Addrinfo with :STREAM as the socket type' do
addr = Addrinfo.new(@sockaddr, nil, :STREAM)
addr.socktype.should == Socket::SOCK_STREAM
end
end
describe 'with Strings' do
before do
@sockaddr = Socket.sockaddr_in(80, '127.0.0.1')
end
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
addr = Addrinfo.new(@sockaddr, 'INET')
addr.pfamily.should == Socket::PF_INET
end
it 'returns an Addrinfo with "SOCK_STREAM" as the socket type' do
addr = Addrinfo.new(@sockaddr, nil, 'SOCK_STREAM')
addr.socktype.should == Socket::SOCK_STREAM
end
it 'returns an Addrinfo with "STREAM" as the socket type' do
addr = Addrinfo.new(@sockaddr, nil, 'STREAM')
addr.socktype.should == Socket::SOCK_STREAM
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
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 address family' do
Addrinfo.new(@sockaddr).afamily.should == Socket::AF_UNIX
end
end
end
end end

View file

@ -1,25 +1,50 @@
require_relative '../../../spec_helper' require_relative '../spec_helper'
require 'socket'
describe 'Addrinfo#inspect_sockaddr' do describe 'Addrinfo#inspect_sockaddr' do
it 'IPv4' do describe 'using an IPv4 address' do
Addrinfo.tcp('127.0.0.1', 80).inspect_sockaddr.should == '127.0.0.1:80' it 'returns a String containing the IP address and port number' do
Addrinfo.tcp('127.0.0.1', 0).inspect_sockaddr.should == '127.0.0.1' addr = Addrinfo.tcp('127.0.0.1', 80)
addr.inspect_sockaddr.should == '127.0.0.1:80'
end
it 'returns a String containing just the IP address when no port is given' do
addr = Addrinfo.tcp('127.0.0.1', 0)
addr.inspect_sockaddr.should == '127.0.0.1'
end
end end
it 'IPv6' do describe 'using an IPv6 address' do
Addrinfo.tcp('::1', 80).inspect_sockaddr.should == '[::1]:80' before :each do
Addrinfo.tcp('::1', 0).inspect_sockaddr.should == '::1' @ip = '2001:0db8:85a3:0000:0000:8a2e:0370:7334'
ip = '2001:0db8:85a3:0000:0000:8a2e:0370:7334' end
Addrinfo.tcp(ip, 80).inspect_sockaddr.should == '[2001:db8:85a3::8a2e:370:7334]:80'
Addrinfo.tcp(ip, 0).inspect_sockaddr.should == '2001:db8:85a3::8a2e:370:7334' it 'returns a String containing the IP address and port number' do
Addrinfo.tcp('::1', 80).inspect_sockaddr.should == '[::1]:80'
Addrinfo.tcp(@ip, 80).inspect_sockaddr.should == '[2001:db8:85a3::8a2e:370:7334]:80'
end
it 'returns a String containing just the IP address when no port is given' do
Addrinfo.tcp('::1', 0).inspect_sockaddr.should == '::1'
Addrinfo.tcp(@ip, 0).inspect_sockaddr.should == '2001:db8:85a3::8a2e:370:7334'
end
end end
platform_is_not :windows do with_feature :unix_socket do
it 'UNIX' do describe 'using a UNIX path' do
Addrinfo.unix('/tmp/sock').inspect_sockaddr.should == '/tmp/sock' it 'returns a String containing the UNIX path' do
Addrinfo.unix('rel').inspect_sockaddr.should == 'UNIX rel' addr = Addrinfo.unix('/foo/bar')
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')
addr.inspect_sockaddr.should == 'UNIX foo'
end
end end
end end
end end

View file

@ -0,0 +1,65 @@
require_relative '../spec_helper'
describe 'Addrinfo#inspect' do
describe 'using an IPv4 Addrinfo' do
it 'returns a String when using a TCP Addrinfo' do
addr = Addrinfo.tcp('127.0.0.1', 80)
addr.inspect.should == '#<Addrinfo: 127.0.0.1:80 TCP>'
end
it 'returns a String when using an UDP Addrinfo' do
addr = Addrinfo.udp('127.0.0.1', 80)
addr.inspect.should == '#<Addrinfo: 127.0.0.1:80 UDP>'
end
it 'returns a String when using an Addrinfo without a port' do
addr = Addrinfo.ip('127.0.0.1')
addr.inspect.should == '#<Addrinfo: 127.0.0.1>'
end
end
describe 'using an IPv6 Addrinfo' do
it 'returns a String when using a TCP Addrinfo' do
addr = Addrinfo.tcp('::1', 80)
addr.inspect.should == '#<Addrinfo: [::1]:80 TCP>'
end
it 'returns a String when using an UDP Addrinfo' do
addr = Addrinfo.udp('::1', 80)
addr.inspect.should == '#<Addrinfo: [::1]:80 UDP>'
end
it 'returns a String when using an Addrinfo without a port' do
addr = Addrinfo.ip('::1')
addr.inspect.should == '#<Addrinfo: ::1>'
end
end
with_feature :unix_socket do
describe 'using a UNIX Addrinfo' do
it 'returns a String' do
addr = Addrinfo.unix('/foo')
addr.inspect.should == '#<Addrinfo: /foo SOCK_STREAM>'
end
it 'returns a String when using a relative UNIX path' do
addr = Addrinfo.unix('foo')
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)
addr.inspect.should == '#<Addrinfo: /foo SOCK_DGRAM>'
end
end
end
end

View file

@ -1,5 +1,4 @@
require_relative '../../../spec_helper' require_relative '../spec_helper'
require 'socket'
describe "Addrinfo#ip_address" do describe "Addrinfo#ip_address" do
describe "for an ipv4 socket" do describe "for an ipv4 socket" do
@ -22,7 +21,7 @@ describe "Addrinfo#ip_address" do
end end
end end
platform_is_not :windows do with_feature :unix_socket do
describe "for a unix socket" do describe "for a unix socket" do
before :each do before :each do
@addrinfo = Addrinfo.unix("/tmp/sock") @addrinfo = Addrinfo.unix("/tmp/sock")
@ -33,4 +32,54 @@ describe "Addrinfo#ip_address" do
end end
end end
end end
describe 'with an Array as the socket address' do
it 'returns the IP as a String' do
sockaddr = ['AF_INET', 80, 'localhost', '127.0.0.1']
addr = Addrinfo.new(sockaddr)
addr.ip_address.should == '127.0.0.1'
end
end
describe 'without an IP address' do
before do
@ips = ['127.0.0.1', '0.0.0.0', '::1']
end
# Both these cases seem to return different values at times on MRI. Since
# this is network dependent we can't rely on an exact IP being returned.
it 'returns the local IP address when using an empty String as the IP' do
sockaddr = Socket.sockaddr_in(80, '')
addr = Addrinfo.new(sockaddr)
@ips.include?(addr.ip_address).should == true
end
it 'returns the local IP address when using nil as the IP' do
sockaddr = Socket.sockaddr_in(80, nil)
addr = Addrinfo.new(sockaddr)
@ips.include?(addr.ip_address).should == true
end
end
# On MRI calling Addrinfo#ip_address with AF_UNSPEC as the address family is
# supposed to raise a SocketError. MRI however doesn't provide a way to
# actually initialize an Addrinfo with AF_UNSPEC, nor does it allow stubbing
# of any methods since Addrinfo doesn't use any Ruby methods for checking the
# IP address. As a result we can only run this test on Rubinius.
with_feature :pure_ruby_addrinfo do
describe 'with a non IPv4 or IPv6 address' do
it 'raises SocketError' do
sockaddr = Socket.sockaddr_in(80, '127.0.0.1')
addr = Addrinfo.new(sockaddr)
addr.stub!(:ipv4?).and_return(false)
addr.stub!(:ipv6?).and_return(false)
lambda { addr.ip_address }.should raise_error(SocketError)
end
end
end
end end

View file

@ -1,5 +1,4 @@
require_relative '../../../spec_helper' require_relative '../spec_helper'
require 'socket'
describe "Addrinfo#ip_port" do describe "Addrinfo#ip_port" do
describe "for an ipv4 socket" do describe "for an ipv4 socket" do
@ -22,7 +21,7 @@ describe "Addrinfo#ip_port" do
end end
end end
platform_is_not :windows do with_feature :unix_socket do
describe "for a unix socket" do describe "for a unix socket" do
before :each do before :each do
@addrinfo = Addrinfo.unix("/tmp/sock") @addrinfo = Addrinfo.unix("/tmp/sock")

View file

@ -1,5 +1,5 @@
require_relative '../../../spec_helper' require_relative '../spec_helper'
require 'socket' require_relative '../fixtures/classes'
describe "Addrinfo#ip?" do describe "Addrinfo#ip?" do
describe "for an ipv4 socket" do describe "for an ipv4 socket" do
@ -22,15 +22,43 @@ describe "Addrinfo#ip?" do
end end
end end
platform_is_not :windows do with_feature :unix_socket do
describe "for a unix socket" do describe "for a unix socket" do
before :each do before :each do
@addrinfo = Addrinfo.unix("/tmp/sock") @addrinfo = Addrinfo.unix("/tmp/sock")
end end
it "returns Socket::AF_INET6" do it "returns false" do
@addrinfo.ip?.should be_false @addrinfo.ip?.should be_false
end end
end end
end end
end end
describe 'Addrinfo.ip' do
SocketSpecs.each_ip_protocol do |family, ip_address|
it 'returns an Addrinfo instance' do
Addrinfo.ip(ip_address).should be_an_instance_of(Addrinfo)
end
it 'sets the IP address' do
Addrinfo.ip(ip_address).ip_address.should == ip_address
end
it 'sets the port to 0' do
Addrinfo.ip(ip_address).ip_port.should == 0
end
it 'sets the address family' do
Addrinfo.ip(ip_address).afamily.should == family
end
it 'sets the protocol family' do
Addrinfo.ip(ip_address).pfamily.should == family
end
it 'sets the socket type to 0' do
Addrinfo.ip(ip_address).socktype.should == 0
end
end
end

View file

@ -1,5 +1,4 @@
require_relative '../../../spec_helper' require_relative '../spec_helper'
require 'socket'
describe "Addrinfo#ip_unpack" do describe "Addrinfo#ip_unpack" do
describe "for an ipv4 socket" do describe "for an ipv4 socket" do
@ -22,7 +21,7 @@ describe "Addrinfo#ip_unpack" do
end end
end end
platform_is_not :windows do with_feature :unix_socket do
describe "for a unix socket" do describe "for a unix socket" do
before :each do before :each do
@addrinfo = Addrinfo.unix("/tmp/sock") @addrinfo = Addrinfo.unix("/tmp/sock")

View file

@ -1,19 +1,16 @@
require_relative '../../../spec_helper' require_relative '../spec_helper'
require 'socket'
describe "Addrinfo#ipv4_loopback?" do describe "Addrinfo#ipv4_loopback?" do
describe "for an ipv4 socket" do describe "for an ipv4 socket" do
before :each do
@loopback = Addrinfo.tcp("127.0.0.1", 80)
@other = Addrinfo.tcp("0.0.0.0", 80)
end
it "returns true for the loopback address" do it "returns true for the loopback address" do
@loopback.ipv4_loopback?.should be_true Addrinfo.ip('127.0.0.1').ipv4_loopback?.should == true
Addrinfo.ip('127.0.0.2').ipv4_loopback?.should == true
Addrinfo.ip('127.255.0.1').ipv4_loopback?.should == true
Addrinfo.ip('127.255.255.255').ipv4_loopback?.should == true
end end
it "returns false for another address" do it "returns false for another address" do
@other.ipv4_loopback?.should be_false Addrinfo.ip('255.255.255.0').ipv4_loopback?.should be_false
end end
end end
@ -32,7 +29,7 @@ describe "Addrinfo#ipv4_loopback?" do
end end
end end
platform_is_not :windows do with_feature :unix_socket do
describe "for a unix socket" do describe "for a unix socket" do
before :each do before :each do
@addrinfo = Addrinfo.unix("/tmp/sock") @addrinfo = Addrinfo.unix("/tmp/sock")

View file

@ -1,38 +1,21 @@
require_relative '../../../spec_helper' require_relative '../spec_helper'
require 'socket'
describe "Addrinfo#ipv4_multicast?" do describe "Addrinfo#ipv4_multicast?" do
describe "for an ipv4 socket" do it 'returns true for a multicast address' do
before :each do Addrinfo.ip('224.0.0.0').ipv4_multicast?.should == true
@multicast = Addrinfo.tcp("224.0.0.1", 80) Addrinfo.ip('224.0.0.9').ipv4_multicast?.should == true
@other = Addrinfo.tcp("0.0.0.0", 80) Addrinfo.ip('239.255.255.250').ipv4_multicast?.should == true
end
it "returns true for the loopback address" do
@multicast.ipv4_multicast?.should be_true
end
it "returns false for another address" do
@other.ipv4_multicast?.should be_false
end
end end
describe "for an ipv6 socket" do it 'returns false for a regular addrss' do
before :each do Addrinfo.ip('8.8.8.8').ipv4_multicast?.should == false
@multicast = Addrinfo.tcp("ff02::1", 80)
@other = Addrinfo.tcp("::", 80)
end
it "returns false for the loopback address" do
@multicast.ipv4_multicast?.should be_false
end
it "returns false for another address" do
@other.ipv4_multicast?.should be_false
end
end end
platform_is_not :windows do it 'returns false for an IPv6 address' do
Addrinfo.ip('::1').ipv4_multicast?.should == false
end
with_feature :unix_socket do
describe "for a unix socket" do describe "for a unix socket" do
before :each do before :each do
@addrinfo = Addrinfo.unix("/tmp/sock") @addrinfo = Addrinfo.unix("/tmp/sock")

View file

@ -1,5 +1,4 @@
require_relative '../../../spec_helper' require_relative '../spec_helper'
require 'socket'
describe "Addrinfo#ipv4_private?" do describe "Addrinfo#ipv4_private?" do
describe "for an ipv4 socket" do describe "for an ipv4 socket" do
@ -9,7 +8,14 @@ describe "Addrinfo#ipv4_private?" do
end end
it "returns true for a private address" do it "returns true for a private address" do
@private.ipv4_private?.should be_true Addrinfo.ip('10.0.0.0').ipv4_private?.should == true
Addrinfo.ip('10.0.0.5').ipv4_private?.should == true
Addrinfo.ip('172.16.0.0').ipv4_private?.should == true
Addrinfo.ip('172.16.0.5').ipv4_private?.should == true
Addrinfo.ip('192.168.0.0').ipv4_private?.should == true
Addrinfo.ip('192.168.0.5').ipv4_private?.should == true
end end
it "returns false for a public address" do it "returns false for a public address" do
@ -27,7 +33,7 @@ describe "Addrinfo#ipv4_private?" do
end end
end end
platform_is_not :windows do with_feature :unix_socket do
describe "for a unix socket" do describe "for a unix socket" do
before :each do before :each do
@addrinfo = Addrinfo.unix("/tmp/sock") @addrinfo = Addrinfo.unix("/tmp/sock")

View file

@ -1,5 +1,4 @@
require_relative '../../../spec_helper' require_relative '../spec_helper'
require 'socket'
describe "Addrinfo#ipv4?" do describe "Addrinfo#ipv4?" do
describe "for an ipv4 socket" do describe "for an ipv4 socket" do
@ -22,7 +21,7 @@ describe "Addrinfo#ipv4?" do
end end
end end
platform_is_not :windows do with_feature :unix_socket do
describe "for a unix socket" do describe "for a unix socket" do
before :each do before :each do
@addrinfo = Addrinfo.unix("/tmp/sock") @addrinfo = Addrinfo.unix("/tmp/sock")

View file

@ -0,0 +1,18 @@
require_relative '../spec_helper'
describe 'Addrinfo#ipv6_linklocal?' do
it 'returns true for a link-local address' do
Addrinfo.ip('fe80::').ipv6_linklocal?.should == true
Addrinfo.ip('fe81::').ipv6_linklocal?.should == true
Addrinfo.ip('fe8f::').ipv6_linklocal?.should == true
Addrinfo.ip('fe80::1').ipv6_linklocal?.should == true
end
it 'returns false for a regular address' do
Addrinfo.ip('::1').ipv6_linklocal?.should == false
end
it 'returns false for an IPv4 address' do
Addrinfo.ip('127.0.0.1').ipv6_linklocal?.should == false
end
end

View file

@ -1,5 +1,4 @@
require_relative '../../../spec_helper' require_relative '../spec_helper'
require 'socket'
describe "Addrinfo#ipv6_loopback?" do describe "Addrinfo#ipv6_loopback?" do
describe "for an ipv4 socket" do describe "for an ipv4 socket" do
@ -8,7 +7,7 @@ describe "Addrinfo#ipv6_loopback?" do
@other = Addrinfo.tcp("0.0.0.0", 80) @other = Addrinfo.tcp("0.0.0.0", 80)
end end
it "returns true for the loopback address" do it "returns false for the loopback address" do
@loopback.ipv6_loopback?.should be_false @loopback.ipv6_loopback?.should be_false
end end
@ -23,7 +22,7 @@ describe "Addrinfo#ipv6_loopback?" do
@other = Addrinfo.tcp("::", 80) @other = Addrinfo.tcp("::", 80)
end end
it "returns false for the loopback address" do it "returns true for the loopback address" do
@loopback.ipv6_loopback?.should be_true @loopback.ipv6_loopback?.should be_true
end end
@ -32,7 +31,7 @@ describe "Addrinfo#ipv6_loopback?" do
end end
end end
platform_is_not :windows do with_feature :unix_socket do
describe "for a unix socket" do describe "for a unix socket" do
before :each do before :each do
@addrinfo = Addrinfo.unix("/tmp/sock") @addrinfo = Addrinfo.unix("/tmp/sock")

View file

@ -0,0 +1,20 @@
require_relative '../spec_helper'
describe 'Addrinfo#ipv6_mc_global?' do
it 'returns true for a multi-cast address in the global scope' do
Addrinfo.ip('ff1e::').ipv6_mc_global?.should == true
Addrinfo.ip('fffe::').ipv6_mc_global?.should == true
Addrinfo.ip('ff0e::').ipv6_mc_global?.should == true
Addrinfo.ip('ff1e::1').ipv6_mc_global?.should == true
end
it 'returns false for a regular IPv6 address' do
Addrinfo.ip('::1').ipv6_mc_global?.should == false
Addrinfo.ip('ff1a::').ipv6_mc_global?.should == false
Addrinfo.ip('ff1f::1').ipv6_mc_global?.should == false
end
it 'returns false for an IPv4 address' do
Addrinfo.ip('127.0.0.1').ipv6_mc_global?.should == false
end
end

View file

@ -0,0 +1,19 @@
require_relative '../spec_helper'
describe 'Addrinfo#ipv6_mc_linklocal?' do
it 'returns true for a multi-cast link-local address' do
Addrinfo.ip('ff12::').ipv6_mc_linklocal?.should == true
Addrinfo.ip('ff02::').ipv6_mc_linklocal?.should == true
Addrinfo.ip('fff2::').ipv6_mc_linklocal?.should == true
Addrinfo.ip('ff12::1').ipv6_mc_linklocal?.should == true
end
it 'returns false for a regular IPv6 address' do
Addrinfo.ip('::1').ipv6_mc_linklocal?.should == false
Addrinfo.ip('fff1::').ipv6_mc_linklocal?.should == false
end
it 'returns false for an IPv4 address' do
Addrinfo.ip('127.0.0.1').ipv6_mc_linklocal?.should == false
end
end

View file

@ -0,0 +1,18 @@
require_relative '../spec_helper'
describe 'Addrinfo#ipv6_mc_nodelocal?' do
it 'returns true for a multi-cast node-local address' do
Addrinfo.ip('ff11::').ipv6_mc_nodelocal?.should == true
Addrinfo.ip('ff01::').ipv6_mc_nodelocal?.should == true
Addrinfo.ip('fff1::').ipv6_mc_nodelocal?.should == true
Addrinfo.ip('ff11::1').ipv6_mc_nodelocal?.should == true
end
it 'returns false for a regular IPv6 address' do
Addrinfo.ip('::1').ipv6_mc_nodelocal?.should == false
end
it 'returns false for an IPv4 address' do
Addrinfo.ip('127.0.0.1').ipv6_mc_nodelocal?.should == false
end
end

View file

@ -0,0 +1,18 @@
require_relative '../spec_helper'
describe 'Addrinfo#ipv6_mc_orglocal?' do
it 'returns true for a multi-cast org-local address' do
Addrinfo.ip('ff18::').ipv6_mc_orglocal?.should == true
Addrinfo.ip('ff08::').ipv6_mc_orglocal?.should == true
Addrinfo.ip('fff8::').ipv6_mc_orglocal?.should == true
Addrinfo.ip('ff18::1').ipv6_mc_orglocal?.should == true
end
it 'returns false for a regular IPv6 address' do
Addrinfo.ip('::1').ipv6_mc_orglocal?.should == false
end
it 'returns false for an IPv4 address' do
Addrinfo.ip('127.0.0.1').ipv6_mc_orglocal?.should == false
end
end

View file

@ -0,0 +1,18 @@
require_relative '../spec_helper'
describe 'Addrinfo#ipv6_mc_sitelocal?' do
it 'returns true for a multi-cast site-local address' do
Addrinfo.ip('ff15::').ipv6_mc_sitelocal?.should == true
Addrinfo.ip('ff05::').ipv6_mc_sitelocal?.should == true
Addrinfo.ip('fff5::').ipv6_mc_sitelocal?.should == true
Addrinfo.ip('ff15::1').ipv6_mc_sitelocal?.should == true
end
it 'returns false for a regular IPv6 address' do
Addrinfo.ip('::1').ipv6_mc_sitelocal?.should == false
end
it 'returns false for an IPv4 address' do
Addrinfo.ip('127.0.0.1').ipv6_mc_sitelocal?.should == false
end
end

View file

@ -1,5 +1,4 @@
require_relative '../../../spec_helper' require_relative '../spec_helper'
require 'socket'
describe "Addrinfo#ipv6_multicast?" do describe "Addrinfo#ipv6_multicast?" do
describe "for an ipv4 socket" do describe "for an ipv4 socket" do
@ -8,7 +7,7 @@ describe "Addrinfo#ipv6_multicast?" do
@other = Addrinfo.tcp("0.0.0.0", 80) @other = Addrinfo.tcp("0.0.0.0", 80)
end end
it "returns true for the loopback address" do it "returns true for a multicast address" do
@multicast.ipv6_multicast?.should be_false @multicast.ipv6_multicast?.should be_false
end end
@ -18,21 +17,24 @@ describe "Addrinfo#ipv6_multicast?" do
end end
describe "for an ipv6 socket" do describe "for an ipv6 socket" do
before :each do it "returns true for a multicast address" do
@multicast = Addrinfo.tcp("ff02::1", 80) Addrinfo.ip('ff00::').ipv6_multicast?.should == true
@other = Addrinfo.tcp("::", 80) Addrinfo.ip('ff00::1').ipv6_multicast?.should == true
end Addrinfo.ip('ff08::1').ipv6_multicast?.should == true
Addrinfo.ip('fff8::1').ipv6_multicast?.should == true
it "returns false for the loopback address" do Addrinfo.ip('ff02::').ipv6_multicast?.should == true
@multicast.ipv6_multicast?.should be_true Addrinfo.ip('ff02::1').ipv6_multicast?.should == true
Addrinfo.ip('ff0f::').ipv6_multicast?.should == true
end end
it "returns false for another address" do it "returns false for another address" do
@other.ipv6_multicast?.should be_false Addrinfo.ip('::1').ipv6_multicast?.should == false
Addrinfo.ip('fe80::').ipv6_multicast?.should == false
end end
end end
platform_is_not :windows do with_feature :unix_socket do
describe "for a unix socket" do describe "for a unix socket" do
before :each do before :each do
@addrinfo = Addrinfo.unix("/tmp/sock") @addrinfo = Addrinfo.unix("/tmp/sock")

View file

@ -0,0 +1,18 @@
require_relative '../spec_helper'
describe 'Addrinfo#ipv6_sitelocal?' do
it 'returns true for a site-local address' do
Addrinfo.ip('feef::').ipv6_sitelocal?.should == true
Addrinfo.ip('fee0::').ipv6_sitelocal?.should == true
Addrinfo.ip('fee2::').ipv6_sitelocal?.should == true
Addrinfo.ip('feef::1').ipv6_sitelocal?.should == true
end
it 'returns false for a regular IPv6 address' do
Addrinfo.ip('::1').ipv6_sitelocal?.should == false
end
it 'returns false for an IPv4 address' do
Addrinfo.ip('127.0.0.1').ipv6_sitelocal?.should == false
end
end

View file

@ -1,5 +1,4 @@
require_relative '../../../spec_helper' require_relative '../spec_helper'
require 'socket'
describe "Addrinfo#ipv6?" do describe "Addrinfo#ipv6?" do
describe "for an ipv4 socket" do describe "for an ipv4 socket" do
@ -22,7 +21,7 @@ describe "Addrinfo#ipv6?" do
end end
end end
platform_is_not :windows do with_feature :unix_socket do
describe "for a unix socket" do describe "for a unix socket" do
before :each do before :each do
@addrinfo = Addrinfo.unix("/tmp/sock") @addrinfo = Addrinfo.unix("/tmp/sock")

View file

@ -0,0 +1,66 @@
require_relative '../spec_helper'
describe 'Addrinfo#ipv6_to_ipv4' do
it 'returns an Addrinfo for ::192.168.1.1' do
addr = Addrinfo.ip('::192.168.1.1').ipv6_to_ipv4
addr.should be_an_instance_of(Addrinfo)
addr.afamily.should == Socket::AF_INET
addr.ip_address.should == '192.168.1.1'
end
it 'returns an Addrinfo for ::0.0.1.1' do
addr = Addrinfo.ip('::0.0.1.1').ipv6_to_ipv4
addr.should be_an_instance_of(Addrinfo)
addr.afamily.should == Socket::AF_INET
addr.ip_address.should == '0.0.1.1'
end
it 'returns an Addrinfo for ::0.0.1.0' do
addr = Addrinfo.ip('::0.0.1.0').ipv6_to_ipv4
addr.should be_an_instance_of(Addrinfo)
addr.afamily.should == Socket::AF_INET
addr.ip_address.should == '0.0.1.0'
end
it 'returns an Addrinfo for ::0.1.0.0' do
addr = Addrinfo.ip('::0.1.0.0').ipv6_to_ipv4
addr.should be_an_instance_of(Addrinfo)
addr.afamily.should == Socket::AF_INET
addr.ip_address.should == '0.1.0.0'
end
it 'returns an Addrinfo for ::ffff:192.168.1.1' do
addr = Addrinfo.ip('::ffff:192.168.1.1').ipv6_to_ipv4
addr.should be_an_instance_of(Addrinfo)
addr.afamily.should == Socket::AF_INET
addr.ip_address.should == '192.168.1.1'
end
it 'returns nil for ::0.0.0.1' do
Addrinfo.ip('::0.0.0.1').ipv6_to_ipv4.should be_nil
end
it 'returns nil for a pure IPv6 Addrinfo' do
Addrinfo.ip('::1').ipv6_to_ipv4.should be_nil
end
it 'returns nil for an IPv4 Addrinfo' do
Addrinfo.ip('192.168.1.1').ipv6_to_ipv4.should be_nil
end
with_feature :unix_socket do
it 'returns nil for a UNIX Addrinfo' do
Addrinfo.unix('foo').ipv6_to_ipv4.should be_nil
end
end
end

View file

@ -0,0 +1,18 @@
require_relative '../spec_helper'
describe 'Addrinfo#ipv6_unique_local?' do
it 'returns true for an unique local IPv6 address' do
Addrinfo.ip('fc00::').ipv6_unique_local?.should == true
Addrinfo.ip('fd00::').ipv6_unique_local?.should == true
Addrinfo.ip('fcff::').ipv6_unique_local?.should == true
end
it 'returns false for a regular IPv6 address' do
Addrinfo.ip('::1').ipv6_unique_local?.should == false
Addrinfo.ip('fe00::').ipv6_unique_local?.should == false
end
it 'returns false for an IPv4 address' do
Addrinfo.ip('127.0.0.1').ipv6_unique_local?.should == false
end
end

View file

@ -0,0 +1,15 @@
require_relative '../spec_helper'
describe 'Addrinfo#ipv6_unspecified?' do
it 'returns true for an unspecified IPv6 address' do
Addrinfo.ip('::').ipv6_unspecified?.should == true
end
it 'returns false for a regular IPv6 address' do
Addrinfo.ip('::1').ipv6_unspecified?.should == false
end
it 'returns false for an IPv4 address' do
Addrinfo.ip('127.0.0.1').ipv6_unspecified?.should == false
end
end

View file

@ -0,0 +1,20 @@
require_relative '../spec_helper'
describe 'Addrinfo#ipv6_v4compat?' do
it 'returns true for an IPv4 compatible address' do
Addrinfo.ip('::127.0.0.1').ipv6_v4compat?.should == true
Addrinfo.ip('::192.168.1.1').ipv6_v4compat?.should == true
end
it 'returns false for an IPv4 mapped address' do
Addrinfo.ip('::ffff:192.168.1.1').ipv6_v4compat?.should == false
end
it 'returns false for a regular IPv6 address' do
Addrinfo.ip('::1').ipv6_v4compat?.should == false
end
it 'returns false for an IPv4 address' do
Addrinfo.ip('127.0.0.1').ipv6_v4compat?.should == false
end
end

View file

@ -0,0 +1,20 @@
require_relative '../spec_helper'
describe 'Addrinfo#ipv6_v4mapped?' do
it 'returns true for an IPv4 compatible address' do
Addrinfo.ip('::ffff:192.168.1.1').ipv6_v4mapped?.should == true
end
it 'returns false for an IPv4 compatible address' do
Addrinfo.ip('::192.168.1.1').ipv6_v4mapped?.should == false
Addrinfo.ip('::127.0.0.1').ipv6_v4mapped?.should == false
end
it 'returns false for a regular IPv6 address' do
Addrinfo.ip('::1').ipv6_v4mapped?.should == false
end
it 'returns false for an IPv4 address' do
Addrinfo.ip('127.0.0.1').ipv6_v4mapped?.should == false
end
end

View file

@ -0,0 +1,34 @@
require_relative '../spec_helper'
describe 'Addrinfo#listen' do
before do
@addr = Addrinfo.tcp('127.0.0.1', 0)
@socket = nil
end
after do
@socket.close if @socket
end
it 'returns a Socket when no block is given' do
@socket = @addr.listen
@socket.should be_an_instance_of(Socket)
end
it 'yields the Socket if a block is given' do
@addr.listen do |socket|
socket.should be_an_instance_of(Socket)
end
end
it 'closes the socket if a block is given' do
socket = nil
@addr.listen do |sock|
socket = sock
end
socket.closed?.should == true
end
end

View file

@ -0,0 +1,82 @@
require_relative '../spec_helper'
describe 'Addrinfo#marshal_dump' do
describe 'using an IP Addrinfo' do
before do
@addr = Addrinfo.getaddrinfo('localhost', 80, :INET, :STREAM,
Socket::IPPROTO_TCP, Socket::AI_CANONNAME)[0]
end
it 'returns an Array' do
@addr.marshal_dump.should be_an_instance_of(Array)
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_INET'
end
it 'includes the IP address as the 2nd value' do
@array[1].should == [@addr.ip_address, @addr.ip_port.to_s]
end
it 'includes the protocol family as the 3rd value' do
@array[2].should == 'PF_INET'
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 == 'IPPROTO_TCP'
end
it 'includes the canonical name as the 6th value' do
@array[5].should == @addr.canonname
end
end
end
with_feature :unix_socket 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
@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 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 protocol as the 5th value' do
@array[4].should == 0
end
end
end
end
end

View file

@ -0,0 +1,35 @@
require_relative '../spec_helper'
describe 'Addrinfo#marshal_load' do
describe 'using an IP address' do
it 'returns a new Addrinfo' do
source = Addrinfo.getaddrinfo('localhost', 80, :INET, :STREAM,
Socket::IPPROTO_TCP, Socket::AI_CANONNAME)[0]
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.ip_address.should == source.ip_address
addr.ip_port.should == source.ip_port
addr.canonname.should == source.canonname
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))
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
end

View file

@ -1,7 +1,12 @@
require_relative '../../../spec_helper' require_relative '../spec_helper'
require 'socket'
describe "Addrinfo#pfamily" do describe "Addrinfo#pfamily" do
it 'returns PF_UNSPEC as the default socket family' do
sockaddr = Socket.pack_sockaddr_in(80, 'localhost')
Addrinfo.new(sockaddr).pfamily.should == Socket::PF_UNSPEC
end
describe "for an ipv4 socket" do describe "for an ipv4 socket" do
before :each do before :each do
@ -24,7 +29,7 @@ describe "Addrinfo#pfamily" do
end end
end end
platform_is_not :windows do with_feature :unix_socket do
describe "for a unix socket" do describe "for a unix socket" do
before :each do before :each do
@addrinfo = Addrinfo.unix("/tmp/sock") @addrinfo = Addrinfo.unix("/tmp/sock")

View file

@ -1,30 +1,16 @@
require_relative '../../../spec_helper' require_relative '../spec_helper'
require 'socket'
describe "Addrinfo#protocol" do describe "Addrinfo#protocol" do
describe "for an ipv4 socket" do it 'returns 0 by default' do
Addrinfo.ip('127.0.0.1').protocol.should == 0
before :each do
@addrinfo = Addrinfo.tcp("127.0.0.1", 80)
end
it "returns Socket::IPPROTO_TCP" do
@addrinfo.protocol.should == Socket::IPPROTO_TCP
end
end end
describe "for an ipv6 socket" do it 'returns a custom protocol when given' do
before :each do Addrinfo.tcp('127.0.0.1', 80).protocol.should == Socket::IPPROTO_TCP
@addrinfo = Addrinfo.tcp("::1", 80) Addrinfo.tcp('::1', 80).protocol.should == Socket::IPPROTO_TCP
end
it "returns Socket::IPPROTO_TCP" do
@addrinfo.protocol.should == Socket::IPPROTO_TCP
end
end end
platform_is_not :windows do with_feature :unix_socket do
describe "for a unix socket" do describe "for a unix socket" do
before :each do before :each do
@addrinfo = Addrinfo.unix("/tmp/sock") @addrinfo = Addrinfo.unix("/tmp/sock")

View file

@ -6,7 +6,7 @@ describe :socket_addrinfo_to_sockaddr, :shared => true do
end end
it "returns a sockaddr packed structure" do it "returns a sockaddr packed structure" do
@addrinfo.send(@method).should be_kind_of(String) @addrinfo.send(@method).should == Socket.sockaddr_in(80, '127.0.0.1')
end end
end end
@ -16,20 +16,36 @@ describe :socket_addrinfo_to_sockaddr, :shared => true do
end end
it "returns a sockaddr packed structure" do it "returns a sockaddr packed structure" do
@addrinfo.send(@method).should be_kind_of(String) @addrinfo.send(@method).should == Socket.sockaddr_in(80, '::1')
end end
end end
platform_is_not :windows do with_feature :unix_socket do
describe "for a unix socket" do describe "for a unix socket" do
before :each do before :each do
@addrinfo = Addrinfo.unix("/tmp/sock") @addrinfo = Addrinfo.unix("/tmp/sock")
end end
it "returns a sockaddr packed structure" do it "returns a sockaddr packed structure" do
@addrinfo.send(@method).should be_kind_of(String) @addrinfo.send(@method).should == Socket.sockaddr_un('/tmp/sock')
end end
end end
end end
describe 'using a Addrinfo with just an IP address' do
it 'returns a String' do
addr = Addrinfo.ip('127.0.0.1')
addr.send(@method).should == Socket.sockaddr_in(0, '127.0.0.1')
end
end
describe 'using a Addrinfo without an IP and port' do
it 'returns a String' do
addr = Addrinfo.new(['AF_INET', 0, '', ''])
addr.send(@method).should == Socket.sockaddr_in(0, '')
end
end
end end

View file

@ -1,30 +1,15 @@
require_relative '../../../spec_helper' require_relative '../spec_helper'
require 'socket'
describe "Addrinfo#socktype" do describe "Addrinfo#socktype" do
describe "for an ipv4 socket" do it 'returns 0 by default' do
Addrinfo.ip('127.0.0.1').socktype.should == 0
before :each do
@addrinfo = Addrinfo.tcp("127.0.0.1", 80)
end
it "returns Socket::SOCK_STREAM" do
@addrinfo.socktype.should == Socket::SOCK_STREAM
end
end end
describe "for an ipv6 socket" do it 'returns the socket type when given' do
before :each do Addrinfo.tcp('127.0.0.1', 80).socktype.should == Socket::SOCK_STREAM
@addrinfo = Addrinfo.tcp("::1", 80)
end
it "returns Socket::SOCK_STREAM" do
@addrinfo.socktype.should == Socket::SOCK_STREAM
end
end end
platform_is_not :windows do with_feature :unix_socket do
describe "for a unix socket" do describe "for a unix socket" do
before :each do before :each do
@addrinfo = Addrinfo.unix("/tmp/sock") @addrinfo = Addrinfo.unix("/tmp/sock")

View file

@ -1,20 +1,34 @@
require_relative '../../../spec_helper' require_relative '../spec_helper'
require 'socket' require_relative '../fixtures/classes'
describe "Addrinfo.tcp" do describe 'Addrinfo.tcp' do
SocketSpecs.each_ip_protocol do |family, ip_address|
it 'returns an Addrinfo instance' do
Addrinfo.tcp(ip_address, 80).should be_an_instance_of(Addrinfo)
end
before :each do it 'sets the IP address' do
@addrinfo = Addrinfo.tcp("localhost", "smtp") Addrinfo.tcp(ip_address, 80).ip_address.should == ip_address
end end
it "creates a addrinfo for a tcp socket" do it 'sets the port' do
["::1", "127.0.0.1"].should include(@addrinfo.ip_address) Addrinfo.tcp(ip_address, 80).ip_port.should == 80
[Socket::PF_INET, Socket::PF_INET6].should include(@addrinfo.pfamily) end
@addrinfo.ip_port.should == 25
@addrinfo.socktype.should == Socket::SOCK_STREAM it 'sets the address family' do
platform_is_not :solaris do Addrinfo.tcp(ip_address, 80).afamily.should == family
@addrinfo.protocol.should == Socket::IPPROTO_TCP end
it 'sets the protocol family' do
Addrinfo.tcp(ip_address, 80).pfamily.should == family
end
it 'sets the socket type' do
Addrinfo.tcp(ip_address, 80).socktype.should == Socket::SOCK_STREAM
end
it 'sets the socket protocol' do
Addrinfo.tcp(ip_address, 80).protocol.should == Socket::IPPROTO_TCP
end end
end end
end end

View file

@ -1,6 +1,5 @@
require_relative '../../../spec_helper' require_relative '../spec_helper'
require_relative 'shared/to_sockaddr' require_relative 'shared/to_sockaddr'
require 'socket'
describe "Addrinfo#to_s" do describe "Addrinfo#to_s" do
it_behaves_like :socket_addrinfo_to_sockaddr, :to_s it_behaves_like :socket_addrinfo_to_sockaddr, :to_s

View file

@ -1,6 +1,5 @@
require_relative '../../../spec_helper' require_relative '../spec_helper'
require_relative 'shared/to_sockaddr' require_relative 'shared/to_sockaddr'
require 'socket'
describe "Addrinfo#to_sockaddr" do describe "Addrinfo#to_sockaddr" do
it_behaves_like :socket_addrinfo_to_sockaddr, :to_sockaddr it_behaves_like :socket_addrinfo_to_sockaddr, :to_sockaddr

View file

@ -1,20 +1,36 @@
require_relative '../../../spec_helper' require_relative '../spec_helper'
require 'socket' require_relative '../fixtures/classes'
describe "Addrinfo.udp" do describe 'Addrinfo.udp' do
SocketSpecs.each_ip_protocol do |family, ip_address|
it 'returns an Addrinfo instance' do
Addrinfo.udp(ip_address, 80).should be_an_instance_of(Addrinfo)
end
before :each do it 'sets the IP address' do
@addrinfo = Addrinfo.udp("localhost", "daytime") Addrinfo.udp(ip_address, 80).ip_address.should == ip_address
end end
it 'sets the port' do
Addrinfo.udp(ip_address, 80).ip_port.should == 80
end
it 'sets the address family' do
Addrinfo.udp(ip_address, 80).afamily.should == family
end
it 'sets the protocol family' do
Addrinfo.udp(ip_address, 80).pfamily.should == family
end
it 'sets the socket type' do
Addrinfo.udp(ip_address, 80).socktype.should == Socket::SOCK_DGRAM
end
it "creates a addrinfo for a tcp socket" do
["::1", "127.0.0.1"].should include(@addrinfo.ip_address)
[Socket::PF_INET, Socket::PF_INET6].should include(@addrinfo.pfamily)
@addrinfo.ip_port.should == 13
@addrinfo.socktype.should == Socket::SOCK_DGRAM
platform_is_not :solaris do platform_is_not :solaris do
@addrinfo.protocol.should == Socket::IPPROTO_UDP it 'sets the socket protocol' do
Addrinfo.udp(ip_address, 80).protocol.should == Socket::IPPROTO_UDP
end
end end
end end
end end

View file

@ -1,7 +1,6 @@
require_relative '../../../spec_helper' require_relative '../spec_helper'
require 'socket'
platform_is_not :windows do with_feature :unix_socket do
describe "Addrinfo#unix_path" do describe "Addrinfo#unix_path" do
describe "for an ipv4 socket" do describe "for an ipv4 socket" do
@ -25,15 +24,13 @@ platform_is_not :windows do
end end
end end
platform_is_not :windows do describe "for a unix socket" do
describe "for a unix socket" do before :each do
before :each do @addrinfo = Addrinfo.unix("/tmp/sock")
@addrinfo = Addrinfo.unix("/tmp/sock") end
end
it "returns the socket path" do it "returns the socket path" do
@addrinfo.unix_path.should == "/tmp/sock" @addrinfo.unix_path.should == "/tmp/sock"
end
end end
end end
end end

View file

@ -1,18 +1,35 @@
require_relative '../../../spec_helper' require_relative '../spec_helper'
require 'socket'
describe "Addrinfo.unix" do with_feature :unix_socket do
describe 'Addrinfo.unix' do
platform_is_not :windows do it 'returns an Addrinfo instance' do
before :each do Addrinfo.unix('socket').should be_an_instance_of(Addrinfo)
@addrinfo = Addrinfo.unix("/tmp/sock")
end end
it "creates a addrinfo for a unix socket" do it 'sets the IP address' do
@addrinfo.pfamily.should == Socket::PF_UNIX Addrinfo.unix('socket').unix_path.should == 'socket'
@addrinfo.socktype.should == Socket::SOCK_STREAM end
@addrinfo.protocol.should == 0
@addrinfo.unix_path.should == "/tmp/sock" 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 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)
addr.socktype.should == Socket::SOCK_DGRAM
end
it 'sets the socket protocol to 0' do
Addrinfo.unix('socket').protocol.should == 0
end end
end end
end end

View file

@ -0,0 +1,31 @@
require_relative '../spec_helper'
with_feature :ancillary_data do
describe 'Socket::AncillaryData#cmsg_is?' do
describe 'using :INET, :IP, :TTL as the family, level, and type' do
before do
@data = Socket::AncillaryData.new(:INET, :IP, :TTL, '')
end
it 'returns true when comparing with IPPROTO_IP and IP_TTL' do
@data.cmsg_is?(Socket::IPPROTO_IP, Socket::IP_TTL).should == true
end
it 'returns true when comparing with :IP and :TTL' do
@data.cmsg_is?(:IP, :TTL).should == true
end
it 'returns false when comparing with :IP and :PKTINFO' do
@data.cmsg_is?(:IP, :PKTINFO).should == false
end
it 'returns false when comparing with :SOCKET and :RIGHTS' do
@data.cmsg_is?(:SOCKET, :RIGHTS).should == false
end
it 'raises SocketError when comparign with :IPV6 and :RIGHTS' do
lambda { @data.cmsg_is?(:IPV6, :RIGHTS) }.should raise_error(SocketError)
end
end
end
end

View file

@ -0,0 +1,9 @@
require_relative '../spec_helper'
with_feature :ancillary_data do
describe 'Socket::AncillaryData#data' do
it 'returns the data as a String' do
Socket::AncillaryData.new(:INET, :SOCKET, :RIGHTS, 'ugh').data.should == 'ugh'
end
end
end

View file

@ -0,0 +1,9 @@
require_relative '../spec_helper'
with_feature :ancillary_data do
describe 'Socket::AncillaryData#family' do
it 'returns the family as a Fixnum' do
Socket::AncillaryData.new(:INET, :SOCKET, :RIGHTS, '').family.should == Socket::AF_INET
end
end
end

View file

@ -0,0 +1,282 @@
require_relative '../spec_helper'
with_feature :ancillary_data do
describe 'Socket::AncillaryData#initialize' do
describe 'using Fixnums for the family, level, and type' do
before do
@data = Socket::AncillaryData
.new(Socket::AF_INET, Socket::IPPROTO_IP, Socket::IP_RECVTTL, 'ugh')
end
it 'sets the address family' do
@data.family.should == Socket::AF_INET
end
it 'sets the message level' do
@data.level.should == Socket::IPPROTO_IP
end
it 'sets the message type' do
@data.type.should == Socket::IP_RECVTTL
end
it 'sets the data' do
@data.data.should == 'ugh'
end
end
describe 'using Symbols for the family, level, and type' do
before do
@data = Socket::AncillaryData.new(:INET, :IPPROTO_IP, :RECVTTL, 'ugh')
end
it 'sets the address family' do
@data.family.should == Socket::AF_INET
end
it 'sets the message level' do
@data.level.should == Socket::IPPROTO_IP
end
it 'sets the message type' do
@data.type.should == Socket::IP_RECVTTL
end
it 'sets the data' do
@data.data.should == 'ugh'
end
end
describe 'using Strings for the family, level, and type' do
before do
@data = Socket::AncillaryData.new('INET', 'IPPROTO_IP', 'RECVTTL', 'ugh')
end
it 'sets the address family' do
@data.family.should == Socket::AF_INET
end
it 'sets the message level' do
@data.level.should == Socket::IPPROTO_IP
end
it 'sets the message type' do
@data.type.should == Socket::IP_RECVTTL
end
it 'sets the data' do
@data.data.should == 'ugh'
end
end
describe 'using custom objects with a to_str method for the family, level, and type' do
before do
fmock = mock(:family)
lmock = mock(:level)
tmock = mock(:type)
dmock = mock(:data)
fmock.stub!(:to_str).and_return('INET')
lmock.stub!(:to_str).and_return('IP')
tmock.stub!(:to_str).and_return('RECVTTL')
dmock.stub!(:to_str).and_return('ugh')
@data = Socket::AncillaryData.new(fmock, lmock, tmock, dmock)
end
it 'sets the address family' do
@data.family.should == Socket::AF_INET
end
it 'sets the message level' do
@data.level.should == Socket::IPPROTO_IP
end
it 'sets the message type' do
@data.type.should == Socket::IP_RECVTTL
end
it 'sets the data' do
@data.data.should == 'ugh'
end
end
describe 'using :AF_INET as the family and :SOCKET as the level' do
it 'sets the type to SCM_RIGHTS when using :RIGHTS as the type argument' do
Socket::AncillaryData.new(:INET, :SOCKET, :RIGHTS, '').type.should == Socket::SCM_RIGHTS
end
it 'sets the type to SCM_TIMESTAMP when using :TIMESTAMP as the type argument' do
Socket::AncillaryData.new(:INET, :SOCKET, :TIMESTAMP, '').type.should == Socket::SCM_TIMESTAMP
end
it 'raises TypeError when using a numeric string as the type argument' do
lambda {
Socket::AncillaryData.new(:INET, :IGMP, Socket::SCM_RIGHTS.to_s, '')
}.should raise_error(TypeError)
end
it 'raises SocketError when using :RECVTTL as the type argument' do
lambda {
Socket::AncillaryData.new(:INET, :SOCKET, :RECVTTL, '')
}.should raise_error(SocketError)
end
it 'raises SocketError when using :MOO as the type argument' do
lambda {
Socket::AncillaryData.new(:INET, :SOCKET, :MOO, '')
}.should raise_error(SocketError)
end
it 'raises SocketError when using :IP_RECVTTL as the type argument' do
lambda {
Socket::AncillaryData.new(:INET, :SOCKET, :IP_RECVTTL, '')
}.should raise_error(SocketError)
end
end
describe 'using :AF_INET as the family and :SOCKET as the level' do
it 'sets the type to SCM_RIGHTS when using :RIGHTS as the type argument' do
Socket::AncillaryData.new(:INET, :SOCKET, :RIGHTS, '').type.should == Socket::SCM_RIGHTS
end
end
describe 'using :AF_INET as the family and :IP as the level' do
it 'sets the type to IP_RECVTTL when using :RECVTTL as the type argument' do
Socket::AncillaryData.new(:INET, :IP, :RECVTTL, '').type.should == Socket::IP_RECVTTL
end
with_feature :ip_mtu do
it 'sets the type to IP_MTU when using :MTU as the type argument' do
Socket::AncillaryData.new(:INET, :IP, :MTU, '').type.should == Socket::IP_MTU
end
end
it 'raises SocketError when using :RIGHTS as the type argument' do
lambda {
Socket::AncillaryData.new(:INET, :IP, :RIGHTS, '')
}.should raise_error(SocketError)
end
it 'raises SocketError when using :MOO as the type argument' do
lambda {
Socket::AncillaryData.new(:INET, :IP, :MOO, '')
}.should raise_error(SocketError)
end
end
describe 'using :AF_INET as the family and :IPV6 as the level' do
it 'sets the type to IPV6_CHECKSUM when using :CHECKSUM as the type argument' do
Socket::AncillaryData.new(:INET, :IPV6, :CHECKSUM, '').type.should == Socket::IPV6_CHECKSUM
end
with_feature :ipv6_nexthop do
it 'sets the type to IPV6_NEXTHOP when using :NEXTHOP as the type argument' do
Socket::AncillaryData.new(:INET, :IPV6, :NEXTHOP, '').type.should == Socket::IPV6_NEXTHOP
end
end
it 'raises SocketError when using :RIGHTS as the type argument' do
lambda {
Socket::AncillaryData.new(:INET, :IPV6, :RIGHTS, '')
}.should raise_error(SocketError)
end
it 'raises SocketError when using :MOO as the type argument' do
lambda {
Socket::AncillaryData.new(:INET, :IPV6, :MOO, '')
}.should raise_error(SocketError)
end
end
describe 'using :AF_INET as the family and :TCP as the level' do
with_feature :tcp_cork do
it 'sets the type to TCP_CORK when using :CORK as the type argument' do
Socket::AncillaryData.new(:INET, :TCP, :CORK, '').type.should == Socket::TCP_CORK
end
end
with_feature :tcp_info do
it 'sets the type to TCP_INFO when using :INFO as the type argument' do
Socket::AncillaryData.new(:INET, :TCP, :INFO, '').type.should == Socket::TCP_INFO
end
end
it 'raises SocketError when using :RIGHTS as the type argument' do
lambda {
Socket::AncillaryData.new(:INET, :TCP, :RIGHTS, '')
}.should raise_error(SocketError)
end
it 'raises SocketError when using :MOO as the type argument' do
lambda {
Socket::AncillaryData.new(:INET, :TCP, :MOO, '')
}.should raise_error(SocketError)
end
end
describe 'using :AF_INET as the family and :UDP as the level' do
with_feature :udp_cork do
it 'sets the type to UDP_CORK when using :CORK as the type argument' do
Socket::AncillaryData.new(:INET, :UDP, :CORK, '').type.should == Socket::UDP_CORK
end
end
it 'raises SocketError when using :RIGHTS as the type argument' do
lambda {
Socket::AncillaryData.new(:INET, :UDP, :RIGHTS, '')
}.should raise_error(SocketError)
end
it 'raises SocketError when using :MOO as the type argument' do
lambda {
Socket::AncillaryData.new(:INET, :UDP, :MOO, '')
}.should raise_error(SocketError)
end
end
describe 'using :AF_UNIX as the family and :SOCKET as the level' do
it 'sets the type to SCM_RIGHTS when using :RIGHTS as the type argument' do
Socket::AncillaryData.new(:UNIX, :SOCKET, :RIGHTS, '').type.should == Socket::SCM_RIGHTS
end
it 'raises SocketError when using :CORK sa the type argument' do
lambda {
Socket::AncillaryData.new(:UNIX, :SOCKET, :CORK, '')
}.should raise_error(SocketError)
end
end
describe 'using :AF_UNIX as the family and :IP as the level' do
it 'raises SocketError' do
lambda {
Socket::AncillaryData.new(:UNIX, :IP, :RECVTTL, '')
}.should raise_error(SocketError)
end
end
describe 'using :AF_UNIX as the family and :IPV6 as the level' do
it 'raises SocketError' do
lambda {
Socket::AncillaryData.new(:UNIX, :IPV6, :NEXTHOP, '')
}.should raise_error(SocketError)
end
end
describe 'using :AF_UNIX as the family and :TCP as the level' do
it 'raises SocketError' do
lambda {
Socket::AncillaryData.new(:UNIX, :TCP, :CORK, '')
}.should raise_error(SocketError)
end
end
describe 'using :AF_UNIX as the family and :UDP as the level' do
it 'raises SocketError' do
lambda {
Socket::AncillaryData.new(:UNIX, :UDP, :CORK, '')
}.should raise_error(SocketError)
end
end
end
end

View file

@ -0,0 +1,43 @@
require_relative '../spec_helper'
with_feature :ancillary_data do
describe 'Socket::AncillaryData.int' do
before do
@data = Socket::AncillaryData.int(:INET, :SOCKET, :RIGHTS, 4)
end
it 'returns a Socket::AncillaryData' do
@data.should be_an_instance_of(Socket::AncillaryData)
end
it 'sets the family to AF_INET' do
@data.family.should == Socket::AF_INET
end
it 'sets the level SOL_SOCKET' do
@data.level.should == Socket::SOL_SOCKET
end
it 'sets the type SCM_RIGHTS' do
@data.type.should == Socket::SCM_RIGHTS
end
it 'sets the data to a packed String' do
@data.data.should == [4].pack('I')
end
end
describe 'Socket::AncillaryData#int' do
it 'returns the data as a Fixnum' do
data = Socket::AncillaryData.int(:UNIX, :SOCKET, :RIGHTS, 4)
data.int.should == 4
end
it 'raises when the data is not a Fixnum' do
data = Socket::AncillaryData.new(:UNIX, :SOCKET, :RIGHTS, 'ugh')
lambda { data.int }.should raise_error(TypeError)
end
end
end

View file

@ -0,0 +1,145 @@
require_relative '../spec_helper'
with_feature :ancillary_data do
describe 'Socket::AncillaryData.ip_pktinfo' do
describe 'with a source address and index' do
before do
@data = Socket::AncillaryData.ip_pktinfo(Addrinfo.ip('127.0.0.1'), 4)
end
it 'returns a Socket::AncillaryData' do
@data.should be_an_instance_of(Socket::AncillaryData)
end
it 'sets the family to AF_INET' do
@data.family.should == Socket::AF_INET
end
it 'sets the level to IPPROTO_IP' do
@data.level.should == Socket::IPPROTO_IP
end
it 'sets the type to IP_PKTINFO' do
@data.type.should == Socket::IP_PKTINFO
end
end
describe 'with a source address, index, and destination address' do
before do
source = Addrinfo.ip('127.0.0.1')
dest = Addrinfo.ip('127.0.0.5')
@data = Socket::AncillaryData.ip_pktinfo(source, 4, dest)
end
it 'returns a Socket::AncillaryData' do
@data.should be_an_instance_of(Socket::AncillaryData)
end
it 'sets the family to AF_INET' do
@data.family.should == Socket::AF_INET
end
it 'sets the level to IPPROTO_IP' do
@data.level.should == Socket::IPPROTO_IP
end
it 'sets the type to IP_PKTINFO' do
@data.type.should == Socket::IP_PKTINFO
end
end
end
describe 'Socket::AncillaryData#ip_pktinfo' do
describe 'using an Addrinfo without a port number' do
before do
@source = Addrinfo.ip('127.0.0.1')
@dest = Addrinfo.ip('127.0.0.5')
@data = Socket::AncillaryData.ip_pktinfo(@source, 4, @dest)
end
it 'returns an Array' do
@data.ip_pktinfo.should be_an_instance_of(Array)
end
describe 'the returned Array' do
before do
@info = @data.ip_pktinfo
end
it 'stores an Addrinfo at index 0' do
@info[0].should be_an_instance_of(Addrinfo)
end
it 'stores the ifindex at index 1' do
@info[1].should be_an_instance_of(Fixnum)
end
it 'stores an Addrinfo at index 2' do
@info[2].should be_an_instance_of(Addrinfo)
end
end
describe 'the source Addrinfo' do
before do
@addr = @data.ip_pktinfo[0]
end
it 'uses the correct IP address' do
@addr.ip_address.should == '127.0.0.1'
end
it 'is not the same object as the input Addrinfo' do
@addr.should_not == @source
end
end
describe 'the ifindex' do
it 'is a Fixnum' do
@data.ip_pktinfo[1].should == 4
end
end
describe 'the destination Addrinfo' do
before do
@addr = @data.ip_pktinfo[2]
end
it 'uses the correct IP address' do
@addr.ip_address.should == '127.0.0.5'
end
it 'is not the same object as the input Addrinfo' do
@addr.should_not == @dest
end
end
end
describe 'using an Addrinfo with a port number' do
before do
@source = Addrinfo.tcp('127.0.0.1', 80)
@dest = Addrinfo.tcp('127.0.0.5', 85)
@data = Socket::AncillaryData.ip_pktinfo(@source, 4, @dest)
end
describe 'the source Addrinfo' do
before do
@addr = @data.ip_pktinfo[0]
end
it 'does not contain a port number' do
@addr.ip_port.should == 0
end
end
describe 'the destination Addrinfo' do
before do
@addr = @data.ip_pktinfo[2]
end
it 'does not contain a port number' do
@addr.ip_port.should == 0
end
end
end
end
end

View file

@ -0,0 +1,11 @@
require_relative '../spec_helper'
with_feature :ancillary_data, :ipv6_pktinfo do
describe 'Socket::AncillaryData#ipv6_pktinfo_addr' do
it 'returns an Addrinfo' do
data = Socket::AncillaryData.ipv6_pktinfo(Addrinfo.ip('::1'), 4)
data.ipv6_pktinfo_addr.should be_an_instance_of(Addrinfo)
end
end
end

Some files were not shown because too many files have changed in this diff Show more