summaryrefslogtreecommitdiff
path: root/spec
diff options
context:
space:
mode:
authorBenoit Daloze <eregontp@gmail.com>2024-02-05 16:29:57 +0100
committerBenoit Daloze <eregontp@gmail.com>2024-02-05 16:29:57 +0100
commit40642cd3bc581d3bb402ea5e8e61cdfb868b4f68 (patch)
tree077cc3ac94f880ce3c8c98322331c01cb1cc9cb8 /spec
parentabe07d4bf5f2f848b22e511a647a85c878066adb (diff)
Update to ruby/spec@3fc4444
Diffstat (limited to 'spec')
-rw-r--r--spec/ruby/.rubocop.yml6
-rw-r--r--spec/ruby/command_line/dash_r_spec.rb5
-rw-r--r--spec/ruby/command_line/syntax_error_spec.rb10
-rw-r--r--spec/ruby/core/class/attached_object_spec.rb8
-rw-r--r--spec/ruby/core/conditionvariable/broadcast_spec.rb1
-rw-r--r--spec/ruby/core/conditionvariable/marshal_dump_spec.rb1
-rw-r--r--spec/ruby/core/conditionvariable/signal_spec.rb1
-rw-r--r--spec/ruby/core/conditionvariable/wait_spec.rb1
-rw-r--r--spec/ruby/core/data/initialize_spec.rb7
-rw-r--r--spec/ruby/core/data/with_spec.rb35
-rw-r--r--spec/ruby/core/exception/frozen_error_spec.rb16
-rw-r--r--spec/ruby/core/hash/delete_spec.rb18
-rw-r--r--spec/ruby/core/hash/rehash_spec.rb30
-rw-r--r--spec/ruby/core/integer/coerce_spec.rb142
-rw-r--r--spec/ruby/core/integer/div_spec.rb8
-rw-r--r--spec/ruby/core/io/read_spec.rb2
-rw-r--r--spec/ruby/core/io/select_spec.rb33
-rw-r--r--spec/ruby/core/kernel/eval_spec.rb13
-rw-r--r--spec/ruby/core/matchdata/begin_spec.rb28
-rw-r--r--spec/ruby/core/matchdata/byteoffset_spec.rb4
-rw-r--r--spec/ruby/core/module/attr_accessor_spec.rb3
-rw-r--r--spec/ruby/core/module/attr_reader_spec.rb3
-rw-r--r--spec/ruby/core/module/attr_spec.rb3
-rw-r--r--spec/ruby/core/module/attr_writer_spec.rb3
-rw-r--r--spec/ruby/core/module/autoload_spec.rb1
-rw-r--r--spec/ruby/core/module/prepend_spec.rb11
-rw-r--r--spec/ruby/core/module/shared/attr_added.rb34
-rw-r--r--spec/ruby/core/proc/arity_spec.rb16
-rw-r--r--spec/ruby/core/proc/parameters_spec.rb5
-rw-r--r--spec/ruby/core/proc/shared/to_s.rb14
-rw-r--r--spec/ruby/core/process/fixtures/kill.rb2
-rw-r--r--spec/ruby/core/process/status/termsig_spec.rb2
-rw-r--r--spec/ruby/core/range/bsearch_spec.rb44
-rw-r--r--spec/ruby/core/rational/coerce_spec.rb8
-rw-r--r--spec/ruby/core/regexp/shared/new.rb40
-rw-r--r--spec/ruby/core/signal/trap_spec.rb8
-rw-r--r--spec/ruby/core/string/fixtures/utf-8-encoding.rb7
-rw-r--r--spec/ruby/core/string/rindex_spec.rb1
-rw-r--r--spec/ruby/core/thread/backtrace/location/lineno_spec.rb2
-rw-r--r--spec/ruby/core/thread/fetch_spec.rb30
-rw-r--r--spec/ruby/core/thread/thread_variable_get_spec.rb2
-rw-r--r--spec/ruby/core/time/deconstruct_keys_spec.rb5
-rw-r--r--spec/ruby/language/assignments_spec.rb150
-rw-r--r--spec/ruby/language/block_spec.rb81
-rw-r--r--spec/ruby/language/case_spec.rb16
-rw-r--r--spec/ruby/language/defined_spec.rb121
-rw-r--r--spec/ruby/language/delegation_spec.rb36
-rw-r--r--spec/ruby/language/fixtures/rescue/top_level.rb7
-rw-r--r--spec/ruby/language/fixtures/super.rb48
-rw-r--r--spec/ruby/language/method_spec.rb1
-rw-r--r--spec/ruby/language/optional_assignments_spec.rb294
-rw-r--r--spec/ruby/language/pattern_matching_spec.rb222
-rw-r--r--spec/ruby/language/rescue_spec.rb72
-rw-r--r--spec/ruby/language/safe_navigator_spec.rb80
-rw-r--r--spec/ruby/language/super_spec.rb7
-rw-r--r--spec/ruby/language/variables_spec.rb9
-rw-r--r--spec/ruby/library/coverage/result_spec.rb266
-rw-r--r--spec/ruby/library/coverage/start_spec.rb81
-rw-r--r--spec/ruby/library/objectspace/reachable_objects_from_spec.rb2
-rw-r--r--spec/ruby/library/socket/shared/pack_sockaddr.rb3
-rw-r--r--spec/ruby/library/socket/socket/pack_sockaddr_in_spec.rb2
-rw-r--r--spec/ruby/library/socket/socket/pair_spec.rb2
-rw-r--r--spec/ruby/library/socket/socket/socketpair_spec.rb2
-rw-r--r--spec/ruby/library/socket/tcpserver/accept_spec.rb13
-rw-r--r--spec/ruby/library/socket/tcpsocket/initialize_spec.rb13
-rw-r--r--spec/ruby/library/socket/udpsocket/initialize_spec.rb13
-rw-r--r--spec/ruby/library/socket/unixserver/accept_spec.rb11
-rw-r--r--spec/ruby/library/socket/unixserver/for_fd_spec.rb2
-rw-r--r--spec/ruby/library/socket/unixsocket/initialize_spec.rb10
-rw-r--r--spec/ruby/library/socket/unixsocket/pair_spec.rb2
-rw-r--r--spec/ruby/library/yaml/fixtures/strings.rb56
-rw-r--r--spec/ruby/library/yaml/shared/each_document.rb2
-rw-r--r--spec/ruby/library/yaml/shared/load.rb2
-rw-r--r--spec/ruby/optional/capi/debug_spec.rb9
-rw-r--r--spec/ruby/optional/capi/ext/io_spec.c14
-rw-r--r--spec/ruby/optional/capi/ext/kernel_spec.c10
-rw-r--r--spec/ruby/optional/capi/ext/thread_spec.c4
-rw-r--r--spec/ruby/optional/capi/fixtures/kernel.rb6
-rw-r--r--spec/ruby/optional/capi/integer_spec.rb17
-rw-r--r--spec/ruby/optional/capi/io_spec.rb19
-rw-r--r--spec/ruby/optional/capi/kernel_spec.rb43
-rw-r--r--spec/ruby/shared/kernel/at_exit.rb5
-rw-r--r--spec/ruby/shared/queue/deque.rb34
-rw-r--r--spec/ruby/shared/rational/coerce.rb46
-rw-r--r--spec/ruby/shared/sizedqueue/enque.rb34
85 files changed, 2082 insertions, 398 deletions
diff --git a/spec/ruby/.rubocop.yml b/spec/ruby/.rubocop.yml
index 9ad57dd51c..be32ce8900 100644
--- a/spec/ruby/.rubocop.yml
+++ b/spec/ruby/.rubocop.yml
@@ -43,9 +43,6 @@ Lint/InterpolationCheck:
Lint/LiteralAsCondition:
Enabled: false
-Lint/RedundantRequireStatement:
- Enabled: false
-
Lint/RedundantSplatExpansion:
Enabled: false
@@ -106,6 +103,9 @@ Lint/OutOfRangeRegexpRef:
Lint/InheritException:
Enabled: false
+Lint/SafeNavigationChain:
+ Enabled: false
+
Lint/ElseLayout:
Exclude:
- 'language/if_spec.rb'
diff --git a/spec/ruby/command_line/dash_r_spec.rb b/spec/ruby/command_line/dash_r_spec.rb
index ea5bde5adf..9f673c53dc 100644
--- a/spec/ruby/command_line/dash_r_spec.rb
+++ b/spec/ruby/command_line/dash_r_spec.rb
@@ -16,7 +16,10 @@ describe "The -r command line option" do
out = ruby_exe(fixture(__FILE__, "bad_syntax.rb"), options: "-r #{@test_file}", args: "2>&1", exit_status: 1)
$?.should_not.success?
out.should include("REQUIRED")
- out.should include("syntax error")
+
+ # it's tempting not to rely on error message and rely only on exception class name,
+ # but CRuby before 3.2 doesn't print class name for syntax error
+ out.should include_any_of("syntax error", "SyntaxError")
end
it "does not require the file if the main script file does not exist" do
diff --git a/spec/ruby/command_line/syntax_error_spec.rb b/spec/ruby/command_line/syntax_error_spec.rb
index 444ea9635c..9ba87b9e22 100644
--- a/spec/ruby/command_line/syntax_error_spec.rb
+++ b/spec/ruby/command_line/syntax_error_spec.rb
@@ -3,11 +3,17 @@ require_relative '../spec_helper'
describe "The interpreter" do
it "prints an error when given a file with invalid syntax" do
out = ruby_exe(fixture(__FILE__, "bad_syntax.rb"), args: "2>&1", exit_status: 1)
- out.should include "syntax error"
+
+ # it's tempting not to rely on error message and rely only on exception class name,
+ # but CRuby before 3.2 doesn't print class name for syntax error
+ out.should include_any_of("syntax error", "SyntaxError")
end
it "prints an error when given code via -e with invalid syntax" do
out = ruby_exe(nil, args: "-e 'a{' 2>&1", exit_status: 1)
- out.should include "syntax error"
+
+ # it's tempting not to rely on error message and rely only on exception class name,
+ # but CRuby before 3.2 doesn't print class name for syntax error
+ out.should include_any_of("syntax error", "SyntaxError")
end
end
diff --git a/spec/ruby/core/class/attached_object_spec.rb b/spec/ruby/core/class/attached_object_spec.rb
index 115d5fa563..d97f9cc93e 100644
--- a/spec/ruby/core/class/attached_object_spec.rb
+++ b/spec/ruby/core/class/attached_object_spec.rb
@@ -19,13 +19,13 @@ ruby_version_is '3.2' do
it "raises TypeError if the class is not a singleton class" do
a = Class.new
- -> { a.attached_object }.should raise_error(TypeError)
+ -> { a.attached_object }.should raise_error(TypeError, /is not a singleton class/)
end
it "raises TypeError for special singleton classes" do
- -> { nil.singleton_class.attached_object }.should raise_error(TypeError)
- -> { true.singleton_class.attached_object }.should raise_error(TypeError)
- -> { false.singleton_class.attached_object }.should raise_error(TypeError)
+ -> { nil.singleton_class.attached_object }.should raise_error(TypeError, /`NilClass' is not a singleton class/)
+ -> { true.singleton_class.attached_object }.should raise_error(TypeError, /`TrueClass' is not a singleton class/)
+ -> { false.singleton_class.attached_object }.should raise_error(TypeError, /`FalseClass' is not a singleton class/)
end
end
end
diff --git a/spec/ruby/core/conditionvariable/broadcast_spec.rb b/spec/ruby/core/conditionvariable/broadcast_spec.rb
index d88159df23..55a7b89c72 100644
--- a/spec/ruby/core/conditionvariable/broadcast_spec.rb
+++ b/spec/ruby/core/conditionvariable/broadcast_spec.rb
@@ -1,5 +1,4 @@
require_relative '../../spec_helper'
-require 'thread'
describe "ConditionVariable#broadcast" do
it "releases all threads waiting in line for this resource" do
diff --git a/spec/ruby/core/conditionvariable/marshal_dump_spec.rb b/spec/ruby/core/conditionvariable/marshal_dump_spec.rb
index f951a13e28..88b1cc38c1 100644
--- a/spec/ruby/core/conditionvariable/marshal_dump_spec.rb
+++ b/spec/ruby/core/conditionvariable/marshal_dump_spec.rb
@@ -1,5 +1,4 @@
require_relative '../../spec_helper'
-require 'thread'
describe "ConditionVariable#marshal_dump" do
it "raises a TypeError" do
diff --git a/spec/ruby/core/conditionvariable/signal_spec.rb b/spec/ruby/core/conditionvariable/signal_spec.rb
index 86383073f1..43a9cc611b 100644
--- a/spec/ruby/core/conditionvariable/signal_spec.rb
+++ b/spec/ruby/core/conditionvariable/signal_spec.rb
@@ -1,5 +1,4 @@
require_relative '../../spec_helper'
-require 'thread'
describe "ConditionVariable#signal" do
it "releases the first thread waiting in line for this resource" do
diff --git a/spec/ruby/core/conditionvariable/wait_spec.rb b/spec/ruby/core/conditionvariable/wait_spec.rb
index 9a68c2b5a1..fe73e513c0 100644
--- a/spec/ruby/core/conditionvariable/wait_spec.rb
+++ b/spec/ruby/core/conditionvariable/wait_spec.rb
@@ -1,5 +1,4 @@
require_relative '../../spec_helper'
-require 'thread'
describe "ConditionVariable#wait" do
it "calls #sleep on the given object" do
diff --git a/spec/ruby/core/data/initialize_spec.rb b/spec/ruby/core/data/initialize_spec.rb
index 94470cd108..2c36bd3ac4 100644
--- a/spec/ruby/core/data/initialize_spec.rb
+++ b/spec/ruby/core/data/initialize_spec.rb
@@ -31,6 +31,13 @@ ruby_version_is "3.2" do
data.unit.should == "km"
end
+ it "accepts String keyword arguments" do
+ data = DataSpecs::Measure.new("amount" => 42, "unit" => "km")
+
+ data.amount.should == 42
+ data.unit.should == "km"
+ end
+
it "raises ArgumentError if no arguments are given" do
-> {
DataSpecs::Measure.new
diff --git a/spec/ruby/core/data/with_spec.rb b/spec/ruby/core/data/with_spec.rb
new file mode 100644
index 0000000000..97e34c951f
--- /dev/null
+++ b/spec/ruby/core/data/with_spec.rb
@@ -0,0 +1,35 @@
+require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
+
+ruby_version_is "3.2" do
+ describe "Data#with" do
+ it "returns self if given no arguments" do
+ data = DataSpecs::Measure.new(amount: 42, unit: "km")
+ data = data.with.should.equal?(data)
+ end
+
+ it "accepts keyword arguments" do
+ data = DataSpecs::Measure.new(amount: 42, unit: "km")
+ data = data.with(amount: 4, unit: "m")
+
+ data.amount.should == 4
+ data.unit.should == "m"
+ end
+
+ it "accepts String keyword arguments" do
+ data = DataSpecs::Measure.new(amount: 42, unit: "km")
+ data = data.with("amount" => 4, "unit" => "m")
+
+ data.amount.should == 4
+ data.unit.should == "m"
+ end
+
+ it "raises ArgumentError if no keyword arguments are given" do
+ data = DataSpecs::Measure.new(amount: 42, unit: "km")
+
+ -> {
+ data.with(4, "m")
+ }.should raise_error(ArgumentError, "wrong number of arguments (given 2, expected 0)")
+ end
+ end
+end
diff --git a/spec/ruby/core/exception/frozen_error_spec.rb b/spec/ruby/core/exception/frozen_error_spec.rb
index 2efdc239d8..979ec2ff98 100644
--- a/spec/ruby/core/exception/frozen_error_spec.rb
+++ b/spec/ruby/core/exception/frozen_error_spec.rb
@@ -20,3 +20,19 @@ describe "FrozenError#receiver" do
end
end
end
+
+describe "Modifying a frozen object" do
+ context "#inspect is redefined and modifies the object" do
+ it "returns ... instead of String representation of object" do
+ object = Object.new
+ def object.inspect; @a = 1 end
+ def object.modify; @a = 2 end
+
+ object.freeze
+
+ # CRuby's message contains multiple whitespaces before '...'.
+ # So handle both multiple and single whitespace.
+ -> { object.modify }.should raise_error(FrozenError, /can't modify frozen .*?: \s*.../)
+ end
+ end
+end
diff --git a/spec/ruby/core/hash/delete_spec.rb b/spec/ruby/core/hash/delete_spec.rb
index b262e8846b..3e3479c69c 100644
--- a/spec/ruby/core/hash/delete_spec.rb
+++ b/spec/ruby/core/hash/delete_spec.rb
@@ -24,7 +24,7 @@ describe "Hash#delete" do
it "allows removing a key while iterating" do
h = { a: 1, b: 2 }
visited = []
- h.each_pair { |k,v|
+ h.each_pair { |k, v|
visited << k
h.delete(k)
}
@@ -32,13 +32,27 @@ describe "Hash#delete" do
h.should == {}
end
+ it "allows removing a key while iterating for big hashes" do
+ h = { a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8, i: 9, j: 10,
+ k: 11, l: 12, m: 13, n: 14, o: 15, p: 16, q: 17, r: 18, s: 19, t: 20,
+ u: 21, v: 22, w: 23, x: 24, y: 25, z: 26 }
+ visited = []
+ h.each_pair { |k, v|
+ visited << k
+ h.delete(k)
+ }
+ visited.should == [:a, :b, :c, :d, :e, :f, :g, :h, :i, :j, :k, :l, :m,
+ :n, :o, :p, :q, :r, :s, :t, :u, :v, :w, :x, :y, :z]
+ h.should == {}
+ end
+
it "accepts keys with private #hash method" do
key = HashSpecs::KeyWithPrivateHash.new
{ key => 5 }.delete(key).should == 5
end
it "raises a FrozenError if called on a frozen instance" do
- -> { HashSpecs.frozen_hash.delete("foo") }.should raise_error(FrozenError)
+ -> { HashSpecs.frozen_hash.delete("foo") }.should raise_error(FrozenError)
-> { HashSpecs.empty_frozen_hash.delete("foo") }.should raise_error(FrozenError)
end
end
diff --git a/spec/ruby/core/hash/rehash_spec.rb b/spec/ruby/core/hash/rehash_spec.rb
index 0049080456..db3e91b166 100644
--- a/spec/ruby/core/hash/rehash_spec.rb
+++ b/spec/ruby/core/hash/rehash_spec.rb
@@ -77,6 +77,36 @@ describe "Hash#rehash" do
h.keys.should_not.include? [1]
end
+ it "iterates keys in insertion order" do
+ key = Class.new do
+ attr_reader :name
+
+ def initialize(name)
+ @name = name
+ end
+
+ def hash
+ 123
+ end
+ end
+
+ a, b, c, d = key.new('a'), key.new('b'), key.new('c'), key.new('d')
+ h = { a => 1, b => 2, c => 3, d => 4 }
+ h.size.should == 4
+
+ key.class_exec do
+ def eql?(other)
+ true
+ end
+ end
+
+ h.rehash
+ h.size.should == 1
+ k, v = h.first
+ k.name.should == 'a'
+ v.should == 4
+ end
+
it "raises a FrozenError if called on a frozen instance" do
-> { HashSpecs.frozen_hash.rehash }.should raise_error(FrozenError)
-> { HashSpecs.empty_frozen_hash.rehash }.should raise_error(FrozenError)
diff --git a/spec/ruby/core/integer/coerce_spec.rb b/spec/ruby/core/integer/coerce_spec.rb
index c967b0dea3..13fe7b3321 100644
--- a/spec/ruby/core/integer/coerce_spec.rb
+++ b/spec/ruby/core/integer/coerce_spec.rb
@@ -1,98 +1,96 @@
require_relative '../../spec_helper'
-ruby_version_is ""..."3.4" do
-
- require 'bigdecimal'
-
- describe "Integer#coerce" do
- context "fixnum" do
- describe "when given a Fixnum" do
- it "returns an array containing two Fixnums" do
- 1.coerce(2).should == [2, 1]
- 1.coerce(2).map { |i| i.class }.should == [Integer, Integer]
- end
+describe "Integer#coerce" do
+ context "fixnum" do
+ describe "when given a Fixnum" do
+ it "returns an array containing two Fixnums" do
+ 1.coerce(2).should == [2, 1]
+ 1.coerce(2).map { |i| i.class }.should == [Integer, Integer]
end
+ end
- describe "when given a String" do
- it "raises an ArgumentError when trying to coerce with a non-number String" do
- -> { 1.coerce(":)") }.should raise_error(ArgumentError)
- end
-
- it "returns an array containing two Floats" do
- 1.coerce("2").should == [2.0, 1.0]
- 1.coerce("-2").should == [-2.0, 1.0]
- end
+ describe "when given a String" do
+ it "raises an ArgumentError when trying to coerce with a non-number String" do
+ -> { 1.coerce(":)") }.should raise_error(ArgumentError)
end
- it "raises a TypeError when trying to coerce with nil" do
- -> { 1.coerce(nil) }.should raise_error(TypeError)
+ it "returns an array containing two Floats" do
+ 1.coerce("2").should == [2.0, 1.0]
+ 1.coerce("-2").should == [-2.0, 1.0]
end
+ end
- it "tries to convert the given Object into a Float by using #to_f" do
- (obj = mock('1.0')).should_receive(:to_f).and_return(1.0)
- 2.coerce(obj).should == [1.0, 2.0]
+ it "raises a TypeError when trying to coerce with nil" do
+ -> { 1.coerce(nil) }.should raise_error(TypeError)
+ end
- (obj = mock('0')).should_receive(:to_f).and_return('0')
- -> { 2.coerce(obj).should == [1.0, 2.0] }.should raise_error(TypeError)
- end
+ it "tries to convert the given Object into a Float by using #to_f" do
+ (obj = mock('1.0')).should_receive(:to_f).and_return(1.0)
+ 2.coerce(obj).should == [1.0, 2.0]
- it "raises a TypeError when given an Object that does not respond to #to_f" do
- -> { 1.coerce(mock('x')) }.should raise_error(TypeError)
- -> { 1.coerce(1..4) }.should raise_error(TypeError)
- -> { 1.coerce(:test) }.should raise_error(TypeError)
- end
+ (obj = mock('0')).should_receive(:to_f).and_return('0')
+ -> { 2.coerce(obj).should == [1.0, 2.0] }.should raise_error(TypeError)
end
- context "bignum" do
- it "coerces other to a Bignum and returns [other, self] when passed a Fixnum" do
- a = bignum_value
- ary = a.coerce(2)
+ it "raises a TypeError when given an Object that does not respond to #to_f" do
+ -> { 1.coerce(mock('x')) }.should raise_error(TypeError)
+ -> { 1.coerce(1..4) }.should raise_error(TypeError)
+ -> { 1.coerce(:test) }.should raise_error(TypeError)
+ end
+ end
- ary[0].should be_kind_of(Integer)
- ary[1].should be_kind_of(Integer)
- ary.should == [2, a]
- end
+ context "bignum" do
+ it "coerces other to a Bignum and returns [other, self] when passed a Fixnum" do
+ a = bignum_value
+ ary = a.coerce(2)
- it "returns [other, self] when passed a Bignum" do
- a = bignum_value
- b = bignum_value
- ary = a.coerce(b)
+ ary[0].should be_kind_of(Integer)
+ ary[1].should be_kind_of(Integer)
+ ary.should == [2, a]
+ end
- ary[0].should be_kind_of(Integer)
- ary[1].should be_kind_of(Integer)
- ary.should == [b, a]
- end
+ it "returns [other, self] when passed a Bignum" do
+ a = bignum_value
+ b = bignum_value
+ ary = a.coerce(b)
- it "raises a TypeError when not passed a Fixnum or Bignum" do
- a = bignum_value
+ ary[0].should be_kind_of(Integer)
+ ary[1].should be_kind_of(Integer)
+ ary.should == [b, a]
+ end
- -> { a.coerce(nil) }.should raise_error(TypeError)
- -> { a.coerce(mock('str')) }.should raise_error(TypeError)
- -> { a.coerce(1..4) }.should raise_error(TypeError)
- -> { a.coerce(:test) }.should raise_error(TypeError)
- end
+ it "raises a TypeError when not passed a Fixnum or Bignum" do
+ a = bignum_value
- it "coerces both values to Floats and returns [other, self] when passed a Float" do
- a = bignum_value
- a.coerce(1.2).should == [1.2, a.to_f]
- end
+ -> { a.coerce(nil) }.should raise_error(TypeError)
+ -> { a.coerce(mock('str')) }.should raise_error(TypeError)
+ -> { a.coerce(1..4) }.should raise_error(TypeError)
+ -> { a.coerce(:test) }.should raise_error(TypeError)
+ end
- it "coerces both values to Floats and returns [other, self] when passed a String" do
- a = bignum_value
- a.coerce("123").should == [123.0, a.to_f]
- end
+ it "coerces both values to Floats and returns [other, self] when passed a Float" do
+ a = bignum_value
+ a.coerce(1.2).should == [1.2, a.to_f]
+ end
- it "calls #to_f to coerce other to a Float" do
- b = mock("bignum value")
- b.should_receive(:to_f).and_return(1.2)
+ it "coerces both values to Floats and returns [other, self] when passed a String" do
+ a = bignum_value
+ a.coerce("123").should == [123.0, a.to_f]
+ end
- a = bignum_value
- ary = a.coerce(b)
+ it "calls #to_f to coerce other to a Float" do
+ b = mock("bignum value")
+ b.should_receive(:to_f).and_return(1.2)
- ary.should == [1.2, a.to_f]
- end
+ a = bignum_value
+ ary = a.coerce(b)
+
+ ary.should == [1.2, a.to_f]
end
+ end
+ ruby_version_is ""..."3.4" do
+ require 'bigdecimal'
context "bigdecimal" do
it "produces Floats" do
x, y = 3.coerce(BigDecimal("3.4"))
@@ -102,6 +100,6 @@ ruby_version_is ""..."3.4" do
y.should == 3.0
end
end
-
end
+
end
diff --git a/spec/ruby/core/integer/div_spec.rb b/spec/ruby/core/integer/div_spec.rb
index 344e095179..2eb9c0623b 100644
--- a/spec/ruby/core/integer/div_spec.rb
+++ b/spec/ruby/core/integer/div_spec.rb
@@ -143,4 +143,12 @@ describe "Integer#div" do
-> { @bignum.div(-0) }.should raise_error(ZeroDivisionError)
end
end
+
+ context "rational" do
+ it "returns self divided by the given argument as an Integer" do
+ 2.div(6/5r).should == 1
+ 1.div(6/5r).should == 0
+ 5.div(6/5r).should == 4
+ end
+ end
end
diff --git a/spec/ruby/core/io/read_spec.rb b/spec/ruby/core/io/read_spec.rb
index db11468ea4..b37c6c7121 100644
--- a/spec/ruby/core/io/read_spec.rb
+++ b/spec/ruby/core/io/read_spec.rb
@@ -331,7 +331,7 @@ describe "IO#read" do
@io.read(0).should == ''
@io.pos.should == 0
- @io.getc.chr.should == '1'
+ @io.getc.should == '1'
end
it "is at end-of-file when everything has been read" do
diff --git a/spec/ruby/core/io/select_spec.rb b/spec/ruby/core/io/select_spec.rb
index 1e4e50a81b..3893e7620f 100644
--- a/spec/ruby/core/io/select_spec.rb
+++ b/spec/ruby/core/io/select_spec.rb
@@ -114,6 +114,39 @@ describe "IO.select" do
it "raises an ArgumentError when passed a negative timeout" do
-> { IO.select(nil, nil, nil, -5)}.should raise_error(ArgumentError)
end
+
+ describe "returns the available descriptors when the file descriptor" do
+ it "is in both read and error arrays" do
+ @wr.write("foobar")
+ result = IO.select([@rd], nil, [@rd])
+ result.should == [[@rd], [], []]
+ end
+
+ it "is in both write and error arrays" do
+ result = IO.select(nil, [@wr], [@wr])
+ result.should == [[], [@wr], []]
+ end
+
+ it "is in both read and write arrays" do
+ filename = tmp("IO_select_read_write_file")
+ w = File.open(filename, 'w+')
+ begin
+ IO.select([w], [w], []).should == [[w], [w], []]
+ ensure
+ w.close
+ rm_r filename
+ end
+
+ IO.select([@wr], [@wr], []).should == [[], [@wr], []]
+
+ @wr.write("foobar")
+ # CRuby on macOS returns [[@rd], [@rd], []], weird but we accept it here, probably only for pipe read-end
+ [
+ [[@rd], [], []],
+ [[@rd], [@rd], []]
+ ].should.include? IO.select([@rd], [@rd], [])
+ end
+ end
end
describe "IO.select when passed nil for timeout" do
diff --git a/spec/ruby/core/kernel/eval_spec.rb b/spec/ruby/core/kernel/eval_spec.rb
index 3dfc863368..f3b025fb7b 100644
--- a/spec/ruby/core/kernel/eval_spec.rb
+++ b/spec/ruby/core/kernel/eval_spec.rb
@@ -261,6 +261,19 @@ describe "Kernel#eval" do
end
end
+ it "makes flip-flop operator work correctly" do
+ ScratchPad.record []
+
+ eval "10.times { |i| ScratchPad << i if (i == 4)...(i == 4) }"
+ ScratchPad.recorded.should == [4, 5, 6, 7, 8, 9]
+
+ ScratchPad.clear
+ end
+
+ it "returns nil if given an empty string" do
+ eval("").should == nil
+ end
+
# See language/magic_comment_spec.rb for more magic comments specs
describe "with a magic encoding comment" do
it "uses the magic comment encoding for the encoding of literal strings" do
diff --git a/spec/ruby/core/matchdata/begin_spec.rb b/spec/ruby/core/matchdata/begin_spec.rb
index 85c454da56..54b4e0a33f 100644
--- a/spec/ruby/core/matchdata/begin_spec.rb
+++ b/spec/ruby/core/matchdata/begin_spec.rb
@@ -36,6 +36,18 @@ describe "MatchData#begin" do
match_data = /(.)(.)(\d+)(\d)/.match("THX1138.")
match_data.begin(obj).should == 2
end
+
+ it "raises IndexError if index is out of bounds" do
+ match_data = /(?<f>foo)(?<b>bar)/.match("foobar")
+
+ -> {
+ match_data.begin(-1)
+ }.should raise_error(IndexError, "index -1 out of matches")
+
+ -> {
+ match_data.begin(3)
+ }.should raise_error(IndexError, "index 3 out of matches")
+ end
end
context "when passed a String argument" do
@@ -68,6 +80,14 @@ describe "MatchData#begin" do
match_data = /(?<æ>.)(.)(?<b>\d+)(\d)/.match("THX1138.")
match_data.begin("æ").should == 1
end
+
+ it "raises IndexError if there is no group with the provided name" do
+ match_data = /(?<f>foo)(?<b>bar)/.match("foobar")
+
+ -> {
+ match_data.begin("y")
+ }.should raise_error(IndexError, "undefined group name reference: y")
+ end
end
context "when passed a Symbol argument" do
@@ -100,5 +120,13 @@ describe "MatchData#begin" do
match_data = /(?<æ>.)(.)(?<b>\d+)(\d)/.match("THX1138.")
match_data.begin(:æ).should == 1
end
+
+ it "raises IndexError if there is no group with the provided name" do
+ match_data = /(?<f>foo)(?<b>bar)/.match("foobar")
+
+ -> {
+ match_data.begin(:y)
+ }.should raise_error(IndexError, "undefined group name reference: y")
+ end
end
end
diff --git a/spec/ruby/core/matchdata/byteoffset_spec.rb b/spec/ruby/core/matchdata/byteoffset_spec.rb
index 6036097834..b27267fd0e 100644
--- a/spec/ruby/core/matchdata/byteoffset_spec.rb
+++ b/spec/ruby/core/matchdata/byteoffset_spec.rb
@@ -60,7 +60,7 @@ describe "MatchData#byteoffset" do
m.byteoffset(obj).should == [3, 6]
end
- it "raises IndexError if there is no group with provided name" do
+ it "raises IndexError if there is no group with the provided name" do
m = /(?<f>foo)(?<b>bar)/.match("foobar")
-> {
@@ -72,7 +72,7 @@ describe "MatchData#byteoffset" do
}.should raise_error(IndexError, "undefined group name reference: y")
end
- it "raises IndexError if index is out of matches" do
+ it "raises IndexError if index is out of bounds" do
m = /(?<f>foo)(?<b>bar)/.match("foobar")
-> {
diff --git a/spec/ruby/core/module/attr_accessor_spec.rb b/spec/ruby/core/module/attr_accessor_spec.rb
index eea5b4b64b..503dccc61e 100644
--- a/spec/ruby/core/module/attr_accessor_spec.rb
+++ b/spec/ruby/core/module/attr_accessor_spec.rb
@@ -1,5 +1,6 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
+require_relative 'shared/attr_added'
describe "Module#attr_accessor" do
it "creates a getter and setter for each given attribute name" do
@@ -106,4 +107,6 @@ describe "Module#attr_accessor" do
1.foobar.should be_nil
end
end
+
+ it_behaves_like :module_attr_added, :attr_accessor
end
diff --git a/spec/ruby/core/module/attr_reader_spec.rb b/spec/ruby/core/module/attr_reader_spec.rb
index 0b6d996719..37fd537ff5 100644
--- a/spec/ruby/core/module/attr_reader_spec.rb
+++ b/spec/ruby/core/module/attr_reader_spec.rb
@@ -1,5 +1,6 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
+require_relative 'shared/attr_added'
describe "Module#attr_reader" do
it "creates a getter for each given attribute name" do
@@ -67,4 +68,6 @@ describe "Module#attr_reader" do
(attr_reader :foo, 'bar').should == [:foo, :bar]
end
end
+
+ it_behaves_like :module_attr_added, :attr_reader
end
diff --git a/spec/ruby/core/module/attr_spec.rb b/spec/ruby/core/module/attr_spec.rb
index 72a6646b1e..2f9f4e26dc 100644
--- a/spec/ruby/core/module/attr_spec.rb
+++ b/spec/ruby/core/module/attr_spec.rb
@@ -1,5 +1,6 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
+require_relative 'shared/attr_added'
describe "Module#attr" do
before :each do
@@ -153,4 +154,6 @@ describe "Module#attr" do
(attr :qux, true).should == [:qux, :qux=]
end
end
+
+ it_behaves_like :module_attr_added, :attr
end
diff --git a/spec/ruby/core/module/attr_writer_spec.rb b/spec/ruby/core/module/attr_writer_spec.rb
index aaea0ce43f..5b863ef88c 100644
--- a/spec/ruby/core/module/attr_writer_spec.rb
+++ b/spec/ruby/core/module/attr_writer_spec.rb
@@ -1,5 +1,6 @@
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
+require_relative 'shared/attr_added'
describe "Module#attr_writer" do
it "creates a setter for each given attribute name" do
@@ -77,4 +78,6 @@ describe "Module#attr_writer" do
(attr_writer :foo, 'bar').should == [:foo=, :bar=]
end
end
+
+ it_behaves_like :module_attr_added, :attr_writer
end
diff --git a/spec/ruby/core/module/autoload_spec.rb b/spec/ruby/core/module/autoload_spec.rb
index ab4df7600e..271c55ebf0 100644
--- a/spec/ruby/core/module/autoload_spec.rb
+++ b/spec/ruby/core/module/autoload_spec.rb
@@ -1,7 +1,6 @@
require_relative '../../spec_helper'
require_relative '../../fixtures/code_loading'
require_relative 'fixtures/classes'
-require 'thread'
describe "Module#autoload?" do
it "returns the name of the file that will be autoloaded" do
diff --git a/spec/ruby/core/module/prepend_spec.rb b/spec/ruby/core/module/prepend_spec.rb
index 96598e7209..f80cfbcca1 100644
--- a/spec/ruby/core/module/prepend_spec.rb
+++ b/spec/ruby/core/module/prepend_spec.rb
@@ -726,6 +726,17 @@ describe "Module#prepend" do
ary.should == [3, 2, 1]
end
+ it "does not prepend a second copy if the module already indirectly exists in the hierarchy" do
+ mod = Module.new do; end
+ submod = Module.new do; end
+ klass = Class.new do; end
+ klass.include(mod)
+ mod.prepend(submod)
+ klass.include(mod)
+
+ klass.ancestors.take(4).should == [klass, submod, mod, Object]
+ end
+
describe "called on a module" do
describe "included into a class"
it "does not obscure the module's methods from reflective access" do
diff --git a/spec/ruby/core/module/shared/attr_added.rb b/spec/ruby/core/module/shared/attr_added.rb
new file mode 100644
index 0000000000..ce832cdcff
--- /dev/null
+++ b/spec/ruby/core/module/shared/attr_added.rb
@@ -0,0 +1,34 @@
+describe :module_attr_added, shared: true do
+ it "calls method_added for normal classes" do
+ ScratchPad.record []
+
+ cls = Class.new do
+ class << self
+ def method_added(name)
+ ScratchPad.recorded << name
+ end
+ end
+ end
+
+ cls.send(@method, :foo)
+
+ ScratchPad.recorded.each {|name| name.to_s.should =~ /foo[=]?/}
+ end
+
+ it "calls singleton_method_added for singleton classes" do
+ ScratchPad.record []
+ cls = Class.new do
+ class << self
+ def singleton_method_added(name)
+ # called for this def so ignore it
+ return if name == :singleton_method_added
+ ScratchPad.recorded << name
+ end
+ end
+ end
+
+ cls.singleton_class.send(@method, :foo)
+
+ ScratchPad.recorded.each {|name| name.to_s.should =~ /foo[=]?/}
+ end
+end
diff --git a/spec/ruby/core/proc/arity_spec.rb b/spec/ruby/core/proc/arity_spec.rb
index f7cb5ad0f8..5c7728cb30 100644
--- a/spec/ruby/core/proc/arity_spec.rb
+++ b/spec/ruby/core/proc/arity_spec.rb
@@ -268,6 +268,14 @@ describe "Proc#arity" do
@a.arity.should == 3
@b.arity.should == 3
end
+
+ # implicit rest
+ evaluate <<-ruby do
+ @a = lambda { |a, | }
+ ruby
+
+ @a.arity.should == 1
+ end
end
context "returns negative values" do
@@ -530,6 +538,14 @@ describe "Proc#arity" do
@a.arity.should == 1
@b.arity.should == 5
end
+
+ # implicit rest
+ evaluate <<-ruby do
+ @a = proc { |a, | }
+ ruby
+
+ @a.arity.should == 1
+ end
end
context "returns negative values" do
diff --git a/spec/ruby/core/proc/parameters_spec.rb b/spec/ruby/core/proc/parameters_spec.rb
index 2a4dcc36b3..6c21784ab6 100644
--- a/spec/ruby/core/proc/parameters_spec.rb
+++ b/spec/ruby/core/proc/parameters_spec.rb
@@ -95,6 +95,11 @@ describe "Proc#parameters" do
-> x {}.parameters.should == [[:req, :x]]
end
+ it "ignores implicit rest arguments" do
+ proc { |x, | }.parameters.should == [[:opt, :x]]
+ -> x { }.parameters.should == [[:req, :x]]
+ end
+
ruby_version_is '3.2' do
it "adds rest arg with name * for \"star\" argument" do
-> * {}.parameters.should == [[:rest, :*]]
diff --git a/spec/ruby/core/proc/shared/to_s.rb b/spec/ruby/core/proc/shared/to_s.rb
index f1e2f416fc..a52688a89f 100644
--- a/spec/ruby/core/proc/shared/to_s.rb
+++ b/spec/ruby/core/proc/shared/to_s.rb
@@ -31,13 +31,13 @@ describe :proc_to_s, shared: true do
describe "for a proc created with UnboundMethod#to_proc" do
it "returns a description including '(lambda)' and optionally including file and line number" do
- def hello; end
- s = method("hello").to_proc.send(@method)
- if s.include? __FILE__
- s.should =~ /^#<Proc:([^ ]*?) #{Regexp.escape __FILE__}:#{__LINE__ - 3} \(lambda\)>$/
- else
- s.should =~ /^#<Proc:([^ ]*?) \(lambda\)>$/
- end
+ def hello; end
+ s = method("hello").to_proc.send(@method)
+ if s.include? __FILE__
+ s.should =~ /^#<Proc:([^ ]*?) #{Regexp.escape __FILE__}:#{__LINE__ - 3} \(lambda\)>$/
+ else
+ s.should =~ /^#<Proc:([^ ]*?) \(lambda\)>$/
+ end
end
it "has a binary encoding" do
diff --git a/spec/ruby/core/process/fixtures/kill.rb b/spec/ruby/core/process/fixtures/kill.rb
index 0b88f8ee1f..b922a043f1 100644
--- a/spec/ruby/core/process/fixtures/kill.rb
+++ b/spec/ruby/core/process/fixtures/kill.rb
@@ -1,5 +1,3 @@
-require 'thread'
-
pid_file = ARGV.shift
scenario = ARGV.shift
diff --git a/spec/ruby/core/process/status/termsig_spec.rb b/spec/ruby/core/process/status/termsig_spec.rb
index 5d286950f8..9a22dbea71 100644
--- a/spec/ruby/core/process/status/termsig_spec.rb
+++ b/spec/ruby/core/process/status/termsig_spec.rb
@@ -6,7 +6,7 @@ describe "Process::Status#termsig" do
ruby_exe("exit(0)")
end
- it "returns true" do
+ it "returns nil" do
$?.termsig.should be_nil
end
end
diff --git a/spec/ruby/core/range/bsearch_spec.rb b/spec/ruby/core/range/bsearch_spec.rb
index 9c93671d85..5254ab756c 100644
--- a/spec/ruby/core/range/bsearch_spec.rb
+++ b/spec/ruby/core/range/bsearch_spec.rb
@@ -9,22 +9,30 @@ describe "Range#bsearch" do
it_behaves_like :enumeratorized_with_unknown_size, :bsearch, (1..3)
it "raises a TypeError if the block returns an Object" do
- -> { (0..1).bsearch { Object.new } }.should raise_error(TypeError)
+ -> { (0..1).bsearch { Object.new } }.should raise_error(TypeError, "wrong argument type Object (must be numeric, true, false or nil)")
end
- it "raises a TypeError if the block returns a String" do
- -> { (0..1).bsearch { "1" } }.should raise_error(TypeError)
+ it "raises a TypeError if the block returns a String and boundaries are Integer values" do
+ -> { (0..1).bsearch { "1" } }.should raise_error(TypeError, "wrong argument type String (must be numeric, true, false or nil)")
+ end
+
+ it "raises a TypeError if the block returns a String and boundaries are Float values" do
+ -> { (0.0..1.0).bsearch { "1" } }.should raise_error(TypeError, "wrong argument type String (must be numeric, true, false or nil)")
end
it "raises a TypeError if the Range has Object values" do
value = mock("range bsearch")
r = Range.new value, value
- -> { r.bsearch { true } }.should raise_error(TypeError)
+ -> { r.bsearch { true } }.should raise_error(TypeError, "can't do binary search for MockObject")
end
it "raises a TypeError if the Range has String values" do
- -> { ("a".."e").bsearch { true } }.should raise_error(TypeError)
+ -> { ("a".."e").bsearch { true } }.should raise_error(TypeError, "can't do binary search for String")
+ end
+
+ it "raises TypeError when non-Numeric begin/end and block not passed" do
+ -> { ("a".."e").bsearch }.should raise_error(TypeError, "can't do binary search for String")
end
context "with Integer values" do
@@ -94,6 +102,10 @@ describe "Range#bsearch" do
(4..2).bsearch { 0 }.should == nil
(4..2).bsearch { -1 }.should == nil
end
+
+ it "returns enumerator when block not passed" do
+ (0...3).bsearch.kind_of?(Enumerator).should == true
+ end
end
context "with Float values" do
@@ -156,7 +168,6 @@ describe "Range#bsearch" do
it "returns nil if the block returns greater than zero for every element" do
(0.3..3.0).bsearch { |x| x <=> -1 }.should be_nil
-
end
it "returns nil if the block never returns zero" do
@@ -213,6 +224,10 @@ describe "Range#bsearch" do
(0...inf).bsearch { |x| x >= Float::MAX ? 0 : 1 }.should == Float::MAX
end
end
+
+ it "returns enumerator when block not passed" do
+ (0.1...2.3).bsearch.kind_of?(Enumerator).should == true
+ end
end
context "with endless ranges and Integer values" do
@@ -250,6 +265,10 @@ describe "Range#bsearch" do
[1, 2, 3].should include(result)
end
end
+
+ it "returns enumerator when block not passed" do
+ eval("(-2..)").bsearch.kind_of?(Enumerator).should == true
+ end
end
context "with endless ranges and Float values" do
@@ -327,8 +346,11 @@ describe "Range#bsearch" do
eval("(0.0...)").bsearch { 0 }.should != inf
end
end
- end
+ it "returns enumerator when block not passed" do
+ eval("(0.1..)").bsearch.kind_of?(Enumerator).should == true
+ end
+ end
context "with beginless ranges and Integer values" do
context "with a block returning true or false" do
@@ -361,6 +383,10 @@ describe "Range#bsearch" do
[1, 2, 3].should include(result)
end
end
+
+ it "returns enumerator when block not passed" do
+ (..10).bsearch.kind_of?(Enumerator).should == true
+ end
end
context "with beginless ranges and Float values" do
@@ -432,5 +458,9 @@ describe "Range#bsearch" do
(...inf).bsearch { |x| 3 - x }.should == 3
end
end
+
+ it "returns enumerator when block not passed" do
+ (..-0.1).bsearch.kind_of?(Enumerator).should == true
+ end
end
end
diff --git a/spec/ruby/core/rational/coerce_spec.rb b/spec/ruby/core/rational/coerce_spec.rb
index bba0c810cc..7aea31aea9 100644
--- a/spec/ruby/core/rational/coerce_spec.rb
+++ b/spec/ruby/core/rational/coerce_spec.rb
@@ -1,9 +1,7 @@
require_relative "../../spec_helper"
-ruby_version_is ""..."3.4" do
- require_relative '../../shared/rational/coerce'
+require_relative '../../shared/rational/coerce'
- describe "Rational#coerce" do
- it_behaves_like :rational_coerce, :coerce
- end
+describe "Rational#coerce" do
+ it_behaves_like :rational_coerce, :coerce
end
diff --git a/spec/ruby/core/regexp/shared/new.rb b/spec/ruby/core/regexp/shared/new.rb
index 773882e495..06c32e36cd 100644
--- a/spec/ruby/core/regexp/shared/new.rb
+++ b/spec/ruby/core/regexp/shared/new.rb
@@ -123,14 +123,30 @@ describe :regexp_new_string, shared: true do
(r.options & Regexp::EXTENDED).should_not == 0
end
- it "does not try to convert the second argument to Integer with #to_int method call" do
- ScratchPad.clear
- obj = Object.new
- def obj.to_int() ScratchPad.record(:called) end
+ ruby_version_is ""..."3.2" do
+ it "does not try to convert the second argument to Integer with #to_int method call" do
+ ScratchPad.clear
+ obj = Object.new
+ def obj.to_int() ScratchPad.record(:called) end
+
+ Regexp.send(@method, "Hi", obj)
- Regexp.send(@method, "Hi", obj)
+ ScratchPad.recorded.should == nil
+ end
+ end
- ScratchPad.recorded.should == nil
+ ruby_version_is "3.2" do
+ it "does not try to convert the second argument to Integer with #to_int method call" do
+ ScratchPad.clear
+ obj = Object.new
+ def obj.to_int() ScratchPad.record(:called) end
+
+ -> {
+ Regexp.send(@method, "Hi", obj)
+ }.should complain(/expected true or false as ignorecase/, {verbose: true})
+
+ ScratchPad.recorded.should == nil
+ end
end
ruby_version_is ""..."3.2" do
@@ -188,12 +204,12 @@ describe :regexp_new_string, shared: true do
end
it "raises an Argument error if the second argument contains unsupported chars" do
- -> { Regexp.send(@method, 'Hi', 'e') }.should raise_error(ArgumentError)
- -> { Regexp.send(@method, 'Hi', 'n') }.should raise_error(ArgumentError)
- -> { Regexp.send(@method, 'Hi', 's') }.should raise_error(ArgumentError)
- -> { Regexp.send(@method, 'Hi', 'u') }.should raise_error(ArgumentError)
- -> { Regexp.send(@method, 'Hi', 'j') }.should raise_error(ArgumentError)
- -> { Regexp.send(@method, 'Hi', 'mjx') }.should raise_error(ArgumentError)
+ -> { Regexp.send(@method, 'Hi', 'e') }.should raise_error(ArgumentError, "unknown regexp option: e")
+ -> { Regexp.send(@method, 'Hi', 'n') }.should raise_error(ArgumentError, "unknown regexp option: n")
+ -> { Regexp.send(@method, 'Hi', 's') }.should raise_error(ArgumentError, "unknown regexp option: s")
+ -> { Regexp.send(@method, 'Hi', 'u') }.should raise_error(ArgumentError, "unknown regexp option: u")
+ -> { Regexp.send(@method, 'Hi', 'j') }.should raise_error(ArgumentError, "unknown regexp option: j")
+ -> { Regexp.send(@method, 'Hi', 'mjx') }.should raise_error(ArgumentError, /unknown regexp option: mjx\b/)
end
end
diff --git a/spec/ruby/core/signal/trap_spec.rb b/spec/ruby/core/signal/trap_spec.rb
index b3186cda92..e238da3ca2 100644
--- a/spec/ruby/core/signal/trap_spec.rb
+++ b/spec/ruby/core/signal/trap_spec.rb
@@ -264,6 +264,14 @@ describe "Signal.trap" do
end
end
+ %w[SEGV BUS ILL FPE VTALRM].each do |signal|
+ it "raises ArgumentError for SIG#{signal} which is reserved by Ruby" do
+ -> {
+ Signal.trap(signal, -> {})
+ }.should raise_error(ArgumentError, "can't trap reserved signal: SIG#{signal}")
+ end
+ end
+
it "allows to register a handler for all known signals, except reserved signals for which it raises ArgumentError" do
out = ruby_exe(fixture(__FILE__, "trap_all.rb"), args: "2>&1")
out.should == "OK\n"
diff --git a/spec/ruby/core/string/fixtures/utf-8-encoding.rb b/spec/ruby/core/string/fixtures/utf-8-encoding.rb
deleted file mode 100644
index fd243ec522..0000000000
--- a/spec/ruby/core/string/fixtures/utf-8-encoding.rb
+++ /dev/null
@@ -1,7 +0,0 @@
-# -*- encoding: utf-8 -*-
-module StringSpecs
- class UTF8Encoding
- def self.source_encoding; __ENCODING__; end
- def self.egrave; "é"; end
- end
-end
diff --git a/spec/ruby/core/string/rindex_spec.rb b/spec/ruby/core/string/rindex_spec.rb
index 45ff13a006..f6271b270d 100644
--- a/spec/ruby/core/string/rindex_spec.rb
+++ b/spec/ruby/core/string/rindex_spec.rb
@@ -1,7 +1,6 @@
# -*- encoding: utf-8 -*-
require_relative '../../spec_helper'
require_relative 'fixtures/classes'
-require_relative 'fixtures/utf-8-encoding'
describe "String#rindex with object" do
it "raises a TypeError if obj isn't a String or Regexp" do
diff --git a/spec/ruby/core/thread/backtrace/location/lineno_spec.rb b/spec/ruby/core/thread/backtrace/location/lineno_spec.rb
index d14cf17514..10457f80f0 100644
--- a/spec/ruby/core/thread/backtrace/location/lineno_spec.rb
+++ b/spec/ruby/core/thread/backtrace/location/lineno_spec.rb
@@ -7,7 +7,7 @@ describe 'Thread::Backtrace::Location#lineno' do
@line = __LINE__ - 1
end
- it 'returns the absolute path of the call frame' do
+ it 'returns the line number of the call frame' do
@frame.lineno.should == @line
end
diff --git a/spec/ruby/core/thread/fetch_spec.rb b/spec/ruby/core/thread/fetch_spec.rb
index 6b37d4cfc5..85ffb71874 100644
--- a/spec/ruby/core/thread/fetch_spec.rb
+++ b/spec/ruby/core/thread/fetch_spec.rb
@@ -29,6 +29,36 @@ describe 'Thread#fetch' do
end
end
+ describe 'with a block' do
+ it 'returns the value of the fiber-local variable if value has been assigned' do
+ th = Thread.new { Thread.current[:cat] = 'meow' }
+ th.join
+ th.fetch(:cat) { true }.should == 'meow'
+ end
+
+ it "returns the block value if fiber-local variable hasn't been assigned" do
+ th = Thread.new {}
+ th.join
+ th.fetch(:cat) { true }.should == true
+ end
+
+ it "does not call the block if value has been assigned" do
+ th = Thread.new { Thread.current[:cat] = 'meow' }
+ th.join
+ var = :not_updated
+ th.fetch(:cat) { var = :updated }.should == 'meow'
+ var.should == :not_updated
+ end
+
+ it "uses the block if a default is given and warns about it" do
+ th = Thread.new {}
+ th.join
+ -> {
+ th.fetch(:cat, false) { true }.should == true
+ }.should complain(/warning: block supersedes default value argument/)
+ end
+ end
+
it 'raises an ArgumentError when not passed one or two arguments' do
-> { Thread.current.fetch() }.should raise_error(ArgumentError)
-> { Thread.current.fetch(1, 2, 3) }.should raise_error(ArgumentError)
diff --git a/spec/ruby/core/thread/thread_variable_get_spec.rb b/spec/ruby/core/thread/thread_variable_get_spec.rb
index 38f90d5830..0ad19bfd88 100644
--- a/spec/ruby/core/thread/thread_variable_get_spec.rb
+++ b/spec/ruby/core/thread/thread_variable_get_spec.rb
@@ -13,7 +13,7 @@ describe "Thread#thread_variable_get" do
@t.thread_variable_get(:a).should be_nil
end
- it "returns the value previously set by #[]=" do
+ it "returns the value previously set by #thread_variable_set" do
@t.thread_variable_set :a, 49
@t.thread_variable_get(:a).should == 49
end
diff --git a/spec/ruby/core/time/deconstruct_keys_spec.rb b/spec/ruby/core/time/deconstruct_keys_spec.rb
index fbb0ec2164..ee17e7dbd4 100644
--- a/spec/ruby/core/time/deconstruct_keys_spec.rb
+++ b/spec/ruby/core/time/deconstruct_keys_spec.rb
@@ -37,8 +37,9 @@ ruby_version_is "3.2" do
Time.new(2022, 10, 5, 13, 30).deconstruct_keys(['year', []]).should == {}
end
- it "ignores not existing Symbol keys" do
- Time.new(2022, 10, 5, 13, 30).deconstruct_keys([:year, :a]).should == { year: 2022 }
+ it "ignores not existing Symbol keys and processes keys after the first non-existing one" do
+ d = Time.utc(2022, 10, 5, 13, 30)
+ d.deconstruct_keys([:year, :a, :month, :b, :day]).should == { year: 2022, month: 10, day: 5 }
end
end
end
diff --git a/spec/ruby/language/assignments_spec.rb b/spec/ruby/language/assignments_spec.rb
new file mode 100644
index 0000000000..005c1f0dc3
--- /dev/null
+++ b/spec/ruby/language/assignments_spec.rb
@@ -0,0 +1,150 @@
+require_relative '../spec_helper'
+
+# Should be synchronized with spec/ruby/language/optional_assignments_spec.rb
+describe 'Assignments' do
+ describe 'using +=' do
+ describe 'using an accessor' do
+ before do
+ klass = Class.new { attr_accessor :b }
+ @a = klass.new
+ end
+
+ it 'does evaluate receiver only once when assigns' do
+ ScratchPad.record []
+ @a.b = 1
+
+ (ScratchPad << :evaluated; @a).b += 2
+
+ ScratchPad.recorded.should == [:evaluated]
+ @a.b.should == 3
+ end
+
+ it 'ignores method visibility when receiver is self' do
+ klass_with_private_methods = Class.new do
+ def initialize(n) @a = n end
+ def public_method(n); self.a += n end
+ private
+ def a; @a end
+ def a=(n) @a = n; 42 end
+ end
+
+ a = klass_with_private_methods.new(0)
+ a.public_method(2).should == 2
+ end
+ end
+
+ describe 'using a #[]' do
+ before do
+ klass = Class.new do
+ def [](k)
+ @hash ||= {}
+ @hash[k]
+ end
+
+ def []=(k, v)
+ @hash ||= {}
+ @hash[k] = v
+ 7
+ end
+ end
+ @b = klass.new
+ end
+
+ it 'evaluates receiver only once when assigns' do
+ ScratchPad.record []
+ a = {k: 1}
+
+ (ScratchPad << :evaluated; a)[:k] += 2
+
+ ScratchPad.recorded.should == [:evaluated]
+ a[:k].should == 3
+ end
+
+ it 'ignores method visibility when receiver is self' do
+ klass_with_private_methods = Class.new do
+ def initialize(h) @a = h end
+ def public_method(k, n); self[k] += n end
+ private
+ def [](k) @a[k] end
+ def []=(k, v) @a[k] = v; 42 end
+ end
+
+ a = klass_with_private_methods.new(k: 0)
+ a.public_method(:k, 2).should == 2
+ end
+
+ context 'splatted argument' do
+ it 'correctly handles it' do
+ @b[:m] = 10
+ (@b[*[:m]] += 10).should == 20
+ @b[:m].should == 20
+
+ @b[:n] = 10
+ (@b[*(1; [:n])] += 10).should == 20
+ @b[:n].should == 20
+
+ @b[:k] = 10
+ (@b[*begin 1; [:k] end] += 10).should == 20
+ @b[:k].should == 20
+ end
+
+ it 'calls #to_a only once' do
+ k = Object.new
+ def k.to_a
+ ScratchPad << :to_a
+ [:k]
+ end
+
+ ScratchPad.record []
+ @b[:k] = 10
+ (@b[*k] += 10).should == 20
+ @b[:k].should == 20
+ ScratchPad.recorded.should == [:to_a]
+ end
+
+ it 'correctly handles a nested splatted argument' do
+ @b[:k] = 10
+ (@b[*[*[:k]]] += 10).should == 20
+ @b[:k].should == 20
+ end
+
+ it 'correctly handles multiple nested splatted arguments' do
+ klass_with_multiple_parameters = Class.new do
+ def [](k1, k2, k3)
+ @hash ||= {}
+ @hash[:"#{k1}#{k2}#{k3}"]
+ end
+
+ def []=(k1, k2, k3, v)
+ @hash ||= {}
+ @hash[:"#{k1}#{k2}#{k3}"] = v
+ 7
+ end
+ end
+ a = klass_with_multiple_parameters.new
+
+ a[:a, :b, :c] = 10
+ (a[*[:a], *[:b], *[:c]] += 10).should == 20
+ a[:a, :b, :c].should == 20
+ end
+ end
+ end
+
+ describe 'using compounded constants' do
+ it 'causes side-effects of the module part to be applied only once (when assigns)' do
+ module ConstantSpecs
+ OpAssignTrue = 1
+ end
+
+ suppress_warning do # already initialized constant
+ x = 0
+ (x += 1; ConstantSpecs)::OpAssignTrue += 2
+ x.should == 1
+ ConstantSpecs::OpAssignTrue.should == 3
+ end
+
+ ConstantSpecs.send :remove_const, :OpAssignTrue
+ end
+ end
+ end
+end
diff --git a/spec/ruby/language/block_spec.rb b/spec/ruby/language/block_spec.rb
index 90329e2f6f..578d9cb3b0 100644
--- a/spec/ruby/language/block_spec.rb
+++ b/spec/ruby/language/block_spec.rb
@@ -40,10 +40,42 @@ describe "A block yielded a single" do
m([1, 2]) { |a=5, b, c, d| [a, b, c, d] }.should == [5, 1, 2, nil]
end
+ it "assigns elements to pre arguments" do
+ m([1, 2]) { |a, b, c, d=5| [a, b, c, d] }.should == [1, 2, nil, 5]
+ end
+
+ it "assigns elements to pre and post arguments" do
+ m([1 ]) { |a, b=5, c=6, d, e| [a, b, c, d, e] }.should == [1, 5, 6, nil, nil]
+ m([1, 2 ]) { |a, b=5, c=6, d, e| [a, b, c, d, e] }.should == [1, 5, 6, 2, nil]
+ m([1, 2, 3 ]) { |a, b=5, c=6, d, e| [a, b, c, d, e] }.should == [1, 5, 6, 2, 3]
+ m([1, 2, 3, 4 ]) { |a, b=5, c=6, d, e| [a, b, c, d, e] }.should == [1, 2, 6, 3, 4]
+ m([1, 2, 3, 4, 5 ]) { |a, b=5, c=6, d, e| [a, b, c, d, e] }.should == [1, 2, 3, 4, 5]
+ m([1, 2, 3, 4, 5, 6]) { |a, b=5, c=6, d, e| [a, b, c, d, e] }.should == [1, 2, 3, 4, 5]
+ end
+
+ it "assigns elements to pre and post arguments when *rest is present" do
+ m([1 ]) { |a, b=5, c=6, *d, e, f| [a, b, c, d, e, f] }.should == [1, 5, 6, [], nil, nil]
+ m([1, 2 ]) { |a, b=5, c=6, *d, e, f| [a, b, c, d, e, f] }.should == [1, 5, 6, [], 2, nil]
+ m([1, 2, 3 ]) { |a, b=5, c=6, *d, e, f| [a, b, c, d, e, f] }.should == [1, 5, 6, [], 2, 3]
+ m([1, 2, 3, 4 ]) { |a, b=5, c=6, *d, e, f| [a, b, c, d, e, f] }.should == [1, 2, 6, [], 3, 4]
+ m([1, 2, 3, 4, 5 ]) { |a, b=5, c=6, *d, e, f| [a, b, c, d, e, f] }.should == [1, 2, 3, [], 4, 5]
+ m([1, 2, 3, 4, 5, 6]) { |a, b=5, c=6, *d, e, f| [a, b, c, d, e, f] }.should == [1, 2, 3, [4], 5, 6]
+ end
+
ruby_version_is "3.2" do
it "does not autosplat single argument to required arguments when a keyword rest argument is present" do
m([1, 2]) { |a, **k| [a, k] }.should == [[1, 2], {}]
end
+
+ it "does not autosplat single argument to required arguments when keyword arguments are present" do
+ m([1, 2]) { |a, b: :b, c: :c| [a, b, c] }.should == [[1, 2], :b, :c]
+ end
+
+ it "raises error when required keyword arguments are present" do
+ -> {
+ m([1, 2]) { |a, b:, c:| [a, b, c] }
+ }.should raise_error(ArgumentError, "missing keywords: :b, :c")
+ end
end
ruby_version_is ''..."3.2" do
@@ -51,6 +83,16 @@ describe "A block yielded a single" do
it "autosplats single argument to required arguments when a keyword rest argument is present" do
m([1, 2]) { |a, **k| [a, k] }.should == [1, {}]
end
+
+ it "autosplats single argument to required arguments when optional keyword arguments are present" do
+ m([1, 2]) { |a, b: :b, c: :c| [a, b, c] }.should == [1, :b, :c]
+ end
+
+ it "raises error when required keyword arguments are present" do
+ -> {
+ m([1, 2]) { |a, b:, c:| [a, b, c] }
+ }.should raise_error(ArgumentError, "missing keywords: :b, :c")
+ end
end
it "assigns elements to mixed argument types" do
@@ -368,7 +410,6 @@ describe "A block" do
-> { @y.s(obj) { |a, b| } }.should raise_error(ZeroDivisionError)
end
-
end
describe "taking |a, *b| arguments" do
@@ -701,6 +742,42 @@ describe "A block" do
eval("Proc.new { |_,_| }").should be_an_instance_of(Proc)
end
end
+
+ describe 'pre and post parameters' do
+ it "assigns nil to unassigned required arguments" do
+ proc { |a, *b, c, d| [a, b, c, d] }.call(1, 2).should == [1, [], 2, nil]
+ end
+
+ it "assigns elements to optional arguments" do
+ proc { |a=5, b=4, c=3| [a, b, c] }.call(1, 2).should == [1, 2, 3]
+ end
+
+ it "assigns elements to post arguments" do
+ proc { |a=5, b, c, d| [a, b, c, d] }.call(1, 2).should == [5, 1, 2, nil]
+ end
+
+ it "assigns elements to pre arguments" do
+ proc { |a, b, c, d=5| [a, b, c, d] }.call(1, 2).should == [1, 2, nil, 5]
+ end
+
+ it "assigns elements to pre and post arguments" do
+ proc { |a, b=5, c=6, d, e| [a, b, c, d, e] }.call(1 ).should == [1, 5, 6, nil, nil]
+ proc { |a, b=5, c=6, d, e| [a, b, c, d, e] }.call(1, 2 ).should == [1, 5, 6, 2, nil]
+ proc { |a, b=5, c=6, d, e| [a, b, c, d, e] }.call(1, 2, 3 ).should == [1, 5, 6, 2, 3]
+ proc { |a, b=5, c=6, d, e| [a, b, c, d, e] }.call(1, 2, 3, 4 ).should == [1, 2, 6, 3, 4]
+ proc { |a, b=5, c=6, d, e| [a, b, c, d, e] }.call(1, 2, 3, 4, 5 ).should == [1, 2, 3, 4, 5]
+ proc { |a, b=5, c=6, d, e| [a, b, c, d, e] }.call(1, 2, 3, 4, 5, 6).should == [1, 2, 3, 4, 5]
+ end
+
+ it "assigns elements to pre and post arguments when *rest is present" do
+ proc { |a, b=5, c=6, *d, e, f| [a, b, c, d, e, f] }.call(1 ).should == [1, 5, 6, [], nil, nil]
+ proc { |a, b=5, c=6, *d, e, f| [a, b, c, d, e, f] }.call(1, 2 ).should == [1, 5, 6, [], 2, nil]
+ proc { |a, b=5, c=6, *d, e, f| [a, b, c, d, e, f] }.call(1, 2, 3 ).should == [1, 5, 6, [], 2, 3]
+ proc { |a, b=5, c=6, *d, e, f| [a, b, c, d, e, f] }.call(1, 2, 3, 4 ).should == [1, 2, 6, [], 3, 4]
+ proc { |a, b=5, c=6, *d, e, f| [a, b, c, d, e, f] }.call(1, 2, 3, 4, 5 ).should == [1, 2, 3, [], 4, 5]
+ proc { |a, b=5, c=6, *d, e, f| [a, b, c, d, e, f] }.call(1, 2, 3, 4, 5, 6).should == [1, 2, 3, [4], 5, 6]
+ end
+ end
end
describe "Block-local variables" do
@@ -921,7 +998,7 @@ end
describe "Anonymous block forwarding" do
ruby_version_is "3.1" do
- it "forwards blocks to other functions that formally declare anonymous blocks" do
+ it "forwards blocks to other method that formally declares anonymous block" do
eval <<-EOF
def b(&); c(&) end
def c(&); yield :non_null end
diff --git a/spec/ruby/language/case_spec.rb b/spec/ruby/language/case_spec.rb
index 1a3925c9c6..cfa612b93a 100644
--- a/spec/ruby/language/case_spec.rb
+++ b/spec/ruby/language/case_spec.rb
@@ -399,6 +399,22 @@ describe "The 'case'-construct" do
:called
end.should == :called
end
+
+ it "supports declaring variables in the case target expression" do
+ def test(v)
+ case new_variable_in_expression = v
+ when true
+ # This extra block is a test that `new_variable_in_expression` is declared outside of it and not inside
+ self.then { new_variable_in_expression }
+ else
+ # Same
+ self.then { new_variable_in_expression.casecmp?("foo") }
+ end
+ end
+
+ self.test("bar").should == false
+ self.test(true).should == true
+ end
end
describe "The 'case'-construct with no target expression" do
diff --git a/spec/ruby/language/defined_spec.rb b/spec/ruby/language/defined_spec.rb
index b84fe9394a..34408c0190 100644
--- a/spec/ruby/language/defined_spec.rb
+++ b/spec/ruby/language/defined_spec.rb
@@ -116,6 +116,11 @@ describe "The defined? keyword when called with a method name" do
defined?(obj.a_defined_method).should == "method"
end
+ it "returns 'method' for []=" do
+ a = []
+ defined?(a[0] = 1).should == "method"
+ end
+
it "returns nil if the method is not defined" do
obj = DefinedSpecs::Basic.new
defined?(obj.an_undefined_method).should be_nil
@@ -231,6 +236,14 @@ describe "The defined? keyword for an expression" do
defined?(@@defined_specs_x = 2).should == "assignment"
end
+ it "returns 'assignment' for assigning a constant" do
+ defined?(A = 2).should == "assignment"
+ end
+
+ it "returns 'assignment' for assigning a fully qualified constant" do
+ defined?(Object::A = 2).should == "assignment"
+ end
+
it "returns 'assignment' for assigning multiple variables" do
defined?((a, b = 1, 2)).should == "assignment"
end
@@ -248,7 +261,27 @@ describe "The defined? keyword for an expression" do
end
it "returns 'assignment' for an expression with '+='" do
- defined?(x += 2).should == "assignment"
+ defined?(a += 1).should == "assignment"
+ defined?(@a += 1).should == "assignment"
+ defined?(@@a += 1).should == "assignment"
+ defined?($a += 1).should == "assignment"
+ defined?(A += 1).should == "assignment"
+ # fully qualified constant check is moved out into a separate test case
+ defined?(a.b += 1).should == "assignment"
+ defined?(a[:b] += 1).should == "assignment"
+ end
+
+ # https://bugs.ruby-lang.org/issues/20111
+ ruby_version_is ""..."3.4" do
+ it "returns 'expression' for an assigning a fully qualified constant with '+='" do
+ defined?(Object::A += 1).should == "expression"
+ end
+ end
+
+ ruby_version_is "3.4" do
+ it "returns 'assignment' for an assigning a fully qualified constant with '+='" do
+ defined?(Object::A += 1).should == "assignment"
+ end
end
it "returns 'assignment' for an expression with '*='" do
@@ -279,12 +312,90 @@ describe "The defined? keyword for an expression" do
defined?(x >>= 2).should == "assignment"
end
- it "returns 'assignment' for an expression with '||='" do
- defined?(x ||= 2).should == "assignment"
+ context "||=" do
+ it "returns 'assignment' for assigning a local variable with '||='" do
+ defined?(a ||= true).should == "assignment"
+ end
+
+ it "returns 'assignment' for assigning an instance variable with '||='" do
+ defined?(@a ||= true).should == "assignment"
+ end
+
+ it "returns 'assignment' for assigning a class variable with '||='" do
+ defined?(@@a ||= true).should == "assignment"
+ end
+
+ it "returns 'assignment' for assigning a global variable with '||='" do
+ defined?($a ||= true).should == "assignment"
+ end
+
+ it "returns 'assignment' for assigning a constant with '||='" do
+ defined?(A ||= true).should == "assignment"
+ end
+
+ # https://bugs.ruby-lang.org/issues/20111
+ ruby_version_is ""..."3.4" do
+ it "returns 'expression' for assigning a fully qualified constant with '||='" do
+ defined?(Object::A ||= true).should == "expression"
+ end
+ end
+
+ ruby_version_is "3.4" do
+ it "returns 'assignment' for assigning a fully qualified constant with '||='" do
+ defined?(Object::A ||= true).should == "assignment"
+ end
+ end
+
+ it "returns 'assignment' for assigning an attribute with '||='" do
+ defined?(a.b ||= true).should == "assignment"
+ end
+
+ it "returns 'assignment' for assigning a referenced element with '||='" do
+ defined?(a[:b] ||= true).should == "assignment"
+ end
end
- it "returns 'assignment' for an expression with '&&='" do
- defined?(x &&= 2).should == "assignment"
+ context "&&=" do
+ it "returns 'assignment' for assigning a local variable with '&&='" do
+ defined?(a &&= true).should == "assignment"
+ end
+
+ it "returns 'assignment' for assigning an instance variable with '&&='" do
+ defined?(@a &&= true).should == "assignment"
+ end
+
+ it "returns 'assignment' for assigning a class variable with '&&='" do
+ defined?(@@a &&= true).should == "assignment"
+ end
+
+ it "returns 'assignment' for assigning a global variable with '&&='" do
+ defined?($a &&= true).should == "assignment"
+ end
+
+ it "returns 'assignment' for assigning a constant with '&&='" do
+ defined?(A &&= true).should == "assignment"
+ end
+
+ # https://bugs.ruby-lang.org/issues/20111
+ ruby_version_is ""..."3.4" do
+ it "returns 'expression' for assigning a fully qualified constant with '&&='" do
+ defined?(Object::A &&= true).should == "expression"
+ end
+ end
+
+ ruby_version_is "3.4" do
+ it "returns 'assignment' for assigning a fully qualified constant with '&&='" do
+ defined?(Object::A &&= true).should == "assignment"
+ end
+ end
+
+ it "returns 'assignment' for assigning an attribute with '&&='" do
+ defined?(a.b &&= true).should == "assignment"
+ end
+
+ it "returns 'assignment' for assigning a referenced element with '&&='" do
+ defined?(a[:b] &&= true).should == "assignment"
+ end
end
it "returns 'assignment' for an expression with '**='" do
diff --git a/spec/ruby/language/delegation_spec.rb b/spec/ruby/language/delegation_spec.rb
index 020787aff6..d780506421 100644
--- a/spec/ruby/language/delegation_spec.rb
+++ b/spec/ruby/language/delegation_spec.rb
@@ -31,10 +31,10 @@ describe "delegation with def(...)" do
def delegate(...)
target ...
end
- RUBY
- end
+ RUBY
+ end
- a.new.delegate(1, b: 2).should == Range.new([[], {}], nil, true)
+ a.new.delegate(1, b: 2).should == Range.new([[], {}], nil, true)
end
end
@@ -61,3 +61,33 @@ describe "delegation with def(x, ...)" do
a.new.delegate_block(0, 1, b: 2) { |x| x }.should == [{b: 2}, [1]]
end
end
+
+ruby_version_is "3.2" do
+ describe "delegation with def(*)" do
+ it "delegates rest" do
+ a = Class.new(DelegationSpecs::Target)
+ a.class_eval(<<-RUBY)
+ def delegate(*)
+ target(*)
+ end
+ RUBY
+
+ a.new.delegate(0, 1).should == [[0, 1], {}]
+ end
+ end
+end
+
+ruby_version_is "3.2" do
+ describe "delegation with def(**)" do
+ it "delegates kwargs" do
+ a = Class.new(DelegationSpecs::Target)
+ a.class_eval(<<-RUBY)
+ def delegate(**)
+ target(**)
+ end
+ RUBY
+
+ a.new.delegate(a: 1) { |x| x }.should == [[], {a: 1}]
+ end
+ end
+end
diff --git a/spec/ruby/language/fixtures/rescue/top_level.rb b/spec/ruby/language/fixtures/rescue/top_level.rb
new file mode 100644
index 0000000000..59e78ef1d6
--- /dev/null
+++ b/spec/ruby/language/fixtures/rescue/top_level.rb
@@ -0,0 +1,7 @@
+# capturing in local variable at top-level
+
+begin
+ raise "message"
+rescue => e
+ ScratchPad << e.message
+end
diff --git a/spec/ruby/language/fixtures/super.rb b/spec/ruby/language/fixtures/super.rb
index 94a2a91be0..c5bdcf0e40 100644
--- a/spec/ruby/language/fixtures/super.rb
+++ b/spec/ruby/language/fixtures/super.rb
@@ -539,6 +539,30 @@ module SuperSpecs
args
end
+ def m3(*args)
+ args
+ end
+
+ def m4(*args)
+ args
+ end
+
+ def m_default(*args)
+ args
+ end
+
+ def m_rest(*args)
+ args
+ end
+
+ def m_pre_default_rest_post(*args)
+ args
+ end
+
+ def m_kwrest(**kw)
+ kw
+ end
+
def m_modified(*args)
args
end
@@ -549,6 +573,30 @@ module SuperSpecs
super
end
+ def m3(_, _, _)
+ super
+ end
+
+ def m4(_, _, _, _)
+ super
+ end
+
+ def m_default(_ = 0)
+ super
+ end
+
+ def m_rest(*_)
+ super
+ end
+
+ def m_pre_default_rest_post(_, _, _=:a, _=:b, *_, _, _)
+ super
+ end
+
+ def m_kwrest(**_)
+ super
+ end
+
def m_modified(_, _)
_ = 14
super
diff --git a/spec/ruby/language/method_spec.rb b/spec/ruby/language/method_spec.rb
index 5f42c52341..e34ff7e1a6 100644
--- a/spec/ruby/language/method_spec.rb
+++ b/spec/ruby/language/method_spec.rb
@@ -1335,6 +1335,7 @@ describe "An endless method definition" do
end
end
+ # tested more thoroughly in language/delegation_spec.rb
context "with args forwarding" do
evaluate <<-ruby do
def mm(word, num:)
diff --git a/spec/ruby/language/optional_assignments_spec.rb b/spec/ruby/language/optional_assignments_spec.rb
index 02461655d6..2443cc6b79 100644
--- a/spec/ruby/language/optional_assignments_spec.rb
+++ b/spec/ruby/language/optional_assignments_spec.rb
@@ -57,7 +57,7 @@ describe 'Optional variable assignments' do
end
end
- describe 'using a accessor' do
+ describe 'using an accessor' do
before do
klass = Class.new { attr_accessor :b }
@a = klass.new
@@ -103,6 +103,16 @@ describe 'Optional variable assignments' do
@a.b.should == 10
end
+ it 'does evaluate receiver only once when assigns' do
+ ScratchPad.record []
+ @a.b = nil
+
+ (ScratchPad << :evaluated; @a).b ||= 10
+
+ ScratchPad.recorded.should == [:evaluated]
+ @a.b.should == 10
+ end
+
it 'returns the new value if set to false' do
def @a.b=(x)
:v
@@ -122,29 +132,148 @@ describe 'Optional variable assignments' do
(@a.b ||= 20).should == 10
end
- it 'works when writer is private' do
+ it 'ignores method visibility when receiver is self' do
+ klass_with_private_methods = Class.new do
+ def initialize(v) @a = v end
+ def public_method(v); self.a ||= v end
+ private
+ def a; @a end
+ def a=(v) @a = v; 42 end
+ end
+
+ a = klass_with_private_methods.new(false)
+ a.public_method(10).should == 10
+ end
+ end
+
+ describe 'using a #[]' do
+ before do
+ @a = {}
klass = Class.new do
- def t
- self.b = false
- (self.b ||= 10).should == 10
- (self.b ||= 20).should == 10
+ def [](k)
+ @hash ||= {}
+ @hash[k]
+ end
+
+ def []=(k, v)
+ @hash ||= {}
+ @hash[k] = v
+ 7
end
+ end
+ @b = klass.new
+ end
+
+ it 'returns the assigned value, not the result of the []= method with ||=' do
+ (@b[:k] ||= 12).should == 12
+ end
+
+ it "evaluates the index precisely once" do
+ ary = [:x, :y]
+ @a[:x] = 15
+ @a[ary.pop] ||= 25
+ ary.should == [:x]
+ @a.should == { x: 15, y: 25 }
+ end
- def b
- @b
+ it "evaluates the index arguments in the correct order" do
+ ary = Class.new(Array) do
+ def [](x, y)
+ super(x + 3 * y)
end
- def b=(x)
- @b = x
- :v
+ def []=(x, y, value)
+ super(x + 3 * y, value)
end
+ end.new
+ ary[0, 0] = 1
+ ary[1, 0] = 1
+ ary[2, 0] = nil
+ ary[3, 0] = 1
+ ary[4, 0] = 1
+ ary[5, 0] = 1
+ ary[6, 0] = nil
+
+ foo = [0, 2]
+
+ ary[foo.pop, foo.pop] ||= 2 # expected `ary[2, 0] ||= 2`
+
+ ary[2, 0].should == 2
+ ary[6, 0].should == nil # returns the same element as `ary[0, 2]`
+ end
+
+ it 'evaluates receiver only once when assigns' do
+ ScratchPad.record []
+ @a[:k] = nil
- private :b=
+ (ScratchPad << :evaluated; @a)[:k] ||= 2
+
+ ScratchPad.recorded.should == [:evaluated]
+ @a[:k].should == 2
+ end
+
+ it 'ignores method visibility when receiver is self' do
+ klass_with_private_methods = Class.new do
+ def initialize(h) @a = h end
+ def public_method(k, v); self[k] ||= v end
+ private
+ def [](k) @a[k] end
+ def []=(k, v) @a[k] = v; 42 end
end
- klass.new.t
+ a = klass_with_private_methods.new(k: false)
+ a.public_method(:k, 10).should == 10
end
+ context 'splatted argument' do
+ it 'correctly handles it' do
+ (@b[*[:m]] ||= 10).should == 10
+ @b[:m].should == 10
+
+ (@b[*(1; [:n])] ||= 10).should == 10
+ @b[:n].should == 10
+
+ (@b[*begin 1; [:k] end] ||= 10).should == 10
+ @b[:k].should == 10
+ end
+
+ it 'calls #to_a only once' do
+ k = Object.new
+ def k.to_a
+ ScratchPad << :to_a
+ [:k]
+ end
+
+ ScratchPad.record []
+ (@b[*k] ||= 20).should == 20
+ @b[:k].should == 20
+ ScratchPad.recorded.should == [:to_a]
+ end
+
+ it 'correctly handles a nested splatted argument' do
+ (@b[*[*[:k]]] ||= 20).should == 20
+ @b[:k].should == 20
+ end
+
+ it 'correctly handles multiple nested splatted arguments' do
+ klass_with_multiple_parameters = Class.new do
+ def [](k1, k2, k3)
+ @hash ||= {}
+ @hash[:"#{k1}#{k2}#{k3}"]
+ end
+
+ def []=(k1, k2, k3, v)
+ @hash ||= {}
+ @hash[:"#{k1}#{k2}#{k3}"] = v
+ 7
+ end
+ end
+ a = klass_with_multiple_parameters.new
+
+ (a[*[:a], *[:b], *[:c]] ||= 20).should == 20
+ a[:a, :b, :c].should == 20
+ end
+ end
end
end
@@ -191,7 +320,7 @@ describe 'Optional variable assignments' do
end
end
- describe 'using a single variable' do
+ describe 'using an accessor' do
before do
klass = Class.new { attr_accessor :b }
@a = klass.new
@@ -236,6 +365,29 @@ describe 'Optional variable assignments' do
@a.b.should == 20
end
+
+ it 'does evaluate receiver only once when assigns' do
+ ScratchPad.record []
+ @a.b = 10
+
+ (ScratchPad << :evaluated; @a).b &&= 20
+
+ ScratchPad.recorded.should == [:evaluated]
+ @a.b.should == 20
+ end
+
+ it 'ignores method visibility when receiver is self' do
+ klass_with_private_methods = Class.new do
+ def initialize(v) @a = v end
+ def public_method(v); self.a &&= v end
+ private
+ def a; @a end
+ def a=(v) @a = v; 42 end
+ end
+
+ a = klass_with_private_methods.new(true)
+ a.public_method(10).should == 10
+ end
end
describe 'using a #[]' do
@@ -297,17 +449,15 @@ describe 'Optional variable assignments' do
end
it 'returns the assigned value, not the result of the []= method with ||=' do
- (@b[:k] ||= 12).should == 12
- end
-
- it 'correctly handles a splatted argument for the index' do
- (@b[*[:k]] ||= 12).should == 12
+ @b[:k] = 10
+ (@b[:k] &&= 12).should == 12
end
it "evaluates the index precisely once" do
ary = [:x, :y]
@a[:x] = 15
- @a[ary.pop] ||= 25
+ @a[:y] = 20
+ @a[ary.pop] &&= 25
ary.should == [:x]
@a.should == { x: 15, y: 25 }
end
@@ -324,24 +474,103 @@ describe 'Optional variable assignments' do
end.new
ary[0, 0] = 1
ary[1, 0] = 1
- ary[2, 0] = nil
+ ary[2, 0] = 1
ary[3, 0] = 1
ary[4, 0] = 1
ary[5, 0] = 1
- ary[6, 0] = nil
+ ary[6, 0] = 1
foo = [0, 2]
- ary[foo.pop, foo.pop] ||= 2
+ ary[foo.pop, foo.pop] &&= 2 # expected `ary[2, 0] &&= 2`
ary[2, 0].should == 2
- ary[6, 0].should == nil
+ ary[6, 0].should == 1 # returns the same element as `ary[0, 2]`
+ end
+
+ it 'evaluates receiver only once when assigns' do
+ ScratchPad.record []
+ @a[:k] = 1
+
+ (ScratchPad << :evaluated; @a)[:k] &&= 2
+
+ ScratchPad.recorded.should == [:evaluated]
+ @a[:k].should == 2
end
it 'returns the assigned value, not the result of the []= method with +=' do
@b[:k] = 17
(@b[:k] += 12).should == 29
end
+
+ it 'ignores method visibility when receiver is self' do
+ klass_with_private_methods = Class.new do
+ def initialize(h) @a = h end
+ def public_method(k, v); self[k] &&= v end
+ private
+ def [](k) @a[k] end
+ def []=(k, v) @a[k] = v; 42 end
+ end
+
+ a = klass_with_private_methods.new(k: true)
+ a.public_method(:k, 10).should == 10
+ end
+
+ context 'splatted argument' do
+ it 'correctly handles it' do
+ @b[:m] = 0
+ (@b[*[:m]] &&= 10).should == 10
+ @b[:m].should == 10
+
+ @b[:n] = 0
+ (@b[*(1; [:n])] &&= 10).should == 10
+ @b[:n].should == 10
+
+ @b[:k] = 0
+ (@b[*begin 1; [:k] end] &&= 10).should == 10
+ @b[:k].should == 10
+ end
+
+ it 'calls #to_a only once' do
+ k = Object.new
+ def k.to_a
+ ScratchPad << :to_a
+ [:k]
+ end
+
+ ScratchPad.record []
+ @b[:k] = 10
+ (@b[*k] &&= 20).should == 20
+ @b[:k].should == 20
+ ScratchPad.recorded.should == [:to_a]
+ end
+
+ it 'correctly handles a nested splatted argument' do
+ @b[:k] = 10
+ (@b[*[*[:k]]] &&= 20).should == 20
+ @b[:k].should == 20
+ end
+
+ it 'correctly handles multiple nested splatted arguments' do
+ klass_with_multiple_parameters = Class.new do
+ def [](k1, k2, k3)
+ @hash ||= {}
+ @hash[:"#{k1}#{k2}#{k3}"]
+ end
+
+ def []=(k1, k2, k3, v)
+ @hash ||= {}
+ @hash[:"#{k1}#{k2}#{k3}"] = v
+ 7
+ end
+ end
+ a = klass_with_multiple_parameters.new
+
+ a[:a, :b, :c] = 10
+ (a[*[:a], *[:b], *[:c]] &&= 20).should == 20
+ a[:a, :b, :c].should == 20
+ end
+ end
end
end
@@ -434,7 +663,7 @@ describe 'Optional constant assignment' do
ConstantSpecs::ClassA::OR_ASSIGNED_CONSTANT2.should == :assigned
end
- it 'causes side-effects of the module part to be applied (for nil constant)' do
+ it 'causes side-effects of the module part to be applied only once (for nil constant)' do
suppress_warning do # already initialized constant
ConstantSpecs::ClassA::NIL_OR_ASSIGNED_CONSTANT2 = nil
x = 0
@@ -492,5 +721,20 @@ describe 'Optional constant assignment' do
ConstantSpecs::OpAssignFalse.should == false
ConstantSpecs.send :remove_const, :OpAssignFalse
end
+
+ it 'causes side-effects of the module part to be applied only once (when assigns)' do
+ module ConstantSpecs
+ OpAssignTrue = true
+ end
+
+ suppress_warning do # already initialized constant
+ x = 0
+ (x += 1; ConstantSpecs)::OpAssignTrue &&= :assigned
+ x.should == 1
+ ConstantSpecs::OpAssignTrue.should == :assigned
+ end
+
+ ConstantSpecs.send :remove_const, :OpAssignTrue
+ end
end
end
diff --git a/spec/ruby/language/pattern_matching_spec.rb b/spec/ruby/language/pattern_matching_spec.rb
index 050a8a052d..a8ec078cd0 100644
--- a/spec/ruby/language/pattern_matching_spec.rb
+++ b/spec/ruby/language/pattern_matching_spec.rb
@@ -207,7 +207,7 @@ describe "Pattern matching" do
in []
end
RUBY
- }.should raise_error(SyntaxError, /syntax error, unexpected `in'|\(eval\):3: syntax error, unexpected keyword_in/)
+ }.should raise_error(SyntaxError, /syntax error, unexpected `in'|\(eval\):3: syntax error, unexpected keyword_in|unexpected 'in'/)
-> {
eval <<~RUBY
@@ -216,7 +216,7 @@ describe "Pattern matching" do
when 1 == 1
end
RUBY
- }.should raise_error(SyntaxError, /syntax error, unexpected `when'|\(eval\):3: syntax error, unexpected keyword_when/)
+ }.should raise_error(SyntaxError, /syntax error, unexpected `when'|\(eval\):3: syntax error, unexpected keyword_when|unexpected 'when'/)
end
it "checks patterns until the first matching" do
@@ -273,7 +273,7 @@ describe "Pattern matching" do
true
end
RUBY
- }.should raise_error(SyntaxError, /unexpected/)
+ }.should raise_error(SyntaxError, /unexpected|expected a delimiter after the predicates of a `when` clause/)
end
it "evaluates the case expression once for multiple patterns, caching the result" do
@@ -739,6 +739,20 @@ describe "Pattern matching" do
RUBY
end
+ it "checks Constant === object before calling #deconstruct" do
+ c1 = Class.new
+ obj = c1.new
+ obj.should_not_receive(:deconstruct)
+ eval(<<~RUBY).should == false
+ case obj
+ in String[1]
+ true
+ else
+ false
+ end
+ RUBY
+ end
+
it "does not match object without #deconstruct method" do
obj = Object.new
obj.should_receive(:respond_to?).with(:deconstruct)
@@ -770,11 +784,7 @@ describe "Pattern matching" do
it "accepts a subclass of Array from #deconstruct" do
obj = Object.new
def obj.deconstruct
- subarray = Class.new(Array).new(2)
- def subarray.[](n)
- n
- end
- subarray
+ Class.new(Array).new([0, 1])
end
eval(<<~RUBY).should == true
@@ -1004,7 +1014,7 @@ describe "Pattern matching" do
in {"a" => 1}
end
RUBY
- }.should raise_error(SyntaxError, /unexpected/)
+ }.should raise_error(SyntaxError, /unexpected|expected a label as the key in the hash pattern/)
end
it "does not support string interpolation in keys" do
@@ -1016,7 +1026,7 @@ describe "Pattern matching" do
in {"#{x}": 1}
end
RUBY
- }.should raise_error(SyntaxError, /symbol literal with interpolation is not allowed/)
+ }.should raise_error(SyntaxError, /symbol literal with interpolation is not allowed|expected a label as the key in the hash pattern/)
end
it "raise SyntaxError when keys duplicate in pattern" do
@@ -1072,6 +1082,20 @@ describe "Pattern matching" do
RUBY
end
+ it "checks Constant === object before calling #deconstruct_keys" do
+ c1 = Class.new
+ obj = c1.new
+ obj.should_not_receive(:deconstruct_keys)
+ eval(<<~RUBY).should == false
+ case obj
+ in String(a: 1)
+ true
+ else
+ false
+ end
+ RUBY
+ end
+
it "does not match object without #deconstruct_keys method" do
obj = Object.new
obj.should_receive(:respond_to?).with(:deconstruct_keys)
@@ -1232,6 +1256,37 @@ describe "Pattern matching" do
RUBY
end
+ it "in {} only matches empty hashes" do
+ eval(<<~RUBY).should == false
+ case {a: 1}
+ in {}
+ true
+ else
+ false
+ end
+ RUBY
+ end
+
+ it "in {**nil} only matches empty hashes" do
+ eval(<<~RUBY).should == true
+ case {}
+ in {**nil}
+ true
+ else
+ false
+ end
+ RUBY
+
+ eval(<<~RUBY).should == false
+ case {a: 1}
+ in {**nil}
+ true
+ else
+ false
+ end
+ RUBY
+ end
+
it "matches anything with **" do
eval(<<~RUBY).should == true
case {a: 1}
@@ -1340,76 +1395,115 @@ describe "Pattern matching" do
end
end
- ruby_version_is "3.1" do
- it "can omit parentheses in one line pattern matching" do
- eval(<<~RUBY).should == [1, 2]
- [1, 2] => a, b
- [a, b]
- RUBY
+ describe "Ruby 3.1 improvements" do
+ ruby_version_is "3.1" do
+ it "can omit parentheses in one line pattern matching" do
+ eval(<<~RUBY).should == [1, 2]
+ [1, 2] => a, b
+ [a, b]
+ RUBY
- eval(<<~RUBY).should == 1
- {a: 1} => a:
- a
- RUBY
- end
+ eval(<<~RUBY).should == 1
+ {a: 1} => a:
+ a
+ RUBY
+ end
- it "supports pinning instance variables" do
- eval(<<~RUBY).should == true
- @a = /a/
- case 'abc'
- in ^@a
- true
+ it "supports pinning instance variables" do
+ eval(<<~RUBY).should == true
+ @a = /a/
+ case 'abc'
+ in ^@a
+ true
+ end
+ RUBY
+ end
+
+ it "supports pinning class variables" do
+ result = nil
+ Module.new do
+ result = module_eval(<<~RUBY)
+ @@a = 0..10
+
+ case 2
+ in ^@@a
+ true
+ end
+ RUBY
end
- RUBY
- end
- it "supports pinning class variables" do
- result = nil
- Module.new do
- result = module_eval(<<~RUBY)
- @@a = 0..10
+ result.should == true
+ end
- case 2
- in ^@@a
+ it "supports pinning global variables" do
+ eval(<<~RUBY).should == true
+ $a = /a/
+ case 'abc'
+ in ^$a
true
end
RUBY
end
- result.should == true
+ it "supports pinning expressions" do
+ eval(<<~RUBY).should == true
+ case 'abc'
+ in ^(/a/)
+ true
+ end
+ RUBY
+
+ eval(<<~RUBY).should == true
+ case 0
+ in ^(0+0)
+ true
+ end
+ RUBY
+ end
+
+ it "supports pinning expressions in array pattern" do
+ eval(<<~RUBY).should == true
+ case [3]
+ in [^(1+2)]
+ true
+ end
+ RUBY
+ end
+
+ it "supports pinning expressions in hash pattern" do
+ eval(<<~RUBY).should == true
+ case {name: '2.6', released_at: Time.new(2018, 12, 25)}
+ in {released_at: ^(Time.new(2010)..Time.new(2020))}
+ true
+ end
+ RUBY
+ end
end
+ end
- it "supports pinning global variables" do
- eval(<<~RUBY).should == true
- $a = /a/
- case 'abc'
- in ^$a
- true
- end
- RUBY
+ describe "value in pattern" do
+ it "returns true if the pattern matches" do
+ eval("1 in 1").should == true
+
+ eval("1 in Integer").should == true
+
+ e = nil
+ eval("[1, 2] in [1, e]").should == true
+ e.should == 2
+
+ k = nil
+ eval("{k: 1} in {k:}").should == true
+ k.should == 1
end
- it "supports pinning expressions" do
- eval(<<~RUBY).should == true
- case 'abc'
- in ^(/a/)
- true
- end
- RUBY
+ it "returns false if the pattern does not match" do
+ eval("1 in 2").should == false
- eval(<<~RUBY).should == true
- case {name: '2.6', released_at: Time.new(2018, 12, 25)}
- in {released_at: ^(Time.new(2010)..Time.new(2020))}
- true
- end
- RUBY
+ eval("1 in Float").should == false
- eval(<<~RUBY).should == true
- case 0
- in ^(0+0)
- true
- end
- RUBY
+ eval("[1, 2] in [2, e]").should == false
+
+ eval("{k: 1} in {k: 2}").should == false
end
end
end
diff --git a/spec/ruby/language/rescue_spec.rb b/spec/ruby/language/rescue_spec.rb
index b91b52fa0f..69ed038fda 100644
--- a/spec/ruby/language/rescue_spec.rb
+++ b/spec/ruby/language/rescue_spec.rb
@@ -61,6 +61,78 @@ describe "The rescue keyword" do
end
end
+ describe 'capturing in a local variable (that defines it)' do
+ it 'captures successfully in a method' do
+ ScratchPad.record []
+
+ def a
+ raise "message"
+ rescue => e
+ ScratchPad << e.message
+ end
+
+ a
+ ScratchPad.recorded.should == ["message"]
+ end
+
+ it 'captures successfully in a block' do
+ ScratchPad.record []
+
+ p = proc do
+ raise "message"
+ rescue => e
+ ScratchPad << e.message
+ end
+
+ p.call
+ ScratchPad.recorded.should == ["message"]
+ end
+
+ it 'captures successfully in a class' do
+ ScratchPad.record []
+
+ class RescueSpecs::C
+ raise "message"
+ rescue => e
+ ScratchPad << e.message
+ end
+
+ ScratchPad.recorded.should == ["message"]
+ end
+
+ it 'captures successfully in a module' do
+ ScratchPad.record []
+
+ module RescueSpecs::M
+ raise "message"
+ rescue => e
+ ScratchPad << e.message
+ end
+
+ ScratchPad.recorded.should == ["message"]
+ end
+
+ it 'captures sucpcessfully in a singleton class' do
+ ScratchPad.record []
+
+ class << Object.new
+ raise "message"
+ rescue => e
+ ScratchPad << e.message
+ end
+
+ ScratchPad.recorded.should == ["message"]
+ end
+
+ it 'captures successfully at the top-level' do
+ ScratchPad.record []
+
+ require_relative 'fixtures/rescue/top_level'
+
+ ScratchPad.recorded.should == ["message"]
+ end
+ end
+
it "returns value from `rescue` if an exception was raised" do
begin
raise
diff --git a/spec/ruby/language/safe_navigator_spec.rb b/spec/ruby/language/safe_navigator_spec.rb
index c3aecff2dd..b1e28c3963 100644
--- a/spec/ruby/language/safe_navigator_spec.rb
+++ b/spec/ruby/language/safe_navigator_spec.rb
@@ -7,43 +7,43 @@ describe "Safe navigator" do
context "when context is nil" do
it "always returns nil" do
- eval("nil&.unknown").should == nil
- eval("[][10]&.unknown").should == nil
+ nil&.unknown.should == nil
+ [][10]&.unknown.should == nil
end
it "can be chained" do
- eval("nil&.one&.two&.three").should == nil
+ nil&.one&.two&.three.should == nil
end
it "doesn't evaluate arguments" do
obj = Object.new
obj.should_not_receive(:m)
- eval("nil&.unknown(obj.m) { obj.m }")
+ nil&.unknown(obj.m) { obj.m }
end
end
context "when context is false" do
it "calls the method" do
- eval("false&.to_s").should == "false"
+ false&.to_s.should == "false"
- -> { eval("false&.unknown") }.should raise_error(NoMethodError)
+ -> { false&.unknown }.should raise_error(NoMethodError)
end
end
context "when context is truthy" do
it "calls the method" do
- eval("1&.to_s").should == "1"
+ 1&.to_s.should == "1"
- -> { eval("1&.unknown") }.should raise_error(NoMethodError)
+ -> { 1&.unknown }.should raise_error(NoMethodError)
end
end
it "takes a list of arguments" do
- eval("[1,2,3]&.first(2)").should == [1,2]
+ [1,2,3]&.first(2).should == [1,2]
end
it "takes a block" do
- eval("[1,2]&.map { |i| i * 2 }").should == [2, 4]
+ [1,2]&.map { |i| i * 2 }.should == [2, 4]
end
it "allows assignment methods" do
@@ -56,29 +56,77 @@ describe "Safe navigator" do
end
obj = klass.new
- eval("obj&.foo = 3").should == 3
+ (obj&.foo = 3).should == 3
obj.foo.should == 3
obj = nil
- eval("obj&.foo = 3").should == nil
+ (obj&.foo = 3).should == nil
end
it "allows assignment operators" do
klass = Class.new do
- attr_accessor :m
+ attr_reader :m
def initialize
@m = 0
end
+
+ def m=(v)
+ @m = v
+ 42
+ end
end
obj = klass.new
- eval("obj&.m += 3")
+ obj&.m += 3
obj.m.should == 3
obj = nil
- eval("obj&.m += 3").should == nil
+ (obj&.m += 3).should == nil
+ end
+
+ it "allows ||= operator" do
+ klass = Class.new do
+ attr_reader :m
+
+ def initialize
+ @m = false
+ end
+
+ def m=(v)
+ @m = v
+ 42
+ end
+ end
+
+ obj = klass.new
+
+ (obj&.m ||= true).should == true
+ obj.m.should == true
+
+ obj = nil
+ (obj&.m ||= true).should == nil
+ obj.should == nil
+ end
+
+ it "allows &&= operator" do
+ klass = Class.new do
+ attr_accessor :m
+
+ def initialize
+ @m = true
+ end
+ end
+
+ obj = klass.new
+
+ (obj&.m &&= false).should == false
+ obj.m.should == false
+
+ obj = nil
+ (obj&.m &&= false).should == nil
+ obj.should == nil
end
it "does not call the operator method lazily with an assignment operator" do
@@ -91,7 +139,7 @@ describe "Safe navigator" do
obj = klass.new
-> {
- eval("obj&.foo += 3")
+ obj&.foo += 3
}.should raise_error(NoMethodError) { |e|
e.name.should == :+
}
diff --git a/spec/ruby/language/super_spec.rb b/spec/ruby/language/super_spec.rb
index d22c603605..a98b3b3091 100644
--- a/spec/ruby/language/super_spec.rb
+++ b/spec/ruby/language/super_spec.rb
@@ -335,6 +335,13 @@ describe "The super keyword" do
it "without explicit arguments that are '_'" do
SuperSpecs::ZSuperWithUnderscores::B.new.m(1, 2).should == [1, 2]
+ SuperSpecs::ZSuperWithUnderscores::B.new.m3(1, 2, 3).should == [1, 2, 3]
+ SuperSpecs::ZSuperWithUnderscores::B.new.m4(1, 2, 3, 4).should == [1, 2, 3, 4]
+ SuperSpecs::ZSuperWithUnderscores::B.new.m_default(1).should == [1]
+ SuperSpecs::ZSuperWithUnderscores::B.new.m_default.should == [0]
+ SuperSpecs::ZSuperWithUnderscores::B.new.m_pre_default_rest_post(1, 2, 3, 4, 5, 6, 7).should == [1, 2, 3, 4, 5, 6, 7]
+ SuperSpecs::ZSuperWithUnderscores::B.new.m_rest(1, 2).should == [1, 2]
+ SuperSpecs::ZSuperWithUnderscores::B.new.m_kwrest(a: 1).should == {a: 1}
end
it "without explicit arguments that are '_' including any modifications" do
diff --git a/spec/ruby/language/variables_spec.rb b/spec/ruby/language/variables_spec.rb
index 23c2cdb557..53d191b456 100644
--- a/spec/ruby/language/variables_spec.rb
+++ b/spec/ruby/language/variables_spec.rb
@@ -367,8 +367,13 @@ describe "Multiple assignment" do
it "assigns indexed elements" do
a = []
- a[1], a[2] = 1
- a.should == [nil, 1, nil]
+ a[1], a[2] = 1, 2
+ a.should == [nil, 1, 2]
+
+ # with splatted argument
+ a = []
+ a[*[1]], a[*[2]] = 1, 2
+ a.should == [nil, 1, 2]
end
it "assigns constants" do
diff --git a/spec/ruby/library/coverage/result_spec.rb b/spec/ruby/library/coverage/result_spec.rb
index 4bcce00cd7..33276778e8 100644
--- a/spec/ruby/library/coverage/result_spec.rb
+++ b/spec/ruby/library/coverage/result_spec.rb
@@ -8,10 +8,16 @@ describe 'Coverage.result' do
@eval_code_file = fixture __FILE__, 'eval_code.rb'
end
+ before :each do
+ Coverage.running?.should == false
+ end
+
after :each do
$LOADED_FEATURES.delete(@class_file)
$LOADED_FEATURES.delete(@config_file)
$LOADED_FEATURES.delete(@eval_code_file)
+
+ Coverage.result if Coverage.running?
end
it 'gives the covered files as a hash with arrays of count or nil' do
@@ -26,6 +32,41 @@ describe 'Coverage.result' do
}
end
+ ruby_version_is "3.2" do
+ it 'returns results for each mode separately when enabled :all modes' do
+ Coverage.start(:all)
+ require @class_file.chomp('.rb')
+ result = Coverage.result
+
+ result.should == {
+ @class_file => {
+ lines: [
+ nil, nil, 1, nil, nil, 1, nil, nil, 0, nil, nil, nil, nil, nil, nil, nil
+ ],
+ branches: {},
+ methods: {
+ [SomeClass, :some_method, 6, 2, 11, 5] => 0
+ }
+ }
+ }
+ end
+
+ it 'returns results for each mode separately when enabled any mode explicitly' do
+ Coverage.start(lines: true)
+ require @class_file.chomp('.rb')
+ result = Coverage.result
+
+ result.should == {
+ @class_file =>
+ {
+ lines: [
+ nil, nil, 1, nil, nil, 1, nil, nil, 0, nil, nil, nil, nil, nil, nil, nil
+ ]
+ }
+ }
+ end
+ end
+
it 'no requires/loads should give empty hash' do
Coverage.start
result = Coverage.result
@@ -75,17 +116,6 @@ describe 'Coverage.result' do
end
end
- ruby_version_is '3.1' do
- it 'second Coverage.start give exception' do
- Coverage.start
- -> {
- require @config_file.chomp('.rb')
- }.should raise_error(RuntimeError, 'coverage measurement is already setup')
- ensure
- Coverage.result
- end
- end
-
it 'does not include the file starting coverage since it is not tracked' do
require @config_file.chomp('.rb')
Coverage.result.should_not include(@config_file)
@@ -98,18 +128,14 @@ describe 'Coverage.result' do
result = Coverage.result
result.should == {
- @eval_code_file => [
- 1, nil, 1, nil, 1, nil, nil, nil, nil, nil, 1
- ]
+ @eval_code_file => [
+ 1, nil, 1, nil, 1, nil, nil, nil, nil, nil, 1
+ ]
}
end
end
ruby_version_is '3.2' do
- it 'indicates support for different features' do
- Coverage.supported?(:lines).should == true
- end
-
it 'returns the correct results when eval coverage is enabled' do
Coverage.supported?(:eval).should == true
@@ -118,13 +144,13 @@ describe 'Coverage.result' do
result = Coverage.result
result.should == {
- @eval_code_file => {
- lines: [1, nil, 1, nil, 1, 1, nil, nil, nil, nil, 1]
- }
+ @eval_code_file => {
+ lines: [1, nil, 1, nil, 1, 1, nil, nil, nil, nil, 1]
+ }
}
end
- it 'returns the correct results when eval coverage is enabled' do
+ it 'returns the correct results when eval coverage is disabled' do
Coverage.supported?(:eval).should == true
Coverage.start(lines: true, eval: false)
@@ -132,10 +158,200 @@ describe 'Coverage.result' do
result = Coverage.result
result.should == {
- @eval_code_file => {
- lines: [1, nil, 1, nil, 1, nil, nil, nil, nil, nil, 1]
- }
+ @eval_code_file => {
+ lines: [1, nil, 1, nil, 1, nil, nil, nil, nil, nil, 1]
+ }
}
end
end
+
+ it "disables coverage measurement when stop option is not specified" do
+ Coverage.start
+ require @class_file.chomp('.rb')
+
+ Coverage.result
+ Coverage.running?.should == false
+ end
+
+ it "disables coverage measurement when stop: true option is specified" do
+ Coverage.start
+ require @class_file.chomp('.rb')
+
+ -> {
+ Coverage.result(stop: true)
+ }.should complain(/warning: stop implies clear/)
+
+ Coverage.running?.should == false
+ end
+
+ it "does not disable coverage measurement when stop: false option is specified" do
+ Coverage.start
+ require @class_file.chomp('.rb')
+
+ Coverage.result(stop: false)
+ Coverage.running?.should == true
+ end
+
+ it "does not disable coverage measurement when stop option is not specified but clear: true specified" do
+ Coverage.start
+ require @class_file.chomp('.rb')
+
+ Coverage.result(clear: true)
+ Coverage.running?.should == true
+ end
+
+ it "does not disable coverage measurement when stop option is not specified but clear: false specified" do
+ Coverage.start
+ require @class_file.chomp('.rb')
+
+ Coverage.result(clear: false)
+ Coverage.running?.should == true
+ end
+
+ it "disables coverage measurement when stop: true and clear: true specified" do
+ Coverage.start
+ require @class_file.chomp('.rb')
+
+ Coverage.result(stop: true, clear: true)
+ Coverage.running?.should == false
+ end
+
+ it "disables coverage measurement when stop: true and clear: false specified" do
+ Coverage.start
+ require @class_file.chomp('.rb')
+
+ -> {
+ Coverage.result(stop: true, clear: false)
+ }.should complain(/warning: stop implies clear/)
+
+ Coverage.running?.should == false
+ end
+
+ it "does not disable coverage measurement when stop: false and clear: true specified" do
+ Coverage.start
+ require @class_file.chomp('.rb')
+
+ Coverage.result(stop: false, clear: true)
+ Coverage.running?.should == true
+ end
+
+ it "does not disable coverage measurement when stop: false and clear: false specified" do
+ Coverage.start
+ require @class_file.chomp('.rb')
+
+ Coverage.result(stop: false, clear: false)
+ Coverage.running?.should == true
+ end
+
+ it "resets counters (remove them) when stop: true specified but clear option is not specified" do
+ Coverage.start
+ require @class_file.chomp('.rb')
+
+ -> {
+ Coverage.result(stop: true) # clears counters
+ }.should complain(/warning: stop implies clear/)
+
+ Coverage.start
+ Coverage.peek_result.should == {}
+ end
+
+ it "resets counters (remove them) when stop: true and clear: true specified" do
+ Coverage.start
+ require @class_file.chomp('.rb')
+
+ Coverage.result(stop: true, clear: true) # clears counters
+
+ Coverage.start
+ Coverage.peek_result.should == {}
+ end
+
+ it "resets counters (remove them) when stop: true and clear: false specified" do
+ Coverage.start
+ require @class_file.chomp('.rb')
+
+ -> {
+ Coverage.result(stop: true, clear: false) # clears counters
+ }.should complain(/warning: stop implies clear/)
+
+ Coverage.start
+ Coverage.peek_result.should == {}
+ end
+
+ it "resets counters (remove them) when both stop and clear options are not specified" do
+ Coverage.start
+ require @class_file.chomp('.rb')
+
+ Coverage.result # clears counters
+
+ Coverage.start
+ Coverage.peek_result.should == {}
+ end
+
+ it "clears counters (sets 0 values) when stop is not specified but clear: true specified" do
+ Coverage.start
+ require @class_file.chomp('.rb')
+
+ Coverage.result(clear: true) # clears counters
+
+ Coverage.peek_result.should == {
+ @class_file => [
+ nil, nil, 0, nil, nil, 0, nil, nil, 0, nil, nil, nil, nil, nil, nil, nil
+ ]
+ }
+ end
+
+ it "does not clear counters when stop is not specified but clear: false specified" do
+ Coverage.start
+ require @class_file.chomp('.rb')
+
+ result = Coverage.result(clear: false) # doesn't clear counters
+ result.should == {
+ @class_file => [
+ nil, nil, 1, nil, nil, 1, nil, nil, 0, nil, nil, nil, nil, nil, nil, nil
+ ]
+ }
+
+ Coverage.peek_result.should == result
+ end
+
+ it "does not clear counters when stop: false and clear is not specified" do
+ Coverage.start
+ require @class_file.chomp('.rb')
+
+ result = Coverage.result(stop: false) # doesn't clear counters
+ result.should == {
+ @class_file => [
+ nil, nil, 1, nil, nil, 1, nil, nil, 0, nil, nil, nil, nil, nil, nil, nil
+ ]
+ }
+
+ Coverage.peek_result.should == result
+ end
+
+ it "clears counters (sets 0 values) when stop: false and clear: true specified" do
+ Coverage.start
+ require @class_file.chomp('.rb')
+
+ Coverage.result(stop: false, clear: true) # clears counters
+
+ Coverage.peek_result.should == {
+ @class_file => [
+ nil, nil, 0, nil, nil, 0, nil, nil, 0, nil, nil, nil, nil, nil, nil, nil
+ ]
+ }
+ end
+
+ it "does not clear counters when stop: false and clear: false specified" do
+ Coverage.start
+ require @class_file.chomp('.rb')
+
+ result = Coverage.result(stop: false, clear: false) # doesn't clear counters
+ result.should == {
+ @class_file => [
+ nil, nil, 1, nil, nil, 1, nil, nil, 0, nil, nil, nil, nil, nil, nil, nil
+ ]
+ }
+
+ Coverage.peek_result.should == result
+ end
end
diff --git a/spec/ruby/library/coverage/start_spec.rb b/spec/ruby/library/coverage/start_spec.rb
index a993abbf4e..7fccf2d5cf 100644
--- a/spec/ruby/library/coverage/start_spec.rb
+++ b/spec/ruby/library/coverage/start_spec.rb
@@ -2,8 +2,87 @@ require_relative '../../spec_helper'
require 'coverage'
describe 'Coverage.start' do
+ before :each do
+ Coverage.should_not.running?
+ end
+
+ after :each do
+ Coverage.result(stop: true, clear: true) if Coverage.running?
+ end
+
+ it "enables the coverage measurement" do
+ Coverage.start
+ Coverage.should.running?
+ end
+
+ it "returns nil" do
+ Coverage.start.should == nil
+ end
+
+ ruby_version_is '3.1' do
+ it 'raises error when repeated Coverage.start call happens' do
+ Coverage.start
+
+ -> {
+ Coverage.start
+ }.should raise_error(RuntimeError, 'coverage measurement is already setup')
+ end
+ end
+
ruby_version_is '3.2' do
- it "can measure coverage within eval" do
+ it "accepts :all optional argument" do
+ Coverage.start(:all)
+ Coverage.should.running?
+ end
+
+ it "accepts lines: optional keyword argument" do
+ Coverage.start(lines: true)
+ Coverage.should.running?
+ end
+
+ it "accepts branches: optional keyword argument" do
+ Coverage.start(branches: true)
+ Coverage.should.running?
+ end
+
+ it "accepts methods: optional keyword argument" do
+ Coverage.start(methods: true)
+ Coverage.should.running?
+ end
+
+ it "accepts eval: optional keyword argument" do
+ Coverage.start(eval: true)
+ Coverage.should.running?
+ end
+
+ it "accepts oneshot_lines: optional keyword argument" do
+ Coverage.start(oneshot_lines: true)
+ Coverage.should.running?
+ end
+
+ it "ignores unknown keyword arguments" do
+ Coverage.start(foo: true)
+ Coverage.should.running?
+ end
+
+ it "expects a Hash if not passed :all" do
+ -> {
+ Coverage.start(42)
+ }.should raise_error(TypeError, "no implicit conversion of Integer into Hash")
+ end
+
+ it "does not accept both lines: and oneshot_lines: keyword arguments" do
+ -> {
+ Coverage.start(lines: true, oneshot_lines: true)
+ }.should raise_error(RuntimeError, "cannot enable lines and oneshot_lines simultaneously")
+ end
+
+ it "enables the coverage measurement if passed options with `false` value" do
+ Coverage.start(lines: false, branches: false, methods: false, eval: false, oneshot_lines: false)
+ Coverage.should.running?
+ end
+
+ it "measures coverage within eval" do
Coverage.start(lines: true, eval: true)
eval("Object.new\n"*3, binding, "test.rb", 1)
Coverage.result["test.rb"].should == {lines: [1, 1, 1]}
diff --git a/spec/ruby/library/objectspace/reachable_objects_from_spec.rb b/spec/ruby/library/objectspace/reachable_objects_from_spec.rb
index 7e70bc8569..dee5961663 100644
--- a/spec/ruby/library/objectspace/reachable_objects_from_spec.rb
+++ b/spec/ruby/library/objectspace/reachable_objects_from_spec.rb
@@ -38,7 +38,6 @@ describe "ObjectSpace.reachable_objects_from" do
end
it "finds an object stored in a Queue" do
- require 'thread'
o = Object.new
q = Queue.new
q << o
@@ -49,7 +48,6 @@ describe "ObjectSpace.reachable_objects_from" do
end
it "finds an object stored in a SizedQueue" do
- require 'thread'
o = Object.new
q = SizedQueue.new(3)
q << o
diff --git a/spec/ruby/library/socket/shared/pack_sockaddr.rb b/spec/ruby/library/socket/shared/pack_sockaddr.rb
index 9f6238e7bc..26fdf682b1 100644
--- a/spec/ruby/library/socket/shared/pack_sockaddr.rb
+++ b/spec/ruby/library/socket/shared/pack_sockaddr.rb
@@ -17,6 +17,9 @@ describe :socket_pack_sockaddr_in, shared: true do
sockaddr_in = Socket.public_send(@method, nil, '127.0.0.1')
Socket.unpack_sockaddr_in(sockaddr_in).should == [0, '127.0.0.1']
+
+ sockaddr_in = Socket.public_send(@method, 80, Socket::INADDR_ANY)
+ Socket.unpack_sockaddr_in(sockaddr_in).should == [80, '0.0.0.0']
end
platform_is_not :solaris do
diff --git a/spec/ruby/library/socket/socket/pack_sockaddr_in_spec.rb b/spec/ruby/library/socket/socket/pack_sockaddr_in_spec.rb
index 63d4724453..ef2a2d4ba9 100644
--- a/spec/ruby/library/socket/socket/pack_sockaddr_in_spec.rb
+++ b/spec/ruby/library/socket/socket/pack_sockaddr_in_spec.rb
@@ -2,6 +2,6 @@ require_relative '../spec_helper'
require_relative '../fixtures/classes'
require_relative '../shared/pack_sockaddr'
-describe "Socket#pack_sockaddr_in" do
+describe "Socket.pack_sockaddr_in" do
it_behaves_like :socket_pack_sockaddr_in, :pack_sockaddr_in
end
diff --git a/spec/ruby/library/socket/socket/pair_spec.rb b/spec/ruby/library/socket/socket/pair_spec.rb
index 292eacd38d..8dd470a95e 100644
--- a/spec/ruby/library/socket/socket/pair_spec.rb
+++ b/spec/ruby/library/socket/socket/pair_spec.rb
@@ -2,6 +2,6 @@ require_relative '../spec_helper'
require_relative '../fixtures/classes'
require_relative '../shared/socketpair'
-describe "Socket#pair" do
+describe "Socket.pair" do
it_behaves_like :socket_socketpair, :pair
end
diff --git a/spec/ruby/library/socket/socket/socketpair_spec.rb b/spec/ruby/library/socket/socket/socketpair_spec.rb
index 5b8311124e..551c376d49 100644
--- a/spec/ruby/library/socket/socket/socketpair_spec.rb
+++ b/spec/ruby/library/socket/socket/socketpair_spec.rb
@@ -2,6 +2,6 @@ require_relative '../spec_helper'
require_relative '../fixtures/classes'
require_relative '../shared/socketpair'
-describe "Socket#socketpair" do
+describe "Socket.socketpair" do
it_behaves_like :socket_socketpair, :socketpair
end
diff --git a/spec/ruby/library/socket/tcpserver/accept_spec.rb b/spec/ruby/library/socket/tcpserver/accept_spec.rb
index d38d95e0e1..8f1f0016f0 100644
--- a/spec/ruby/library/socket/tcpserver/accept_spec.rb
+++ b/spec/ruby/library/socket/tcpserver/accept_spec.rb
@@ -114,6 +114,19 @@ describe 'TCPServer#accept' do
@socket = @server.accept
@socket.should be_an_instance_of(TCPSocket)
end
+
+ platform_is_not :windows do
+ it "returns a TCPSocket which is set to nonblocking" do
+ require 'io/nonblock'
+ @socket = @server.accept
+ @socket.should.nonblock?
+ end
+ end
+
+ it "returns a TCPSocket which is set to close on exec" do
+ @socket = @server.accept
+ @socket.should.close_on_exec?
+ end
end
end
end
diff --git a/spec/ruby/library/socket/tcpsocket/initialize_spec.rb b/spec/ruby/library/socket/tcpsocket/initialize_spec.rb
index 3bec06c697..d7feb9751b 100644
--- a/spec/ruby/library/socket/tcpsocket/initialize_spec.rb
+++ b/spec/ruby/library/socket/tcpsocket/initialize_spec.rb
@@ -72,6 +72,19 @@ describe 'TCPSocket#initialize' do
@client.remote_address.ip_port.should == @server.local_address.ip_port
end
+ platform_is_not :windows do
+ it "creates a socket which is set to nonblocking" do
+ require 'io/nonblock'
+ @client = TCPSocket.new(ip_address, @port)
+ @client.should.nonblock?
+ end
+ end
+
+ it "creates a socket which is set to close on exec" do
+ @client = TCPSocket.new(ip_address, @port)
+ @client.should.close_on_exec?
+ end
+
describe 'using a local address and service' do
it 'binds the client socket to the local address and service' do
@client = TCPSocket.new(ip_address, @port, ip_address, 0)
diff --git a/spec/ruby/library/socket/udpsocket/initialize_spec.rb b/spec/ruby/library/socket/udpsocket/initialize_spec.rb
index 1d635149f7..ecf0043c10 100644
--- a/spec/ruby/library/socket/udpsocket/initialize_spec.rb
+++ b/spec/ruby/library/socket/udpsocket/initialize_spec.rb
@@ -30,6 +30,19 @@ describe 'UDPSocket#initialize' do
@socket.binmode?.should be_true
end
+ platform_is_not :windows do
+ it 'sets the socket to nonblock' do
+ require 'io/nonblock'
+ @socket = UDPSocket.new(:INET)
+ @socket.should.nonblock?
+ end
+ end
+
+ it 'sets the socket to close on exec' do
+ @socket = UDPSocket.new(:INET)
+ @socket.should.close_on_exec?
+ end
+
it 'raises Errno::EAFNOSUPPORT or Errno::EPROTONOSUPPORT when given an invalid address family' do
-> {
UDPSocket.new(666)
diff --git a/spec/ruby/library/socket/unixserver/accept_spec.rb b/spec/ruby/library/socket/unixserver/accept_spec.rb
index 624782d6b9..1305bc6220 100644
--- a/spec/ruby/library/socket/unixserver/accept_spec.rb
+++ b/spec/ruby/library/socket/unixserver/accept_spec.rb
@@ -110,6 +110,17 @@ with_feature :unix_socket do
@socket = @server.accept
@socket.recv(5).should == 'hello'
end
+
+ it "is set to nonblocking" do
+ require 'io/nonblock'
+ @socket = @server.accept
+ @socket.should.nonblock?
+ end
+
+ it "is set to close on exec" do
+ @socket = @server.accept
+ @socket.should.close_on_exec?
+ end
end
end
end
diff --git a/spec/ruby/library/socket/unixserver/for_fd_spec.rb b/spec/ruby/library/socket/unixserver/for_fd_spec.rb
index e00c4d9526..8cc55ef391 100644
--- a/spec/ruby/library/socket/unixserver/for_fd_spec.rb
+++ b/spec/ruby/library/socket/unixserver/for_fd_spec.rb
@@ -2,7 +2,7 @@ require_relative '../spec_helper'
require_relative '../fixtures/classes'
with_feature :unix_socket do
- describe "UNIXServer#for_fd" do
+ describe "UNIXServer.for_fd" do
before :each do
@unix_path = SocketSpecs.socket_path
@unix = UNIXServer.new(@unix_path)
diff --git a/spec/ruby/library/socket/unixsocket/initialize_spec.rb b/spec/ruby/library/socket/unixsocket/initialize_spec.rb
index 13b6972f03..bf7896ab0e 100644
--- a/spec/ruby/library/socket/unixsocket/initialize_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/initialize_spec.rb
@@ -33,6 +33,16 @@ with_feature :unix_socket do
it 'sets the socket to binmode' do
@socket.binmode?.should be_true
end
+
+ it 'sets the socket to nonblock' do
+ require 'io/nonblock'
+ @socket.should.nonblock?
+ end
+
+ it 'sets the socket to close on exec' do
+ @socket.should.close_on_exec?
+ end
+
end
end
end
diff --git a/spec/ruby/library/socket/unixsocket/pair_spec.rb b/spec/ruby/library/socket/unixsocket/pair_spec.rb
index 9a66c56c10..d80b60894d 100644
--- a/spec/ruby/library/socket/unixsocket/pair_spec.rb
+++ b/spec/ruby/library/socket/unixsocket/pair_spec.rb
@@ -3,7 +3,7 @@ require_relative '../fixtures/classes'
require_relative '../shared/partially_closable_sockets'
with_feature :unix_socket do
- describe "UNIXSocket#pair" do
+ describe "UNIXSocket.pair" do
it_should_behave_like :partially_closable_sockets
before :each do
diff --git a/spec/ruby/library/yaml/fixtures/strings.rb b/spec/ruby/library/yaml/fixtures/strings.rb
index 6f66dc3659..f478f89823 100644
--- a/spec/ruby/library/yaml/fixtures/strings.rb
+++ b/spec/ruby/library/yaml/fixtures/strings.rb
@@ -1,36 +1,26 @@
-$complex_key_1 = <<EOY
- ? # PLAY SCHEDULE
- - Detroit Tigers
- - Chicago Cubs
- :
- - 2001-07-23
+module YAMLSpecs
+ COMPLEX_KEY_1 = <<~EOY
+ ? # PLAY SCHEDULE
+ - Detroit Tigers
+ - Chicago Cubs
+ :
+ - 2001-07-23
- ? [ New York Yankees,
- Atlanta Braves ]
- : [ 2001-07-02, 2001-08-12,
- 2001-08-14 ]
-EOY
+ ? [ New York Yankees,
+ Atlanta Braves ]
+ : [ 2001-07-02, 2001-08-12,
+ 2001-08-14 ]
+ EOY
-$to_yaml_hash =
-<<EOY
--
- avg: 0.278
- hr: 65
- name: Mark McGwire
--
- avg: 0.288
- hr: 63
- name: Sammy Sosa
-EOY
+ MULTIDOCUMENT = <<~EOY
+ ---
+ - Mark McGwire
+ - Sammy Sosa
+ - Ken Griffey
-$multidocument = <<EOY
----
-- Mark McGwire
-- Sammy Sosa
-- Ken Griffey
-
-# Team ranking
----
-- Chicago Cubs
-- St Louis Cardinals
-EOY
+ # Team ranking
+ ---
+ - Chicago Cubs
+ - St Louis Cardinals
+ EOY
+end
diff --git a/spec/ruby/library/yaml/shared/each_document.rb b/spec/ruby/library/yaml/shared/each_document.rb
index 7d32c6001f..6f00aee297 100644
--- a/spec/ruby/library/yaml/shared/each_document.rb
+++ b/spec/ruby/library/yaml/shared/each_document.rb
@@ -1,7 +1,7 @@
describe :yaml_each_document, shared: true do
it "calls the block on each successive document" do
documents = []
- YAML.send(@method, $multidocument) do |doc|
+ YAML.send(@method, YAMLSpecs::MULTIDOCUMENT) do |doc|
documents << doc
end
documents.should == [["Mark McGwire", "Sammy Sosa", "Ken Griffey"],
diff --git a/spec/ruby/library/yaml/shared/load.rb b/spec/ruby/library/yaml/shared/load.rb
index 1ebe08be2c..bd55332fe5 100644
--- a/spec/ruby/library/yaml/shared/load.rb
+++ b/spec/ruby/library/yaml/shared/load.rb
@@ -106,7 +106,7 @@ describe :yaml_load_unsafe, shared: true do
Date.new( 2001, 8, 12 ),
Date.new( 2001, 8, 14 ) ]
}
- YAML.send(@method, $complex_key_1).should == expected
+ YAML.send(@method, YAMLSpecs::COMPLEX_KEY_1).should == expected
end
describe "with iso8601 timestamp" do
diff --git a/spec/ruby/optional/capi/debug_spec.rb b/spec/ruby/optional/capi/debug_spec.rb
index c8c91417d1..148b8c38fb 100644
--- a/spec/ruby/optional/capi/debug_spec.rb
+++ b/spec/ruby/optional/capi/debug_spec.rb
@@ -17,6 +17,7 @@ describe "C-API Debug function" do
describe "rb_debug_inspector_frame_self_get" do
it "returns self" do
@o.rb_debug_inspector_frame_self_get(0).should == @o
+ @o.rb_debug_inspector_frame_self_get(1).should == self
end
end
@@ -35,10 +36,14 @@ describe "C-API Debug function" do
end
it "matches the locations in rb_debug_inspector_backtrace_locations" do
- frames = @o.rb_debug_inspector_open(42);
+ frames = @o.rb_debug_inspector_open(42)
frames.each do |_s, _klass, binding, _iseq, backtrace_location|
if binding
- "#{backtrace_location.path}:#{backtrace_location.lineno}".should == "#{binding.source_location[0]}:#{binding.source_location[1]}"
+ binding.source_location.should == [backtrace_location.path, backtrace_location.lineno]
+ method_name = binding.eval('__method__')
+ if method_name
+ method_name.should == backtrace_location.base_label.to_sym
+ end
end
end
end
diff --git a/spec/ruby/optional/capi/ext/io_spec.c b/spec/ruby/optional/capi/ext/io_spec.c
index ab3aef4c92..bcd3940e34 100644
--- a/spec/ruby/optional/capi/ext/io_spec.c
+++ b/spec/ruby/optional/capi/ext/io_spec.c
@@ -339,6 +339,16 @@ VALUE io_spec_mode_sync_flag(VALUE self, VALUE io) {
}
}
+#if defined(RUBY_VERSION_IS_3_3) || defined(TRUFFLERUBY)
+static VALUE io_spec_rb_io_mode(VALUE self, VALUE io) {
+ return INT2FIX(rb_io_mode(io));
+}
+
+static VALUE io_spec_rb_io_path(VALUE self, VALUE io) {
+ return rb_io_path(io);
+}
+#endif
+
void Init_io_spec(void) {
VALUE cls = rb_define_class("CApiIOSpecs", rb_cObject);
rb_define_method(cls, "GetOpenFile_fd", io_spec_GetOpenFile_fd, 1);
@@ -372,6 +382,10 @@ void Init_io_spec(void) {
rb_define_method(cls, "rb_cloexec_open", io_spec_rb_cloexec_open, 3);
rb_define_method(cls, "errno=", io_spec_errno_set, 1);
rb_define_method(cls, "rb_io_mode_sync_flag", io_spec_mode_sync_flag, 1);
+#if defined(RUBY_VERSION_IS_3_3) || defined(TRUFFLERUBY)
+ rb_define_method(cls, "rb_io_mode", io_spec_rb_io_mode, 1);
+ rb_define_method(cls, "rb_io_path", io_spec_rb_io_path, 1);
+#endif
}
#ifdef __cplusplus
diff --git a/spec/ruby/optional/capi/ext/kernel_spec.c b/spec/ruby/optional/capi/ext/kernel_spec.c
index a921eb13e0..1761599081 100644
--- a/spec/ruby/optional/capi/ext/kernel_spec.c
+++ b/spec/ruby/optional/capi/ext/kernel_spec.c
@@ -355,6 +355,15 @@ static VALUE kernel_spec_rb_funcall_many_args(VALUE self, VALUE obj, VALUE metho
INT2FIX(5), INT2FIX(4), INT2FIX(3), INT2FIX(2), INT2FIX(1));
}
+static VALUE kernel_spec_rb_check_funcall(VALUE self, VALUE receiver, VALUE method, VALUE args) {
+ VALUE ret = rb_check_funcall(receiver, SYM2ID(method), RARRAY_LENINT(args), RARRAY_PTR(args));
+ if (ret == Qundef) {
+ return ID2SYM(rb_intern("Qundef"));
+ } else {
+ return ret;
+ }
+}
+
void Init_kernel_spec(void) {
VALUE cls = rb_define_class("CApiKernelSpecs", rb_cObject);
rb_define_method(cls, "rb_block_given_p", kernel_spec_rb_block_given_p, 0);
@@ -403,6 +412,7 @@ void Init_kernel_spec(void) {
rb_define_method(cls, "rb_funcall_many_args", kernel_spec_rb_funcall_many_args, 2);
rb_define_method(cls, "rb_funcall_with_block", kernel_spec_rb_funcall_with_block, 4);
rb_define_method(cls, "rb_funcall_with_block_kw", kernel_spec_rb_funcall_with_block_kw, 4);
+ rb_define_method(cls, "rb_check_funcall", kernel_spec_rb_check_funcall, 3);
}
#ifdef __cplusplus
diff --git a/spec/ruby/optional/capi/ext/thread_spec.c b/spec/ruby/optional/capi/ext/thread_spec.c
index 7d08d45098..3511c2fbcf 100644
--- a/spec/ruby/optional/capi/ext/thread_spec.c
+++ b/spec/ruby/optional/capi/ext/thread_spec.c
@@ -67,7 +67,7 @@ static VALUE thread_spec_rb_thread_call_without_gvl(VALUE self) {
}
/* This is unblocked by a signal. */
-static void* blocking_gvl_func_for_udf_io(void *data) {
+static void* blocking_gvl_func_for_ubf_io(void *data) {
int rfd = (int)(size_t)data;
char dummy;
@@ -87,7 +87,7 @@ static VALUE thread_spec_rb_thread_call_without_gvl_with_ubf_io(VALUE self) {
rb_raise(rb_eRuntimeError, "could not create pipe");
}
- ret = rb_thread_call_without_gvl(blocking_gvl_func_for_udf_io,
+ ret = rb_thread_call_without_gvl(blocking_gvl_func_for_ubf_io,
(void*)(size_t)fds[0], RUBY_UBF_IO, 0);
close(fds[0]);
close(fds[1]);
diff --git a/spec/ruby/optional/capi/fixtures/kernel.rb b/spec/ruby/optional/capi/fixtures/kernel.rb
index f5b95e0fea..d3fc7c57e8 100644
--- a/spec/ruby/optional/capi/fixtures/kernel.rb
+++ b/spec/ruby/optional/capi/fixtures/kernel.rb
@@ -1,19 +1,19 @@
class CApiKernelSpecs
class ClassWithPublicMethod
def public_method(*, **)
- 0
+ :public
end
end
class ClassWithPrivateMethod
private def private_method(*, **)
- 0
+ :private
end
end
class ClassWithProtectedMethod
protected def protected_method(*, **)
- 0
+ :protected
end
end
end
diff --git a/spec/ruby/optional/capi/integer_spec.rb b/spec/ruby/optional/capi/integer_spec.rb
index e26735824e..089872381c 100644
--- a/spec/ruby/optional/capi/integer_spec.rb
+++ b/spec/ruby/optional/capi/integer_spec.rb
@@ -140,6 +140,23 @@ describe "CApiIntegerSpecs" do
result.should == -1
@words.should == "\x11\x32\x54\x76\x98\xBA\xDC\xFE"
end
+
+ it "converts numbers near the fixnum limit successfully" do
+ result = @s.rb_integer_pack(0x7123_4567_89ab_cdef, @words, 1, 8, 0,
+ CApiIntegerSpecs::NATIVE|CApiIntegerSpecs::PACK_2COMP)
+ result.should == 1
+ @words.should == "\xEF\xCD\xAB\x89\x67\x45\x23\x71"
+
+ result = @s.rb_integer_pack(2**62-1, @words, 1, 8, 0,
+ CApiIntegerSpecs::NATIVE|CApiIntegerSpecs::PACK_2COMP)
+ result.should == 1
+ @words.should == "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x3F"
+
+ result = @s.rb_integer_pack(2**63-1, @words, 1, 8, 0,
+ CApiIntegerSpecs::NATIVE|CApiIntegerSpecs::PACK_2COMP)
+ result.should == 1
+ @words.should == "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\x7F"
+ end
end
end
end
diff --git a/spec/ruby/optional/capi/io_spec.rb b/spec/ruby/optional/capi/io_spec.rb
index e5fb86a837..870abef3ea 100644
--- a/spec/ruby/optional/capi/io_spec.rb
+++ b/spec/ruby/optional/capi/io_spec.rb
@@ -440,10 +440,27 @@ describe "C-API IO function" do
end
end
end
+
+ ruby_version_is "3.3" do
+ describe "rb_io_mode" do
+ it "returns the mode" do
+ (@o.rb_io_mode(@r_io) & 0b11).should == 0b01
+ (@o.rb_io_mode(@w_io) & 0b11).should == 0b10
+ (@o.rb_io_mode(@rw_io) & 0b11).should == 0b11
+ end
+ end
+
+ describe "rb_io_path" do
+ it "returns the IO#path" do
+ @o.rb_io_path(@r_io).should == @r_io.path
+ @o.rb_io_path(@rw_io).should == @rw_io.path
+ @o.rb_io_path(@rw_io).should == @name
+ end
+ end
+ end
end
describe "rb_fd_fix_cloexec" do
-
before :each do
@o = CApiIOSpecs.new
diff --git a/spec/ruby/optional/capi/kernel_spec.rb b/spec/ruby/optional/capi/kernel_spec.rb
index 17c49b2155..3b61d4f0f1 100644
--- a/spec/ruby/optional/capi/kernel_spec.rb
+++ b/spec/ruby/optional/capi/kernel_spec.rb
@@ -606,12 +606,12 @@ describe "C-API Kernel function" do
it "calls a private method" do
object = CApiKernelSpecs::ClassWithPrivateMethod.new
- @s.rb_funcallv(object, :private_method, []).should == 0
+ @s.rb_funcallv(object, :private_method, []).should == :private
end
it "calls a protected method" do
object = CApiKernelSpecs::ClassWithProtectedMethod.new
- @s.rb_funcallv(object, :protected_method, []).should == 0
+ @s.rb_funcallv(object, :protected_method, []).should == :protected
end
end
@@ -629,12 +629,12 @@ describe "C-API Kernel function" do
it "calls a private method" do
object = CApiKernelSpecs::ClassWithPrivateMethod.new
- @s.rb_funcallv_kw(object, :private_method, [{}]).should == 0
+ @s.rb_funcallv_kw(object, :private_method, [{}]).should == :private
end
it "calls a protected method" do
object = CApiKernelSpecs::ClassWithProtectedMethod.new
- @s.rb_funcallv_kw(object, :protected_method, [{}]).should == 0
+ @s.rb_funcallv_kw(object, :protected_method, [{}]).should == :protected
end
it "raises TypeError if the last argument is not a Hash" do
@@ -752,4 +752,39 @@ describe "C-API Kernel function" do
}.should raise_error(NoMethodError, /protected/)
end
end
+
+ describe "rb_check_funcall" do
+ it "calls a method" do
+ @s.rb_check_funcall(1, :+, [2]).should == 3
+ end
+
+ it "returns Qundef if the method is not defined" do
+ obj = Object.new
+ @s.rb_check_funcall(obj, :foo, []).should == :Qundef
+ end
+
+ it "uses #respond_to? to check if the method is defined" do
+ ScratchPad.record []
+ obj = Object.new
+ def obj.respond_to?(name, priv)
+ ScratchPad << name
+ name == :foo || super
+ end
+ def obj.method_missing(name, *args)
+ name == :foo ? [name, 42] : super
+ end
+ @s.rb_check_funcall(obj, :foo, []).should == [:foo, 42]
+ ScratchPad.recorded.should == [:foo]
+ end
+
+ it "calls a private method" do
+ object = CApiKernelSpecs::ClassWithPrivateMethod.new
+ @s.rb_check_funcall(object, :private_method, []).should == :private
+ end
+
+ it "calls a protected method" do
+ object = CApiKernelSpecs::ClassWithProtectedMethod.new
+ @s.rb_check_funcall(object, :protected_method, []).should == :protected
+ end
+ end
end
diff --git a/spec/ruby/shared/kernel/at_exit.rb b/spec/ruby/shared/kernel/at_exit.rb
index 26ad361a5b..16d41cb01c 100644
--- a/spec/ruby/shared/kernel/at_exit.rb
+++ b/spec/ruby/shared/kernel/at_exit.rb
@@ -54,7 +54,10 @@ describe :kernel_at_exit, shared: true do
result = ruby_exe('{', options: "-r#{script}", args: "2>&1", exit_status: 1)
$?.should_not.success?
result.should.include?("handler ran\n")
- result.should.include?("syntax error")
+
+ # it's tempting not to rely on error message and rely only on exception class name,
+ # but CRuby before 3.2 doesn't print class name for syntax error
+ result.should include_any_of("syntax error", "SyntaxError")
end
it "calls the nested handler right after the outer one if a handler is nested into another handler" do
diff --git a/spec/ruby/shared/queue/deque.rb b/spec/ruby/shared/queue/deque.rb
index 9e6b45009d..0abba5301e 100644
--- a/spec/ruby/shared/queue/deque.rb
+++ b/spec/ruby/shared/queue/deque.rb
@@ -70,7 +70,7 @@ describe :queue_deq, shared: true do
q = @object.call
t = Thread.new {
- q.send(@method, timeout: 1).should == 1
+ q.send(@method, timeout: TIME_TOLERANCE).should == 1
}
Thread.pass until t.status == "sleep" && q.num_waiting == 1
q << 1
@@ -80,10 +80,9 @@ describe :queue_deq, shared: true do
it "returns nil if no item is available in time" do
q = @object.call
- t = Thread.new {
- q.send(@method, timeout: 0.1).should == nil
- }
- t.join
+ Thread.new {
+ q.send(@method, timeout: 0.001).should == nil
+ }.join
end
it "does nothing if the timeout is nil" do
@@ -91,7 +90,7 @@ describe :queue_deq, shared: true do
t = Thread.new {
q.send(@method, timeout: nil).should == 1
}
- t.join(0.2).should == nil
+ Thread.pass until t.status == "sleep" && q.num_waiting == 1
q << 1
t.join
end
@@ -105,23 +104,20 @@ describe :queue_deq, shared: true do
it "raise TypeError if timeout is not a valid numeric" do
q = @object.call
- -> { q.send(@method, timeout: "1") }.should raise_error(
- TypeError,
- "no implicit conversion to float from string",
- )
-
- -> { q.send(@method, timeout: false) }.should raise_error(
- TypeError,
- "no implicit conversion to float from false",
- )
+ -> {
+ q.send(@method, timeout: "1")
+ }.should raise_error(TypeError, "no implicit conversion to float from string")
+
+ -> {
+ q.send(@method, timeout: false)
+ }.should raise_error(TypeError, "no implicit conversion to float from false")
end
it "raise ArgumentError if non_block = true is passed too" do
q = @object.call
- -> { q.send(@method, true, timeout: 1) }.should raise_error(
- ArgumentError,
- "can't set a timeout if non_block is enabled",
- )
+ -> {
+ q.send(@method, true, timeout: 1)
+ }.should raise_error(ArgumentError, "can't set a timeout if non_block is enabled")
end
it "returns nil for a closed empty queue" do
diff --git a/spec/ruby/shared/rational/coerce.rb b/spec/ruby/shared/rational/coerce.rb
index 1650668fe6..38925721ed 100644
--- a/spec/ruby/shared/rational/coerce.rb
+++ b/spec/ruby/shared/rational/coerce.rb
@@ -1,33 +1,31 @@
require_relative '../../spec_helper'
-ruby_version_is ""..."3.4" do
-
- require 'bigdecimal'
-
- describe :rational_coerce, shared: true do
- it "returns the passed argument, self as Float, when given a Float" do
- result = Rational(3, 4).coerce(1.0)
- result.should == [1.0, 0.75]
- result.first.is_a?(Float).should be_true
- result.last.is_a?(Float).should be_true
- end
+describe :rational_coerce, shared: true do
+ it "returns the passed argument, self as Float, when given a Float" do
+ result = Rational(3, 4).coerce(1.0)
+ result.should == [1.0, 0.75]
+ result.first.is_a?(Float).should be_true
+ result.last.is_a?(Float).should be_true
+ end
- it "returns the passed argument, self as Rational, when given an Integer" do
- result = Rational(3, 4).coerce(10)
- result.should == [Rational(10, 1), Rational(3, 4)]
- result.first.is_a?(Rational).should be_true
- result.last.is_a?(Rational).should be_true
- end
+ it "returns the passed argument, self as Rational, when given an Integer" do
+ result = Rational(3, 4).coerce(10)
+ result.should == [Rational(10, 1), Rational(3, 4)]
+ result.first.is_a?(Rational).should be_true
+ result.last.is_a?(Rational).should be_true
+ end
- it "coerces to Rational, when given a Complex" do
- Rational(3, 4).coerce(Complex(5)).should == [Rational(5, 1), Rational(3, 4)]
- Rational(12, 4).coerce(Complex(5, 1)).should == [Complex(5, 1), Complex(3)]
- end
+ it "coerces to Rational, when given a Complex" do
+ Rational(3, 4).coerce(Complex(5)).should == [Rational(5, 1), Rational(3, 4)]
+ Rational(12, 4).coerce(Complex(5, 1)).should == [Complex(5, 1), Complex(3)]
+ end
- it "returns [argument, self] when given a Rational" do
- Rational(3, 7).coerce(Rational(9, 2)).should == [Rational(9, 2), Rational(3, 7)]
- end
+ it "returns [argument, self] when given a Rational" do
+ Rational(3, 7).coerce(Rational(9, 2)).should == [Rational(9, 2), Rational(3, 7)]
+ end
+ ruby_version_is ""..."3.4" do
+ require 'bigdecimal'
it "raises an error when passed a BigDecimal" do
-> {
Rational(500, 3).coerce(BigDecimal('166.666666666'))
diff --git a/spec/ruby/shared/sizedqueue/enque.rb b/spec/ruby/shared/sizedqueue/enque.rb
index 6307f3c3ca..2f25517675 100644
--- a/spec/ruby/shared/sizedqueue/enque.rb
+++ b/spec/ruby/shared/sizedqueue/enque.rb
@@ -55,7 +55,7 @@ describe :sizedqueue_enq, shared: true do
q << 1
t = Thread.new {
- q.send(@method, 2, timeout: 1).should == q
+ q.send(@method, 2, timeout: TIME_TOLERANCE).should == q
}
Thread.pass until t.status == "sleep" && q.num_waiting == 1
q.pop
@@ -82,31 +82,27 @@ describe :sizedqueue_enq, shared: true do
it "returns nil if no space is available in time" do
q = @object.call(1)
q << 1
- t = Thread.new {
- q.send(@method, 2, timeout: 0.1).should == nil
- }
- t.join
+ Thread.new {
+ q.send(@method, 2, timeout: 0.001).should == nil
+ }.join
end
it "raise TypeError if timeout is not a valid numeric" do
q = @object.call(1)
- -> { q.send(@method, 2, timeout: "1") }.should raise_error(
- TypeError,
- "no implicit conversion to float from string",
- )
-
- -> { q.send(@method, 2, timeout: false) }.should raise_error(
- TypeError,
- "no implicit conversion to float from false",
- )
+ -> {
+ q.send(@method, 2, timeout: "1")
+ }.should raise_error(TypeError, "no implicit conversion to float from string")
+
+ -> {
+ q.send(@method, 2, timeout: false)
+ }.should raise_error(TypeError, "no implicit conversion to float from false")
end
it "raise ArgumentError if non_block = true is passed too" do
q = @object.call(1)
- -> { q.send(@method, 2, true, timeout: 1) }.should raise_error(
- ArgumentError,
- "can't set a timeout if non_block is enabled",
- )
+ -> {
+ q.send(@method, 2, true, timeout: 1)
+ }.should raise_error(ArgumentError, "can't set a timeout if non_block is enabled")
end
it "raise ClosedQueueError when closed before enqueued" do
@@ -120,7 +116,7 @@ describe :sizedqueue_enq, shared: true do
q << 1
t = Thread.new {
- -> { q.send(@method, 1, timeout: 10) }.should raise_error(ClosedQueueError, "queue closed")
+ -> { q.send(@method, 1, timeout: TIME_TOLERANCE) }.should raise_error(ClosedQueueError, "queue closed")
}
Thread.pass until q.num_waiting == 1