aboutsummaryrefslogtreecommitdiffstats
path: root/spec
diff options
context:
space:
mode:
authorBenoit Daloze <eregontp@gmail.com>2021-01-28 17:08:57 +0100
committerBenoit Daloze <eregontp@gmail.com>2021-01-28 17:08:57 +0100
commit2e32b919b4f2f5b7f2e1509d6fa985526ef1f61c (patch)
treeaedadac3c99ca0097c2bbeaa95830332d6fb9971 /spec
parent1b377b32c8616f85c0a97e68758c5c2db83f2169 (diff)
downloadruby-2e32b919b4f2f5b7f2e1509d6fa985526ef1f61c.tar.gz
Update to ruby/spec@8cafaa5
Diffstat (limited to 'spec')
-rw-r--r--spec/ruby/core/integer/digits_spec.rb9
-rw-r--r--spec/ruby/core/kernel/caller_locations_spec.rb8
-rw-r--r--spec/ruby/core/kernel/caller_spec.rb8
-rw-r--r--spec/ruby/core/kernel/lambda_spec.rb12
-rw-r--r--spec/ruby/core/kernel/rand_spec.rb42
-rw-r--r--spec/ruby/core/module/ruby2_keywords_spec.rb112
-rw-r--r--spec/ruby/core/module/to_s_spec.rb23
-rw-r--r--spec/ruby/core/proc/ruby2_keywords_spec.rb64
-rw-r--r--spec/ruby/core/range/shared/cover.rb42
-rw-r--r--spec/ruby/core/range/shared/cover_and_include.rb7
-rw-r--r--spec/ruby/core/range/to_a_spec.rb5
-rw-r--r--spec/ruby/core/range/to_s_spec.rb7
-rw-r--r--spec/ruby/core/string/scrub_spec.rb7
-rw-r--r--spec/ruby/core/string/shared/slice.rb10
-rw-r--r--spec/ruby/core/string/split_spec.rb8
-rw-r--r--spec/ruby/core/struct/hash_spec.rb4
-rw-r--r--spec/ruby/core/symbol/name_spec.rb19
-rw-r--r--spec/ruby/core/thread/backtrace_locations_spec.rb8
-rw-r--r--spec/ruby/core/thread/handle_interrupt_spec.rb125
-rw-r--r--spec/ruby/core/thread/pending_interrupt_spec.rb32
-rw-r--r--spec/ruby/core/time/inspect_spec.rb26
-rw-r--r--spec/ruby/language/constants_spec.rb19
-rw-r--r--spec/ruby/language/fixtures/constant_visibility.rb18
-rw-r--r--spec/ruby/language/fixtures/squiggly_heredoc.rb8
-rw-r--r--spec/ruby/language/heredoc_spec.rb5
-rw-r--r--spec/ruby/library/pathname/inspect_spec.rb10
-rw-r--r--spec/ruby/library/socket/basicsocket/send_spec.rb8
-rw-r--r--spec/ruby/library/socket/tcpsocket/recv_nonblock_spec.rb14
-rw-r--r--spec/ruby/library/socket/udpsocket/recvfrom_nonblock_spec.rb7
-rw-r--r--spec/ruby/optional/capi/debug_spec.rb68
-rw-r--r--spec/ruby/optional/capi/ext/debug_spec.c93
-rw-r--r--spec/ruby/optional/capi/ext/object_spec.c1
-rw-r--r--spec/ruby/optional/capi/fixtures/module.rb4
-rw-r--r--spec/ruby/optional/capi/module_spec.rb4
-rw-r--r--spec/ruby/optional/capi/object_spec.rb5
35 files changed, 832 insertions, 10 deletions
diff --git a/spec/ruby/core/integer/digits_spec.rb b/spec/ruby/core/integer/digits_spec.rb
index 4a8e33980c..3d0a64c25f 100644
--- a/spec/ruby/core/integer/digits_spec.rb
+++ b/spec/ruby/core/integer/digits_spec.rb
@@ -29,4 +29,13 @@ describe "Integer#digits" do
it "raises Math::DomainError when calling digits on a negative number" do
-> { -12345.digits(7) }.should raise_error(Math::DomainError)
end
+
+ it "returns integer values > 9 when base is above 10" do
+ 1234.digits(16).should == [2, 13, 4]
+ end
+
+ it "can be used with base > 37" do
+ 1234.digits(100).should == [34, 12]
+ 980099.digits(100).should == [99, 0, 98]
+ end
end
diff --git a/spec/ruby/core/kernel/caller_locations_spec.rb b/spec/ruby/core/kernel/caller_locations_spec.rb
index 8050b5b3ab..bbb7e7b737 100644
--- a/spec/ruby/core/kernel/caller_locations_spec.rb
+++ b/spec/ruby/core/kernel/caller_locations_spec.rb
@@ -36,6 +36,14 @@ describe 'Kernel#caller_locations' do
end
end
+ ruby_version_is "2.7" do
+ it "works with beginless ranges" do
+ locations1 = caller_locations(0)
+ locations2 = caller_locations(eval("(...5)"))
+ locations2.map(&:to_s)[eval("(2..)")].should == locations1[eval("(...5)")].map(&:to_s)[eval("(2..)")]
+ end
+ end
+
it "can be called with a range whose end is negative" do
locations1 = caller_locations(0)
locations2 = caller_locations(2..-1)
diff --git a/spec/ruby/core/kernel/caller_spec.rb b/spec/ruby/core/kernel/caller_spec.rb
index 06e9ea6fc8..6c175868cb 100644
--- a/spec/ruby/core/kernel/caller_spec.rb
+++ b/spec/ruby/core/kernel/caller_spec.rb
@@ -52,6 +52,14 @@ describe 'Kernel#caller' do
end
end
+ ruby_version_is "2.7" do
+ it "works with beginless ranges" do
+ locations1 = KernelSpecs::CallerTest.locations(0)
+ locations2 = KernelSpecs::CallerTest.locations(eval("(..5)"))
+ locations2.map(&:to_s)[eval("(2..)")].should == locations1[eval("(..5)")].map(&:to_s)[eval("(2..)")]
+ end
+ end
+
guard -> { Kernel.instance_method(:tap).source_location } do
it "includes core library methods defined in Ruby" do
file, line = Kernel.instance_method(:tap).source_location
diff --git a/spec/ruby/core/kernel/lambda_spec.rb b/spec/ruby/core/kernel/lambda_spec.rb
index 4dd34c6ca9..9a960f3589 100644
--- a/spec/ruby/core/kernel/lambda_spec.rb
+++ b/spec/ruby/core/kernel/lambda_spec.rb
@@ -123,4 +123,16 @@ describe "Kernel.lambda" do
it "allows long returns to flow through it" do
KernelSpecs::Lambda.new.outer.should == :good
end
+
+ it "treats the block as a Proc when lambda is re-defined" do
+ klass = Class.new do
+ def lambda (&block); block; end
+ def ret
+ lambda { return 1 }.call
+ 2
+ end
+ end
+ klass.new.lambda { 42 }.should be_an_instance_of Proc
+ klass.new.ret.should == 1
+ end
end
diff --git a/spec/ruby/core/kernel/rand_spec.rb b/spec/ruby/core/kernel/rand_spec.rb
index a82b4fba74..481189d969 100644
--- a/spec/ruby/core/kernel/rand_spec.rb
+++ b/spec/ruby/core/kernel/rand_spec.rb
@@ -117,6 +117,48 @@ describe "Kernel.rand" do
end
end
+ context "given an inclusive range between 0 and 1" do
+ it "returns an Integer between the two Integers" do
+ x = rand(0..1)
+ x.should be_kind_of(Integer)
+ (0..1).should include(x)
+ end
+
+ it "returns a Float if at least one side is Float" do
+ seed = 42
+ x1 = Random.new(seed).rand(0..1.0)
+ x2 = Random.new(seed).rand(0.0..1.0)
+ x3 = Random.new(seed).rand(0.0..1)
+
+ x3.should be_kind_of(Float)
+ x1.should equal(x3)
+ x2.should equal(x3)
+
+ (0.0..1.0).should include(x3)
+ end
+ end
+
+ context "given an exclusive range between 0 and 1" do
+ it "returns zero as an Integer" do
+ x = rand(0...1)
+ x.should be_kind_of(Integer)
+ x.should eql(0)
+ end
+
+ it "returns a Float if at least one side is Float" do
+ seed = 42
+ x1 = Random.new(seed).rand(0...1.0)
+ x2 = Random.new(seed).rand(0.0...1.0)
+ x3 = Random.new(seed).rand(0.0...1)
+
+ x3.should be_kind_of(Float)
+ x1.should equal(x3)
+ x2.should equal(x3)
+
+ (0.0...1.0).should include(x3)
+ end
+ end
+
it "returns a numeric for an range argument where max is < 1" do
rand(0.25..0.75).should be_kind_of(Numeric)
end
diff --git a/spec/ruby/core/module/ruby2_keywords_spec.rb b/spec/ruby/core/module/ruby2_keywords_spec.rb
new file mode 100644
index 0000000000..34c45cb1bc
--- /dev/null
+++ b/spec/ruby/core/module/ruby2_keywords_spec.rb
@@ -0,0 +1,112 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+
+ruby_version_is "2.7" do
+ describe "Module#ruby2_keywords" do
+ it "marks the final hash argument as keyword hash" do
+ obj = Object.new
+
+ obj.singleton_class.class_exec do
+ def foo(*a) a.last end
+ ruby2_keywords :foo
+ end
+
+ last = obj.foo(1, 2, a: "a")
+ Hash.ruby2_keywords_hash?(last).should == true
+ end
+
+ ruby_version_is "2.7" ... "3.0" do
+ it "fixes delegation warnings when calling a method accepting keywords" do
+ obj = Object.new
+
+ obj.singleton_class.class_exec do
+ def foo(*a) bar(*a) end
+ def bar(*a, **b) end
+ end
+
+ -> { obj.foo(1, 2, {a: "a"}) }.should complain(/Using the last argument as keyword parameters is deprecated/)
+
+ obj.singleton_class.class_exec do
+ ruby2_keywords :foo
+ end
+
+ -> { obj.foo(1, 2, {a: "a"}) }.should_not complain
+ end
+ end
+
+ it "returns nil" do
+ obj = Object.new
+
+ obj.singleton_class.class_exec do
+ def foo(*a) end
+
+ ruby2_keywords(:foo).should == nil
+ end
+ end
+
+ it "raises NameError when passed not existing method name" do
+ obj = Object.new
+
+ -> {
+ obj.singleton_class.class_exec do
+ ruby2_keywords :not_existing
+ end
+ }.should raise_error(NameError, /undefined method `not_existing'/)
+ end
+
+ it "acceps String as well" do
+ obj = Object.new
+
+ obj.singleton_class.class_exec do
+ def foo(*a) a.last end
+ ruby2_keywords "foo"
+ end
+
+ last = obj.foo(1, 2, a: "a")
+ Hash.ruby2_keywords_hash?(last).should == true
+ end
+
+ it "raises TypeError when passed not Symbol or String" do
+ obj = Object.new
+
+ -> {
+ obj.singleton_class.class_exec do
+ ruby2_keywords Object.new
+ end
+ }.should raise_error(TypeError, /is not a symbol nor a string/)
+ end
+
+ it "prints warning when a method does not accept argument splat" do
+ obj = Object.new
+ def obj.foo(a, b, c) end
+
+ -> {
+ obj.singleton_class.class_exec do
+ ruby2_keywords :foo
+ end
+ }.should complain(/Skipping set of ruby2_keywords flag for/)
+ end
+
+ it "prints warning when a method accepts keywords" do
+ obj = Object.new
+ def obj.foo(a:, b:) end
+
+ -> {
+ obj.singleton_class.class_exec do
+ ruby2_keywords :foo
+ end
+ }.should complain(/Skipping set of ruby2_keywords flag for/)
+ end
+
+ it "prints warning when a method accepts keyword splat" do
+ obj = Object.new
+ def obj.foo(**a) end
+
+ -> {
+ obj.singleton_class.class_exec do
+ ruby2_keywords :foo
+ end
+ }.should complain(/Skipping set of ruby2_keywords flag for/)
+ end
+ end
+end
diff --git a/spec/ruby/core/module/to_s_spec.rb b/spec/ruby/core/module/to_s_spec.rb
index 29f6ecf726..6b1a615ef9 100644
--- a/spec/ruby/core/module/to_s_spec.rb
+++ b/spec/ruby/core/module/to_s_spec.rb
@@ -42,4 +42,27 @@ describe "Module#to_s" do
obj = ModuleSpecs::NamedClass.new
obj.singleton_class.to_s.should =~ /\A#<Class:#<ModuleSpecs::NamedClass:0x\h+>>\z/
end
+
+ it "always show the refinement name, even if the module is named" do
+ module ModuleSpecs::RefinementInspect
+ R = refine String do
+ end
+ end
+
+ ModuleSpecs::RefinementInspect::R.name.should == 'ModuleSpecs::RefinementInspect::R'
+ ModuleSpecs::RefinementInspect::R.to_s.should == '#<refinement:String@ModuleSpecs::RefinementInspect>'
+ end
+
+ it 'does not call #inspect or #to_s for singleton classes' do
+ klass = Class.new
+ obj = klass.new
+ def obj.to_s
+ "to_s"
+ end
+ def obj.inspect
+ "inspect"
+ end
+ sclass = obj.singleton_class
+ sclass.to_s.should =~ /\A#<Class:#<#{Regexp.escape klass.to_s}:0x\h+>>\z/
+ end
end
diff --git a/spec/ruby/core/proc/ruby2_keywords_spec.rb b/spec/ruby/core/proc/ruby2_keywords_spec.rb
new file mode 100644
index 0000000000..4f6bc151b6
--- /dev/null
+++ b/spec/ruby/core/proc/ruby2_keywords_spec.rb
@@ -0,0 +1,64 @@
+require_relative '../../spec_helper'
+
+ruby_version_is "2.7" do
+ describe "Proc#ruby2_keywords" do
+ it "marks the final hash argument as keyword hash" do
+ f = -> *a { a.last }
+ f.ruby2_keywords
+
+ last = f.call(1, 2, a: "a")
+ Hash.ruby2_keywords_hash?(last).should == true
+ end
+
+ ruby_version_is "2.7" ... "3.0" do
+ it "fixes delegation warnings when calling a method accepting keywords" do
+ obj = Object.new
+ def obj.foo(*a, **b) end
+
+ f = -> *a { obj.foo(*a) }
+
+ -> { f.call(1, 2, {a: "a"}) }.should complain(/Using the last argument as keyword parameters is deprecated/)
+ f.ruby2_keywords
+ -> { f.call(1, 2, {a: "a"}) }.should_not complain
+ end
+
+ it "fixes delegation warnings when calling a proc accepting keywords" do
+ g = -> *a, **b { }
+ f = -> *a { g.call(*a) }
+
+ -> { f.call(1, 2, {a: "a"}) }.should complain(/Using the last argument as keyword parameters is deprecated/)
+ f.ruby2_keywords
+ -> { f.call(1, 2, {a: "a"}) }.should_not complain
+ end
+ end
+
+ it "returns self" do
+ f = -> *a { }
+ f.ruby2_keywords.should equal f
+ end
+
+ it "prints warning when a proc does not accept argument splat" do
+ f = -> a, b, c { }
+
+ -> {
+ f.ruby2_keywords
+ }.should complain(/Skipping set of ruby2_keywords flag for/)
+ end
+
+ it "prints warning when a proc accepts keywords" do
+ f = -> a:, b: { }
+
+ -> {
+ f.ruby2_keywords
+ }.should complain(/Skipping set of ruby2_keywords flag for/)
+ end
+
+ it "prints warning when a proc accepts keyword splat" do
+ f = -> **a { }
+
+ -> {
+ f.ruby2_keywords
+ }.should complain(/Skipping set of ruby2_keywords flag for/)
+ end
+ end
+end
diff --git a/spec/ruby/core/range/shared/cover.rb b/spec/ruby/core/range/shared/cover.rb
index 5b09cea4e0..e04682ba71 100644
--- a/spec/ruby/core/range/shared/cover.rb
+++ b/spec/ruby/core/range/shared/cover.rb
@@ -152,4 +152,46 @@ describe :range_cover_subrange, shared: true do
end
end
end
+
+ ruby_version_is "2.7" do
+ it "allows self to be a beginless range" do
+ eval("(...10)").send(@method, (3..7)).should be_true
+ eval("(...10)").send(@method, (3..15)).should be_false
+
+ eval("(..7.9)").send(@method, (2.5..6.5)).should be_true
+ eval("(..7.9)").send(@method, (2.5..8.5)).should be_false
+
+ eval("(..'i')").send(@method, ('d'..'f')).should be_true
+ eval("(..'i')").send(@method, ('d'..'z')).should be_false
+ end
+
+ it "allows self to be a endless range" do
+ eval("(0...)").send(@method, (3..7)).should be_true
+ eval("(5...)").send(@method, (3..15)).should be_false
+
+ eval("(1.1..)").send(@method, (2.5..6.5)).should be_true
+ eval("(3.3..)").send(@method, (2.5..8.5)).should be_false
+
+ eval("('a'..)").send(@method, ('d'..'f')).should be_true
+ eval("('p'..)").send(@method, ('d'..'z')).should be_false
+ end
+
+ it "accepts beginless range argument" do
+ eval("(..10)").send(@method, eval("(...10)")).should be_true
+ (0..10).send(@method, eval("(...10)")).should be_false
+
+ (1.1..7.9).send(@method, eval("(...10.5)")).should be_false
+
+ ('c'..'i').send(@method, eval("(..'i')")).should be_false
+ end
+
+ it "accepts endless range argument" do
+ eval("(0..)").send(@method, eval("(0...)")).should be_true
+ (0..10).send(@method, eval("(0...)")).should be_false
+
+ (1.1..7.9).send(@method, eval("(0.8...)")).should be_false
+
+ ('c'..'i').send(@method, eval("('a'..)")).should be_false
+ end
+ end
end
diff --git a/spec/ruby/core/range/shared/cover_and_include.rb b/spec/ruby/core/range/shared/cover_and_include.rb
index b308524310..0267e3ccb0 100644
--- a/spec/ruby/core/range/shared/cover_and_include.rb
+++ b/spec/ruby/core/range/shared/cover_and_include.rb
@@ -26,6 +26,13 @@ describe :range_cover_and_include, shared: true do
end
end
+ ruby_version_is "2.7" do
+ it "returns true if other is an element of self for beginless ranges" do
+ eval("(..10)").send(@method, 2.4).should == true
+ eval("(...10.5)").send(@method, 2.4).should == true
+ end
+ end
+
it "compares values using <=>" do
rng = (1..5)
m = mock("int")
diff --git a/spec/ruby/core/range/to_a_spec.rb b/spec/ruby/core/range/to_a_spec.rb
index 08f50e4d9e..9a1352b7b0 100644
--- a/spec/ruby/core/range/to_a_spec.rb
+++ b/spec/ruby/core/range/to_a_spec.rb
@@ -16,6 +16,11 @@ describe "Range#to_a" do
(0xffff...0xfffd).to_a.should == []
end
+ it "works with Ranges of 64-bit integers" do
+ large = 1 << 40
+ (large..large+1).to_a.should == [1099511627776, 1099511627777]
+ end
+
it "works with Ranges of Symbols" do
(:A..:z).to_a.size.should == 58
end
diff --git a/spec/ruby/core/range/to_s_spec.rb b/spec/ruby/core/range/to_s_spec.rb
index ccbc5d8e7e..59672da822 100644
--- a/spec/ruby/core/range/to_s_spec.rb
+++ b/spec/ruby/core/range/to_s_spec.rb
@@ -18,6 +18,13 @@ describe "Range#to_s" do
end
end
+ ruby_version_is "2.7" do
+ it "can show beginless ranges" do
+ eval("(..1)").to_s.should == "..1"
+ eval("(...1.0)").to_s.should == "...1.0"
+ end
+ end
+
ruby_version_is ''...'2.7' do
it "returns a tainted string if either end is tainted" do
(("a".taint)..."c").to_s.tainted?.should be_true
diff --git a/spec/ruby/core/string/scrub_spec.rb b/spec/ruby/core/string/scrub_spec.rb
index 390035ef30..86fd4e85ba 100644
--- a/spec/ruby/core/string/scrub_spec.rb
+++ b/spec/ruby/core/string/scrub_spec.rb
@@ -39,6 +39,13 @@ describe "String#scrub with a custom replacement" do
"abc\u3042#{x81}".scrub("*").should == "abc\u3042*"
end
+ it "replaces invalid byte sequences in frozen strings" do
+ x81 = [0x81].pack('C').force_encoding('utf-8')
+ (-"abc\u3042#{x81}").scrub("*").should == "abc\u3042*"
+ utf16_str = ("abc".encode('UTF-16LE').bytes + [0x81]).pack('c*').force_encoding('UTF-16LE')
+ (-(utf16_str)).scrub("*".encode('UTF-16LE')).should == "abc*".encode('UTF-16LE')
+ end
+
it "replaces an incomplete character at the end with a single replacement" do
xE3x80 = [0xE3, 0x80].pack('CC').force_encoding 'utf-8'
xE3x80.scrub("*").should == "*"
diff --git a/spec/ruby/core/string/shared/slice.rb b/spec/ruby/core/string/shared/slice.rb
index 69997b7c1d..a674e0b6ef 100644
--- a/spec/ruby/core/string/shared/slice.rb
+++ b/spec/ruby/core/string/shared/slice.rb
@@ -335,6 +335,16 @@ describe :string_slice_range, shared: true do
"hello there".send(@method, eval("(-4...)")).should == "here"
end
end
+
+ ruby_version_is "2.7" do
+ it "works with beginless ranges" do
+ "hello there".send(@method, eval("(..5)")).should == "hello "
+ "hello there".send(@method, eval("(...5)")).should == "hello"
+ "hello there".send(@method, eval("(..-4)")).should == "hello th"
+ "hello there".send(@method, eval("(...-4)")).should == "hello t"
+ "hello there".send(@method, eval("(...nil)")).should == "hello there"
+ end
+ end
end
describe :string_slice_regexp, shared: true do
diff --git a/spec/ruby/core/string/split_spec.rb b/spec/ruby/core/string/split_spec.rb
index c5441e3a49..2ebfe1e353 100644
--- a/spec/ruby/core/string/split_spec.rb
+++ b/spec/ruby/core/string/split_spec.rb
@@ -471,6 +471,14 @@ describe "String#split with Regexp" do
a.should == ["Chunky", "Bacon"]
end
+ it "yields each split substring with default pattern for a non-ASCII string" do
+ a = []
+ returned_object = "l'été arrive bientôt".split { |str| a << str }
+
+ returned_object.should == "l'été arrive bientôt"
+ a.should == ["l'été", "arrive", "bientôt"]
+ end
+
it "yields the string when limit is 1" do
a = []
returned_object = "chunky bacon".split("", 1) { |str| a << str.capitalize }
diff --git a/spec/ruby/core/struct/hash_spec.rb b/spec/ruby/core/struct/hash_spec.rb
index d3c95fbe56..53361eb7a9 100644
--- a/spec/ruby/core/struct/hash_spec.rb
+++ b/spec/ruby/core/struct/hash_spec.rb
@@ -56,5 +56,9 @@ describe "Struct#hash" do
# See the Struct#eql? specs
end
+ it "returns different hashes for different struct classes" do
+ Struct.new(:x).new(1).hash.should != Struct.new(:y).new(1).hash
+ end
+
it_behaves_like :struct_accessor, :hash
end
diff --git a/spec/ruby/core/symbol/name_spec.rb b/spec/ruby/core/symbol/name_spec.rb
new file mode 100644
index 0000000000..15b9aa75e9
--- /dev/null
+++ b/spec/ruby/core/symbol/name_spec.rb
@@ -0,0 +1,19 @@
+require_relative '../../spec_helper'
+
+ruby_version_is "3.0" do
+ describe "Symbol#name" do
+ it "returns string" do
+ :ruby.name.should == "ruby"
+ :ルビー.name.should == "ルビー"
+ end
+
+ it "returns same string instance" do
+ :"ruby_3".name.should.equal?(:ruby_3.name)
+ :"ruby_#{1+2}".name.should.equal?(:ruby_3.name)
+ end
+
+ it "returns frozen string" do
+ :symbol.name.should.frozen?
+ end
+ end
+end
diff --git a/spec/ruby/core/thread/backtrace_locations_spec.rb b/spec/ruby/core/thread/backtrace_locations_spec.rb
index ead4be2d8c..1f77e13378 100644
--- a/spec/ruby/core/thread/backtrace_locations_spec.rb
+++ b/spec/ruby/core/thread/backtrace_locations_spec.rb
@@ -51,6 +51,14 @@ describe "Thread#backtrace_locations" do
end
end
+ ruby_version_is "2.7" do
+ it "can be called with an beginless range" do
+ locations1 = Thread.current.backtrace_locations(0)
+ locations2 = Thread.current.backtrace_locations(eval("(..5)"))
+ locations2.map(&:to_s)[eval("(2..)")].should == locations1[eval("(..5)")].map(&:to_s)[eval("(2..)")]
+ end
+ end
+
it "returns nil if omitting more locations than available" do
Thread.current.backtrace_locations(100).should == nil
Thread.current.backtrace_locations(100..-1).should == nil
diff --git a/spec/ruby/core/thread/handle_interrupt_spec.rb b/spec/ruby/core/thread/handle_interrupt_spec.rb
new file mode 100644
index 0000000000..ea7e81cb98
--- /dev/null
+++ b/spec/ruby/core/thread/handle_interrupt_spec.rb
@@ -0,0 +1,125 @@
+require_relative '../../spec_helper'
+
+describe "Thread.handle_interrupt" do
+ def make_handle_interrupt_thread(interrupt_config, blocking = true)
+ interrupt_class = Class.new(RuntimeError)
+
+ ScratchPad.record []
+
+ in_handle_interrupt = Queue.new
+ can_continue = Queue.new
+
+ thread = Thread.new do
+ begin
+ Thread.handle_interrupt(interrupt_config) do
+ begin
+ in_handle_interrupt << true
+ if blocking
+ Thread.pass # Make it clearer the other thread needs to wait for this one to be in #pop
+ can_continue.pop
+ else
+ begin
+ can_continue.pop(true)
+ rescue ThreadError
+ Thread.pass
+ retry
+ end
+ end
+ rescue interrupt_class
+ ScratchPad << :interrupted
+ end
+ end
+ rescue interrupt_class
+ ScratchPad << :deferred
+ end
+ end
+
+ in_handle_interrupt.pop
+ if blocking
+ # Ensure the thread is inside Thread#pop, as if thread.raise is done before it would be deferred
+ Thread.pass until thread.stop?
+ end
+ thread.raise interrupt_class, "interrupt"
+ can_continue << true
+ thread.join
+
+ ScratchPad.recorded
+ end
+
+ before :each do
+ Thread.pending_interrupt?.should == false # sanity check
+ end
+
+ it "with :never defers interrupts until exiting the handle_interrupt block" do
+ make_handle_interrupt_thread(RuntimeError => :never).should == [:deferred]
+ end
+
+ it "with :on_blocking defers interrupts until the next blocking call" do
+ make_handle_interrupt_thread(RuntimeError => :on_blocking).should == [:interrupted]
+ make_handle_interrupt_thread({ RuntimeError => :on_blocking }, false).should == [:deferred]
+ end
+
+ it "with :immediate handles interrupts immediately" do
+ make_handle_interrupt_thread(RuntimeError => :immediate).should == [:interrupted]
+ end
+
+ it "with :immediate immediately runs pending interrupts, before the block" do
+ Thread.handle_interrupt(RuntimeError => :never) do
+ current = Thread.current
+ Thread.new {
+ current.raise "interrupt immediate"
+ }.join
+
+ Thread.pending_interrupt?.should == true
+ -> {
+ Thread.handle_interrupt(RuntimeError => :immediate) {
+ flunk "not reached"
+ }
+ }.should raise_error(RuntimeError, "interrupt immediate")
+ Thread.pending_interrupt?.should == false
+ end
+ end
+
+ it "also works with suspended Fibers and does not duplicate interrupts" do
+ fiber = Fiber.new { Fiber.yield }
+ fiber.resume
+
+ Thread.handle_interrupt(RuntimeError => :never) do
+ current = Thread.current
+ Thread.new {
+ current.raise "interrupt with fibers"
+ }.join
+
+ Thread.pending_interrupt?.should == true
+ -> {
+ Thread.handle_interrupt(RuntimeError => :immediate) {
+ flunk "not reached"
+ }
+ }.should raise_error(RuntimeError, "interrupt with fibers")
+ Thread.pending_interrupt?.should == false
+ end
+
+ fiber.resume
+ end
+
+ it "runs pending interrupts at the end of the block, even if there was an exception raised in the block" do
+ executed = false
+ -> {
+ Thread.handle_interrupt(RuntimeError => :never) do
+ current = Thread.current
+ Thread.new {
+ current.raise "interrupt exception"
+ }.join
+
+ Thread.pending_interrupt?.should == true
+ executed = true
+ raise "regular exception"
+ end
+ }.should raise_error(RuntimeError, "interrupt exception")
+ executed.should == true
+ end
+
+ it "supports multiple pairs in the Hash" do
+ make_handle_interrupt_thread(ArgumentError => :never, RuntimeError => :never).should == [:deferred]
+ end
+end
diff --git a/spec/ruby/core/thread/pending_interrupt_spec.rb b/spec/ruby/core/thread/pending_interrupt_spec.rb
new file mode 100644
index 0000000000..cd565d92a4
--- /dev/null
+++ b/spec/ruby/core/thread/pending_interrupt_spec.rb
@@ -0,0 +1,32 @@
+require_relative '../../spec_helper'
+
+describe "Thread.pending_interrupt?" do
+ it "returns false if there are no pending interrupts, e.g., outside any Thread.handle_interrupt block" do
+ Thread.pending_interrupt?.should == false
+ end
+
+ it "returns true if there are pending interrupts, e.g., Thread#raise inside Thread.handle_interrupt" do
+ executed = false
+ -> {
+ Thread.handle_interrupt(RuntimeError => :never) do
+ Thread.pending_interrupt?.should == false
+
+ current = Thread.current
+ Thread.new {
+ current.raise "interrupt"
+ }.join
+
+ Thread.pending_interrupt?.should == true
+ executed = true
+ end
+ }.should raise_error(RuntimeError, "interrupt")
+ executed.should == true
+ Thread.pending_interrupt?.should == false
+ end
+end
+
+describe "Thread#pending_interrupt?" do
+ it "returns whether the given threads has pending interrupts" do
+ Thread.current.pending_interrupt?.should == false
+ end
+end
diff --git a/spec/ruby/core/time/inspect_spec.rb b/spec/ruby/core/time/inspect_spec.rb
index 85133838e2..6f1b2e3ef1 100644
--- a/spec/ruby/core/time/inspect_spec.rb
+++ b/spec/ruby/core/time/inspect_spec.rb
@@ -5,17 +5,31 @@ describe "Time#inspect" do
it_behaves_like :inspect, :inspect
ruby_version_is "2.7" do
- it "preserves milliseconds" do
+ it "preserves microseconds" do
t = Time.utc(2007, 11, 1, 15, 25, 0, 123456)
t.inspect.should == "2007-11-01 15:25:00.123456 UTC"
end
- it "formats nanoseconds as a Rational" do
- t = Time.utc(2007, 11, 1, 15, 25, 0, 123456.789)
- t.nsec.should == 123456789
- t.strftime("%N").should == "123456789"
+ it "omits trailing zeros from microseconds" do
+ t = Time.utc(2007, 11, 1, 15, 25, 0, 100000)
+ t.inspect.should == "2007-11-01 15:25:00.1 UTC"
+ end
+
+ it "uses the correct time zone without microseconds" do
+ t = Time.utc(2000, 1, 1)
+ t = t.localtime(9*3600)
+ t.inspect.should == "2000-01-01 09:00:00 +0900"
+ end
+
+ it "uses the correct time zone with microseconds" do
+ t = Time.utc(2000, 1, 1, 0, 0, 0, 123456)
+ t = t.localtime(9*3600)
+ t.inspect.should == "2000-01-01 09:00:00.123456 +0900"
+ end
- t.inspect.should == "2007-11-01 15:25:00 8483885939586761/68719476736000000 UTC"
+ it "preserves nanoseconds" do
+ t = Time.utc(2007, 11, 1, 15, 25, 0, 123456.789r)
+ t.inspect.should == "2007-11-01 15:25:00.123456789 UTC"
end
end
end
diff --git a/spec/ruby/language/constants_spec.rb b/spec/ruby/language/constants_spec.rb
index 4d46cf2f84..6d3b1a5dd7 100644
--- a/spec/ruby/language/constants_spec.rb
+++ b/spec/ruby/language/constants_spec.rb
@@ -551,11 +551,24 @@ describe "Module#private_constant marked constants" do
end
it "can be accessed from classes that include the module" do
- ConstantVisibility::PrivConstModuleChild.new.private_constant_from_include.should be_true
+ ConstantVisibility::ClassIncludingPrivConstModule.new.private_constant_from_include.should be_true
+ end
+
+ it "can be accessed from modules that include the module" do
+ ConstantVisibility::ModuleIncludingPrivConstModule.private_constant_from_include.should be_true
+ end
+
+ it "raises a NameError when accessed directly from modules that include the module" do
+ -> do
+ ConstantVisibility::ModuleIncludingPrivConstModule.private_constant_self_from_include
+ end.should raise_error(NameError)
+ -> do
+ ConstantVisibility::ModuleIncludingPrivConstModule.private_constant_named_from_include
+ end.should raise_error(NameError)
end
it "is defined? from classes that include the module" do
- ConstantVisibility::PrivConstModuleChild.new.defined_from_include.should == "constant"
+ ConstantVisibility::ClassIncludingPrivConstModule.new.defined_from_include.should == "constant"
end
end
@@ -673,7 +686,7 @@ describe "Module#private_constant marked constants" do
}
-> do
- ConstantVisibility::PrivConstModuleChild::PRIVATE_CONSTANT_MODULE
+ ConstantVisibility::ClassIncludingPrivConstModule::PRIVATE_CONSTANT_MODULE
end.should raise_error(NameError) {|e|
e.receiver.should == ConstantVisibility::PrivConstModule
e.name.should == :PRIVATE_CONSTANT_MODULE
diff --git a/spec/ruby/language/fixtures/constant_visibility.rb b/spec/ruby/language/fixtures/constant_visibility.rb
index 022554430e..af38b2d8f2 100644
--- a/spec/ruby/language/fixtures/constant_visibility.rb
+++ b/spec/ruby/language/fixtures/constant_visibility.rb
@@ -65,7 +65,7 @@ module ConstantVisibility
end
end
- class PrivConstModuleChild
+ class ClassIncludingPrivConstModule
include PrivConstModule
def private_constant_from_include
@@ -77,6 +77,22 @@ module ConstantVisibility
end
end
+ module ModuleIncludingPrivConstModule
+ include PrivConstModule
+
+ def self.private_constant_from_include
+ PRIVATE_CONSTANT_MODULE
+ end
+
+ def self.private_constant_self_from_include
+ self::PRIVATE_CONSTANT_MODULE
+ end
+
+ def self.private_constant_named_from_include
+ PrivConstModule::PRIVATE_CONSTANT_MODULE
+ end
+ end
+
class PrivConstClassChild < PrivConstClass
def private_constant_from_subclass
PRIVATE_CONSTANT_CLASS
diff --git a/spec/ruby/language/fixtures/squiggly_heredoc.rb b/spec/ruby/language/fixtures/squiggly_heredoc.rb
index d223966b93..984a629e5b 100644
--- a/spec/ruby/language/fixtures/squiggly_heredoc.rb
+++ b/spec/ruby/language/fixtures/squiggly_heredoc.rb
@@ -29,6 +29,14 @@ module SquigglyHeredocSpecs
HERE
end
+ def self.backslash
+ <<~HERE
+ a
+ b\
+ c
+ HERE
+ end
+
def self.least_indented_on_the_first_line
<<~HERE
a
diff --git a/spec/ruby/language/heredoc_spec.rb b/spec/ruby/language/heredoc_spec.rb
index 95df8457e4..61a27ad8e0 100644
--- a/spec/ruby/language/heredoc_spec.rb
+++ b/spec/ruby/language/heredoc_spec.rb
@@ -100,6 +100,11 @@ HERE
SquigglyHeredocSpecs.singlequoted.should == "singlequoted \#{\"interpolated\"}\n"
end
+ it "allows HEREDOC with <<~'identifier', no interpolation, with backslash" do
+ require_relative 'fixtures/squiggly_heredoc'
+ SquigglyHeredocSpecs.backslash.should == "a\nbc\n"
+ end
+
it "selects the least-indented line and removes its indentation from all the lines" do
require_relative 'fixtures/squiggly_heredoc'
SquigglyHeredocSpecs.least_indented_on_the_first_line.should == "a\n b\n c\n"
diff --git a/spec/ruby/library/pathname/inspect_spec.rb b/spec/ruby/library/pathname/inspect_spec.rb
new file mode 100644
index 0000000000..304746fbe5
--- /dev/null
+++ b/spec/ruby/library/pathname/inspect_spec.rb
@@ -0,0 +1,10 @@
+require_relative '../../spec_helper'
+require 'pathname'
+
+describe "Pathname#inspect" do
+ it "returns a consistent String" do
+ result = Pathname.new('/tmp').inspect
+ result.should be_an_instance_of(String)
+ result.should == "#<Pathname:/tmp>"
+ end
+end
diff --git a/spec/ruby/library/socket/basicsocket/send_spec.rb b/spec/ruby/library/socket/basicsocket/send_spec.rb
index 041ee46998..868801df30 100644
--- a/spec/ruby/library/socket/basicsocket/send_spec.rb
+++ b/spec/ruby/library/socket/basicsocket/send_spec.rb
@@ -99,6 +99,14 @@ describe 'BasicSocket#send' do
@server.close
end
+ describe 'with an object implementing #to_str' do
+ it 'returns the amount of sent bytes' do
+ data = mock('message')
+ data.should_receive(:to_str).and_return('hello')
+ @client.send(data, 0, @server.getsockname).should == 5
+ end
+ end
+
describe 'without a destination address' do
it "raises #{SocketSpecs.dest_addr_req_error}" do
-> { @client.send('hello', 0) }.should raise_error(SocketSpecs.dest_addr_req_error)
diff --git a/spec/ruby/library/socket/tcpsocket/recv_nonblock_spec.rb b/spec/ruby/library/socket/tcpsocket/recv_nonblock_spec.rb
index bfd815c658..6ce5a41b58 100644
--- a/spec/ruby/library/socket/tcpsocket/recv_nonblock_spec.rb
+++ b/spec/ruby/library/socket/tcpsocket/recv_nonblock_spec.rb
@@ -27,6 +27,20 @@ describe "TCPSocket#recv_nonblock" do
@socket.recv_nonblock(50).should == "TCPSocket#recv_nonblock"
end
+ it 'writes the read to a buffer from the socket' do
+ @socket = TCPSocket.new @hostname, @server.port
+ @socket.write "TCPSocket#recv_nonblock"
+
+ # Wait for the server to echo. This spec is testing the return
+ # value, not the non-blocking behavior.
+ #
+ # TODO: Figure out a good way to test non-blocking.
+ IO.select([@socket])
+ buffer = "".b
+ @socket.recv_nonblock(50, 0, buffer)
+ buffer.should == 'TCPSocket#recv_nonblock'
+ end
+
it 'returns :wait_readable in exceptionless mode' do
@socket = TCPSocket.new @hostname, @server.port
@socket.recv_nonblock(50, exception: false).should == :wait_readable
diff --git a/spec/ruby/library/socket/udpsocket/recvfrom_nonblock_spec.rb b/spec/ruby/library/socket/udpsocket/recvfrom_nonblock_spec.rb
index c66d1df84d..650a061221 100644
--- a/spec/ruby/library/socket/udpsocket/recvfrom_nonblock_spec.rb
+++ b/spec/ruby/library/socket/udpsocket/recvfrom_nonblock_spec.rb
@@ -51,6 +51,13 @@ describe 'UDPSocket#recvfrom_nonblock' do
@server.recvfrom_nonblock(1).should be_an_instance_of(Array)
end
+ it 'writes the data to the buffer when one is present' do
+ buffer = "".b
+ IO.select([@server])
+ @server.recvfrom_nonblock(1, 0, buffer)
+ buffer.should == 'h'
+ end
+
describe 'the returned Array' do
before do
IO.select([@server])
diff --git a/spec/ruby/optional/capi/debug_spec.rb b/spec/ruby/optional/capi/debug_spec.rb
new file mode 100644
index 0000000000..89e72f0049
--- /dev/null
+++ b/spec/ruby/optional/capi/debug_spec.rb
@@ -0,0 +1,68 @@
+require_relative 'spec_helper'
+
+load_extension('debug')
+
+describe "C-API Debug function" do
+ before :each do
+ @o = CApiDebugSpecs.new
+ end
+
+ describe "rb_debug_inspector_open" do
+ it "creates a debug context and calls the given callback" do
+ @o.rb_debug_inspector_open(42).should be_kind_of(Array)
+ @o.debug_spec_callback_data.should == 42
+ end
+ end
+
+ describe "rb_debug_inspector_frame_self_get" do
+ it "returns self" do
+ @o.rb_debug_inspector_frame_self_get(0).should == @o
+ end
+ end
+
+ describe "rb_debug_inspector_frame_class_get" do
+ it "returns the frame class" do
+ @o.rb_debug_inspector_frame_class_get(0).should == CApiDebugSpecs
+ end
+ end
+
+ describe "rb_debug_inspector_frame_binding_get" do
+ it "returns the current binding" do
+ a = "test"
+ b = @o.rb_debug_inspector_frame_binding_get(1)
+ b.should be_an_instance_of(Binding)
+ b.local_variable_get(:a).should == "test"
+ end
+
+ ruby_version_is "2.6" do
+ it "matches the locations in rb_debug_inspector_backtrace_locations" do
+ frames = @o.rb_debug_inspector_open(42);
+ frames.each do |_s, _klass, binding, _iseq, backtrace_location|
+ if binding
+ "#{backtrace_location.path}:#{backtrace_location.lineno}".should == "#{binding.source_location[0]}:#{binding.source_location[1]}"
+ end
+ end
+ end
+ end
+ end
+
+ describe "rb_debug_inspector_frame_iseq_get" do
+ it "returns an InstructionSequence" do
+ if defined?(RubyVM::InstructionSequence)
+ @o.rb_debug_inspector_frame_iseq_get(1).should be_an_instance_of(RubyVM::InstructionSequence)
+ else
+ @o.rb_debug_inspector_frame_iseq_get(1).should == nil
+ end
+ end
+ end
+
+ describe "rb_debug_inspector_backtrace_locations" do
+ it "returns an array of Thread::Backtrace::Location" do
+ bts = @o.rb_debug_inspector_backtrace_locations
+ bts.should_not.empty?
+ bts.each { |bt| bt.should be_kind_of(Thread::Backtrace::Location) }
+ location = "#{__FILE__}:#{__LINE__ - 3}"
+ bts[1].to_s.should include(location)
+ end
+ end
+end
diff --git a/spec/ruby/optional/capi/ext/debug_spec.c b/spec/ruby/optional/capi/ext/debug_spec.c
new file mode 100644
index 0000000000..344dfc33fa
--- /dev/null
+++ b/spec/ruby/optional/capi/ext/debug_spec.c
@@ -0,0 +1,93 @@
+#include "ruby.h"
+#include "rubyspec.h"
+#include "ruby/debug.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+static VALUE callback_data = Qfalse;
+
+static VALUE rb_debug_inspector_open_callback(const rb_debug_inspector_t *dc, void *ptr) {
+ if (!dc) {
+ rb_raise(rb_eRuntimeError, "rb_debug_inspector_t should not be NULL");
+ }
+
+ VALUE locations = rb_debug_inspector_backtrace_locations(dc);
+ int len = RARRAY_LENINT(locations);
+ VALUE results = rb_ary_new2(len);
+ for (int i = 0; i < len; i++) {
+ VALUE ary = rb_ary_new2(5); // [self, klass, binding, iseq, backtrace_location]
+ rb_ary_store(ary, 0, rb_debug_inspector_frame_self_get(dc, i));
+ rb_ary_store(ary, 1, rb_debug_inspector_frame_class_get(dc, i));
+ rb_ary_store(ary, 2, rb_debug_inspector_frame_binding_get(dc, i));
+ rb_ary_store(ary, 3, rb_debug_inspector_frame_iseq_get(dc, i));
+ rb_ary_store(ary, 4, rb_ary_entry(locations, i));
+ rb_ary_push(results, ary);
+ }
+ callback_data = (VALUE)ptr;
+ return results;
+}
+
+static VALUE rb_debug_inspector_frame_self_get_callback(const rb_debug_inspector_t *dc, void *ptr) {
+ return rb_debug_inspector_frame_self_get(dc, NUM2LONG((VALUE) ptr));
+}
+
+static VALUE rb_debug_inspector_frame_class_get_callback(const rb_debug_inspector_t *dc, void *ptr) {
+ return rb_debug_inspector_frame_class_get(dc, NUM2LONG((VALUE) ptr));
+}
+
+static VALUE rb_debug_inspector_frame_binding_get_callback(const rb_debug_inspector_t *dc, void *ptr) {
+ return rb_debug_inspector_frame_binding_get(dc, NUM2LONG((VALUE) ptr));
+}
+
+static VALUE rb_debug_inspector_frame_iseq_get_callback(const rb_debug_inspector_t *dc, void *ptr) {
+ return rb_debug_inspector_frame_iseq_get(dc, NUM2LONG((VALUE) ptr));
+}
+
+static VALUE debug_spec_callback_data(VALUE self){
+ return callback_data;
+}
+
+VALUE debug_spec_rb_debug_inspector_open(VALUE self, VALUE index) {
+ return rb_debug_inspector_open(rb_debug_inspector_open_callback, (void *)index);
+}
+
+VALUE debug_spec_rb_debug_inspector_frame_self_get(VALUE self, VALUE index) {
+ return rb_debug_inspector_open(rb_debug_inspector_frame_self_get_callback, (void *)index);
+}
+
+VALUE debug_spec_rb_debug_inspector_frame_class_get(VALUE self, VALUE index) {
+ return rb_debug_inspector_open(rb_debug_inspector_frame_class_get_callback, (void *)index);
+}
+
+VALUE debug_spec_rb_debug_inspector_frame_binding_get(VALUE self, VALUE index) {
+ return rb_debug_inspector_open(rb_debug_inspector_frame_binding_get_callback, (void *)index);
+}
+
+VALUE debug_spec_rb_debug_inspector_frame_iseq_get(VALUE self, VALUE index) {
+ return rb_debug_inspector_open(rb_debug_inspector_frame_iseq_get_callback, (void *)index);
+}
+
+static VALUE rb_debug_inspector_backtrace_locations_func(const rb_debug_inspector_t *dc, void *ptr) {
+ return rb_debug_inspector_backtrace_locations(dc);
+}
+
+VALUE debug_spec_rb_debug_inspector_backtrace_locations(VALUE self) {
+ return rb_debug_inspector_open(rb_debug_inspector_backtrace_locations_func, (void *)self);
+}
+
+void Init_debug_spec(void) {
+ VALUE cls = rb_define_class("CApiDebugSpecs", rb_cObject);
+ rb_define_method(cls, "rb_debug_inspector_open", debug_spec_rb_debug_inspector_open, 1);
+ rb_define_method(cls, "rb_debug_inspector_frame_self_get", debug_spec_rb_debug_inspector_frame_self_get, 1);
+ rb_define_method(cls, "rb_debug_inspector_frame_class_get", debug_spec_rb_debug_inspector_frame_class_get, 1);
+ rb_define_method(cls, "rb_debug_inspector_frame_binding_get", debug_spec_rb_debug_inspector_frame_binding_get, 1);
+ rb_define_method(cls, "rb_debug_inspector_frame_iseq_get", debug_spec_rb_debug_inspector_frame_iseq_get, 1);
+ rb_define_method(cls, "rb_debug_inspector_backtrace_locations", debug_spec_rb_debug_inspector_backtrace_locations, 0);
+ rb_define_method(cls, "debug_spec_callback_data", debug_spec_callback_data, 0);
+}
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/spec/ruby/optional/capi/ext/object_spec.c b/spec/ruby/optional/capi/ext/object_spec.c
index 59237e8549..a229301f40 100644
--- a/spec/ruby/optional/capi/ext/object_spec.c
+++ b/spec/ruby/optional/capi/ext/object_spec.c
@@ -462,6 +462,7 @@ void Init_object_spec(void) {
rb_define_method(cls, "rb_undef_alloc_func", undef_alloc_func, 1);
rb_define_method(cls, "speced_allocator?", speced_allocator_p, 1);
rb_define_method(cls, "custom_alloc_func?", custom_alloc_func_p, 1);
+ rb_define_method(cls, "not_implemented_method", rb_f_notimplement, 1);
}
#ifdef __cplusplus
diff --git a/spec/ruby/optional/capi/fixtures/module.rb b/spec/ruby/optional/capi/fixtures/module.rb
index ba90eb7181..aac8bfbfb3 100644
--- a/spec/ruby/optional/capi/fixtures/module.rb
+++ b/spec/ruby/optional/capi/fixtures/module.rb
@@ -13,6 +13,10 @@ class CApiModuleSpecs
autoload :D, File.expand_path('../const_get.rb', __FILE__)
X = 1
+ Q = 1
+ R = 2
+ S = 3
+ T = 5
end
class B < A
diff --git a/spec/ruby/optional/capi/module_spec.rb b/spec/ruby/optional/capi/module_spec.rb
index fde86d2223..9a0c707263 100644
--- a/spec/ruby/optional/capi/module_spec.rb
+++ b/spec/ruby/optional/capi/module_spec.rb
@@ -134,6 +134,10 @@ describe "CApiModule" do
@m.rb_const_get(CApiModuleSpecs::A, :X).should == 1
end
+ it "returns a constant defined in the module for multiple constants" do
+ [:Q, :R, :S, :T].each { |x| @m.rb_const_get(CApiModuleSpecs::A, x).should == CApiModuleSpecs::A.const_get(x) }
+ end
+
it "returns a constant defined at toplevel" do
@m.rb_const_get(CApiModuleSpecs::A, :Integer).should == Integer
end
diff --git a/spec/ruby/optional/capi/object_spec.rb b/spec/ruby/optional/capi/object_spec.rb
index be149898bd..83d8f023b3 100644
--- a/spec/ruby/optional/capi/object_spec.rb
+++ b/spec/ruby/optional/capi/object_spec.rb
@@ -115,6 +115,11 @@ describe "CApiObject" do
@o.rb_respond_to(true, :object_id).should == true
@o.rb_respond_to(14, :succ).should == true
end
+
+ it "returns 0 if the method has been defined as rb_f_notimplement" do
+ @o.respond_to?(:not_implemented_method).should == false
+ @o.rb_respond_to(@o, :not_implemented_method).should == false
+ end
end
describe "rb_obj_respond_to" do