summaryrefslogtreecommitdiff
path: root/spec/ruby/core
diff options
context:
space:
mode:
authorBenoit Daloze <[email protected]>2023-04-25 17:04:25 +0200
committerBenoit Daloze <[email protected]>2023-04-25 17:09:53 +0200
commitd562663e4098801c1d7fa7c64a335ea71231a598 (patch)
tree5b2ab2c9fbb86b4223263485fc5a3224562ae78d /spec/ruby/core
parentd3da01cd110ca99dd0249ee9af92e12cf845998c (diff)
Update to ruby/spec@7f69c86
Diffstat (limited to 'spec/ruby/core')
-rw-r--r--spec/ruby/core/array/fixtures/classes.rb10
-rw-r--r--spec/ruby/core/array/pack/c_spec.rb4
-rw-r--r--spec/ruby/core/array/pack/shared/float.rb16
-rw-r--r--spec/ruby/core/array/pack/shared/integer.rb36
-rw-r--r--spec/ruby/core/array/pack/shared/unicode.rb4
-rw-r--r--spec/ruby/core/array/pack/w_spec.rb4
-rw-r--r--spec/ruby/core/array/plus_spec.rb21
-rw-r--r--spec/ruby/core/array/product_spec.rb5
-rw-r--r--spec/ruby/core/array/sample_spec.rb4
-rw-r--r--spec/ruby/core/array/shuffle_spec.rb14
-rw-r--r--spec/ruby/core/array/try_convert_spec.rb2
-rw-r--r--spec/ruby/core/complex/inspect_spec.rb19
-rw-r--r--spec/ruby/core/complex/to_s_spec.rb10
-rw-r--r--spec/ruby/core/data/define_spec.rb22
-rw-r--r--spec/ruby/core/dir/fchdir_spec.rb12
-rw-r--r--spec/ruby/core/dir/home_spec.rb6
-rw-r--r--spec/ruby/core/enumerable/shared/inject.rb9
-rw-r--r--spec/ruby/core/enumerable/tally_spec.rb13
-rw-r--r--spec/ruby/core/fiber/inspect_spec.rb38
-rw-r--r--spec/ruby/core/file/dirname_spec.rb39
-rw-r--r--spec/ruby/core/hash/try_convert_spec.rb2
-rw-r--r--spec/ruby/core/integer/bit_and_spec.rb2
-rw-r--r--spec/ruby/core/integer/bit_or_spec.rb6
-rw-r--r--spec/ruby/core/integer/bit_xor_spec.rb4
-rw-r--r--spec/ruby/core/integer/ceildiv_spec.rb22
-rw-r--r--spec/ruby/core/integer/try_convert_spec.rb12
-rw-r--r--spec/ruby/core/io/gets_spec.rb29
-rw-r--r--spec/ruby/core/io/shared/write.rb55
-rw-r--r--spec/ruby/core/io/syswrite_spec.rb1
-rw-r--r--spec/ruby/core/io/try_convert_spec.rb2
-rw-r--r--spec/ruby/core/io/write_nonblock_spec.rb1
-rw-r--r--spec/ruby/core/io/write_spec.rb1
-rw-r--r--spec/ruby/core/kernel/Complex_spec.rb4
-rw-r--r--spec/ruby/core/kernel/define_singleton_method_spec.rb6
-rw-r--r--spec/ruby/core/kernel/method_spec.rb21
-rw-r--r--spec/ruby/core/kernel/require_spec.rb16
-rw-r--r--spec/ruby/core/kernel/shared/require.rb14
-rw-r--r--spec/ruby/core/marshal/dump_spec.rb200
-rw-r--r--spec/ruby/core/marshal/fixtures/marshal_data.rb96
-rw-r--r--spec/ruby/core/marshal/shared/load.rb201
-rw-r--r--spec/ruby/core/matchdata/element_reference_spec.rb5
-rw-r--r--spec/ruby/core/math/cos_spec.rb26
-rw-r--r--spec/ruby/core/method/parameters_spec.rb16
-rw-r--r--spec/ruby/core/module/alias_method_spec.rb6
-rw-r--r--spec/ruby/core/module/const_defined_spec.rb21
-rw-r--r--spec/ruby/core/module/refine_spec.rb2
-rw-r--r--spec/ruby/core/proc/parameters_spec.rb26
-rw-r--r--spec/ruby/core/process/argv0_spec.rb23
-rw-r--r--spec/ruby/core/process/fixtures/argv0.rb6
-rw-r--r--spec/ruby/core/queue/initialize_spec.rb33
-rw-r--r--spec/ruby/core/range/size_spec.rb4
-rw-r--r--spec/ruby/core/refinement/fixtures/classes.rb10
-rw-r--r--spec/ruby/core/refinement/import_methods_spec.rb235
-rw-r--r--spec/ruby/core/regexp/shared/new.rb4
-rw-r--r--spec/ruby/core/regexp/try_convert_spec.rb6
-rw-r--r--spec/ruby/core/string/append_spec.rb1
-rw-r--r--spec/ruby/core/string/concat_spec.rb1
-rw-r--r--spec/ruby/core/string/plus_spec.rb5
-rw-r--r--spec/ruby/core/string/shared/concat.rb32
-rw-r--r--spec/ruby/core/string/try_convert_spec.rb2
-rw-r--r--spec/ruby/core/string/unpack/b_spec.rb8
-rw-r--r--spec/ruby/core/string/unpack/c_spec.rb4
-rw-r--r--spec/ruby/core/string/unpack/h_spec.rb8
-rw-r--r--spec/ruby/core/string/unpack/shared/float.rb20
-rw-r--r--spec/ruby/core/string/unpack/shared/integer.rb28
-rw-r--r--spec/ruby/core/string/unpack/shared/unicode.rb4
-rw-r--r--spec/ruby/core/string/unpack/w_spec.rb4
-rw-r--r--spec/ruby/core/struct/fixtures/classes.rb6
-rw-r--r--spec/ruby/core/struct/keyword_init_spec.rb19
-rw-r--r--spec/ruby/core/struct/new_spec.rb5
-rw-r--r--spec/ruby/core/struct/shared/inspect.rb12
-rw-r--r--spec/ruby/core/symbol/inspect_spec.rb2
-rw-r--r--spec/ruby/core/time/new_spec.rb22
-rw-r--r--spec/ruby/core/time/now_spec.rb66
-rw-r--r--spec/ruby/core/time/utc_spec.rb10
-rw-r--r--spec/ruby/core/time/zone_spec.rb11
-rw-r--r--spec/ruby/core/warning/warn_spec.rb60
77 files changed, 1557 insertions, 179 deletions
diff --git a/spec/ruby/core/array/fixtures/classes.rb b/spec/ruby/core/array/fixtures/classes.rb
index aa5fecd96b..8596245fb8 100644
--- a/spec/ruby/core/array/fixtures/classes.rb
+++ b/spec/ruby/core/array/fixtures/classes.rb
@@ -160,6 +160,16 @@ module ArraySpecs
end
end
+ class ArrayMethodMissing
+ def initialize(*values, &block)
+ @values = values;
+ end
+
+ def method_missing(name, *args)
+ @values
+ end
+ end
+
class SortSame
def <=>(other); 0; end
def ==(other); true; end
diff --git a/spec/ruby/core/array/pack/c_spec.rb b/spec/ruby/core/array/pack/c_spec.rb
index be03551629..ac133ff9b6 100644
--- a/spec/ruby/core/array/pack/c_spec.rb
+++ b/spec/ruby/core/array/pack/c_spec.rb
@@ -47,7 +47,9 @@ describe :array_pack_8bit, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- [1, 2, 3].pack(pack_format("\000", 2)).should == "\x01\x02"
+ suppress_warning do
+ [1, 2, 3].pack(pack_format("\000", 2)).should == "\x01\x02"
+ end
end
end
diff --git a/spec/ruby/core/array/pack/shared/float.rb b/spec/ruby/core/array/pack/shared/float.rb
index 9510cffed7..1780d7635e 100644
--- a/spec/ruby/core/array/pack/shared/float.rb
+++ b/spec/ruby/core/array/pack/shared/float.rb
@@ -27,7 +27,9 @@ describe :array_pack_float_le, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- [5.3, 9.2].pack(pack_format("\000", 2)).should == "\x9a\x99\xa9@33\x13A"
+ suppress_warning do
+ [5.3, 9.2].pack(pack_format("\000", 2)).should == "\x9a\x99\xa9@33\x13A"
+ end
end
end
@@ -105,7 +107,9 @@ describe :array_pack_float_be, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- [5.3, 9.2].pack(pack_format("\000", 2)).should == "@\xa9\x99\x9aA\x1333"
+ suppress_warning do
+ [5.3, 9.2].pack(pack_format("\000", 2)).should == "@\xa9\x99\x9aA\x1333"
+ end
end
end
@@ -175,7 +179,9 @@ describe :array_pack_double_le, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- [5.3, 9.2].pack(pack_format("\000", 2)).should == "333333\x15@ffffff\x22@"
+ suppress_warning do
+ [5.3, 9.2].pack(pack_format("\000", 2)).should == "333333\x15@ffffff\x22@"
+ end
end
end
@@ -244,7 +250,9 @@ describe :array_pack_double_be, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- [5.3, 9.2].pack(pack_format("\000", 2)).should == "@\x15333333@\x22ffffff"
+ suppress_warning do
+ [5.3, 9.2].pack(pack_format("\000", 2)).should == "@\x15333333@\x22ffffff"
+ end
end
end
diff --git a/spec/ruby/core/array/pack/shared/integer.rb b/spec/ruby/core/array/pack/shared/integer.rb
index d3ce9b5792..fd21b25b19 100644
--- a/spec/ruby/core/array/pack/shared/integer.rb
+++ b/spec/ruby/core/array/pack/shared/integer.rb
@@ -43,8 +43,10 @@ describe :array_pack_16bit_le, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
- str.should == "\x78\x65\xcd\xab"
+ suppress_warning do
+ str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
+ str.should == "\x78\x65\xcd\xab"
+ end
end
end
@@ -105,8 +107,10 @@ describe :array_pack_16bit_be, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
- str.should == "\x65\x78\xab\xcd"
+ suppress_warning do
+ str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
+ str.should == "\x65\x78\xab\xcd"
+ end
end
end
@@ -167,8 +171,10 @@ describe :array_pack_32bit_le, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
- str.should == "\x78\x65\x43\x12\xcd\xab\xf0\xde"
+ suppress_warning do
+ str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
+ str.should == "\x78\x65\x43\x12\xcd\xab\xf0\xde"
+ end
end
end
@@ -229,8 +235,10 @@ describe :array_pack_32bit_be, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
- str.should == "\x12\x43\x65\x78\xde\xf0\xab\xcd"
+ suppress_warning do
+ str = [0x1243_6578, 0xdef0_abcd].pack(pack_format("\000", 2))
+ str.should == "\x12\x43\x65\x78\xde\xf0\xab\xcd"
+ end
end
end
@@ -351,8 +359,10 @@ describe :array_pack_64bit_le, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- str = [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2))
- str.should == "\x56\x78\x12\x34\xcd\xab\xf0\xde\xf0\xde\xba\xdc\x21\x43\x65\x78"
+ suppress_warning do
+ str = [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2))
+ str.should == "\x56\x78\x12\x34\xcd\xab\xf0\xde\xf0\xde\xba\xdc\x21\x43\x65\x78"
+ end
end
end
@@ -421,8 +431,10 @@ describe :array_pack_64bit_be, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- str = [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2))
- str.should == "\xde\xf0\xab\xcd\x34\x12\x78\x56\x78\x65\x43\x21\xdc\xba\xde\xf0"
+ suppress_warning do
+ str = [0xdef0_abcd_3412_7856, 0x7865_4321_dcba_def0].pack(pack_format("\000", 2))
+ str.should == "\xde\xf0\xab\xcd\x34\x12\x78\x56\x78\x65\x43\x21\xdc\xba\xde\xf0"
+ end
end
end
diff --git a/spec/ruby/core/array/pack/shared/unicode.rb b/spec/ruby/core/array/pack/shared/unicode.rb
index 130c447bb7..4d8eaef323 100644
--- a/spec/ruby/core/array/pack/shared/unicode.rb
+++ b/spec/ruby/core/array/pack/shared/unicode.rb
@@ -69,7 +69,9 @@ describe :array_pack_unicode, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- [1, 2, 3].pack("U\x00U").should == "\x01\x02"
+ suppress_warning do
+ [1, 2, 3].pack("U\x00U").should == "\x01\x02"
+ end
end
end
diff --git a/spec/ruby/core/array/pack/w_spec.rb b/spec/ruby/core/array/pack/w_spec.rb
index e241d1519c..48ed4496a5 100644
--- a/spec/ruby/core/array/pack/w_spec.rb
+++ b/spec/ruby/core/array/pack/w_spec.rb
@@ -26,7 +26,9 @@ describe "Array#pack with format 'w'" do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- [1, 2, 3].pack("w\x00w").should == "\x01\x02"
+ suppress_warning do
+ [1, 2, 3].pack("w\x00w").should == "\x01\x02"
+ end
end
end
diff --git a/spec/ruby/core/array/plus_spec.rb b/spec/ruby/core/array/plus_spec.rb
index 3962b05c39..635bd131c9 100644
--- a/spec/ruby/core/array/plus_spec.rb
+++ b/spec/ruby/core/array/plus_spec.rb
@@ -14,10 +14,23 @@ describe "Array#+" do
(ary + ary).should == [1, 2, 3, 1, 2, 3]
end
- it "tries to convert the passed argument to an Array using #to_ary" do
- obj = mock('["x", "y"]')
- obj.should_receive(:to_ary).and_return(["x", "y"])
- ([1, 2, 3] + obj).should == [1, 2, 3, "x", "y"]
+ describe "converts the passed argument to an Array using #to_ary" do
+ it "successfully concatenates the resulting array from the #to_ary call" do
+ obj = mock('["x", "y"]')
+ obj.should_receive(:to_ary).and_return(["x", "y"])
+ ([1, 2, 3] + obj).should == [1, 2, 3, "x", "y"]
+ end
+
+ it "raises a Typeerror if the given argument can't be converted to an array" do
+ -> { [1, 2, 3] + nil }.should raise_error(TypeError)
+ -> { [1, 2, 3] + "abc" }.should raise_error(TypeError)
+ end
+
+ it "raises a NoMethodError if the given argument raises a NoMethodError during type coercion to an Array" do
+ obj = mock("hello")
+ obj.should_receive(:to_ary).and_raise(NoMethodError)
+ -> { [1, 2, 3] + obj }.should raise_error(NoMethodError)
+ end
end
it "properly handles recursive arrays" do
diff --git a/spec/ruby/core/array/product_spec.rb b/spec/ruby/core/array/product_spec.rb
index 07d2880a96..6fb3818508 100644
--- a/spec/ruby/core/array/product_spec.rb
+++ b/spec/ruby/core/array/product_spec.rb
@@ -9,6 +9,11 @@ describe "Array#product" do
ar.called.should == :to_ary
end
+ it "returns converted arguments using :method_missing" do
+ ar = ArraySpecs::ArrayMethodMissing.new(2,3)
+ [1].product(ar).should == [[1,2],[1,3]]
+ end
+
it "returns the expected result" do
[1,2].product([3,4,5],[6,8]).should == [[1, 3, 6], [1, 3, 8], [1, 4, 6], [1, 4, 8], [1, 5, 6], [1, 5, 8],
[2, 3, 6], [2, 3, 8], [2, 4, 6], [2, 4, 8], [2, 5, 6], [2, 5, 8]]
diff --git a/spec/ruby/core/array/sample_spec.rb b/spec/ruby/core/array/sample_spec.rb
index 5b3aac9aed..6ef78594f0 100644
--- a/spec/ruby/core/array/sample_spec.rb
+++ b/spec/ruby/core/array/sample_spec.rb
@@ -29,6 +29,10 @@ describe "Array#sample" do
[4].sample(random: Random.new(42)).should equal(4)
end
+ it "returns a single value when not passed a count and a Random class is given" do
+ [4].sample(random: Random).should equal(4)
+ end
+
it "returns an empty Array when passed zero" do
[4].sample(0).should == []
end
diff --git a/spec/ruby/core/array/shuffle_spec.rb b/spec/ruby/core/array/shuffle_spec.rb
index b255147c75..1d528c124f 100644
--- a/spec/ruby/core/array/shuffle_spec.rb
+++ b/spec/ruby/core/array/shuffle_spec.rb
@@ -47,6 +47,10 @@ describe "Array#shuffle" do
[1, 2].shuffle(random: random).should be_an_instance_of(Array)
end
+ it "accepts a Random class for the value for random: argument" do
+ [1, 2].shuffle(random: Random).should be_an_instance_of(Array)
+ end
+
it "calls #to_int on the Object returned by #rand" do
value = mock("array_shuffle_random_value")
value.should_receive(:to_int).at_least(1).times.and_return(0)
@@ -93,4 +97,14 @@ describe "Array#shuffle!" do
-> { ArraySpecs.frozen_array.shuffle! }.should raise_error(FrozenError)
-> { ArraySpecs.empty_frozen_array.shuffle! }.should raise_error(FrozenError)
end
+
+ it "matches CRuby with random:" do
+ %w[a b c].shuffle(random: Random.new(1)).should == %w[a c b]
+ (0..10).to_a.shuffle(random: Random.new(10)).should == [2, 6, 8, 5, 7, 10, 3, 1, 0, 4, 9]
+ end
+
+ it "matches CRuby with srand" do
+ srand(123)
+ %w[a b c d e f g h i j k].shuffle.should == %w[a e f h i j d b g k c]
+ end
end
diff --git a/spec/ruby/core/array/try_convert_spec.rb b/spec/ruby/core/array/try_convert_spec.rb
index 47b4722d80..bea8815006 100644
--- a/spec/ruby/core/array/try_convert_spec.rb
+++ b/spec/ruby/core/array/try_convert_spec.rb
@@ -39,7 +39,7 @@ describe "Array.try_convert" do
it "sends #to_ary to the argument and raises TypeError if it's not a kind of Array" do
obj = mock("to_ary")
obj.should_receive(:to_ary).and_return(Object.new)
- -> { Array.try_convert obj }.should raise_error(TypeError)
+ -> { Array.try_convert obj }.should raise_error(TypeError, "can't convert MockObject to Array (MockObject#to_ary gives Object)")
end
it "does not rescue exceptions raised by #to_ary" do
diff --git a/spec/ruby/core/complex/inspect_spec.rb b/spec/ruby/core/complex/inspect_spec.rb
index 71aabde5be..7a89ec6854 100644
--- a/spec/ruby/core/complex/inspect_spec.rb
+++ b/spec/ruby/core/complex/inspect_spec.rb
@@ -1,4 +1,5 @@
require_relative '../../spec_helper'
+require_relative '../numeric/fixtures/classes'
describe "Complex#inspect" do
it "returns (${real}+${image}i) for positive imaginary parts" do
@@ -13,4 +14,22 @@ describe "Complex#inspect" do
Complex(-1, -4).inspect.should == "(-1-4i)"
Complex(-7, -6.7).inspect.should == "(-7-6.7i)"
end
+
+ it "calls #inspect on real and imaginary" do
+ real = NumericSpecs::Subclass.new
+ real.should_receive(:inspect).and_return("1")
+ imaginary = NumericSpecs::Subclass.new
+ imaginary.should_receive(:inspect).and_return("2")
+ imaginary.should_receive(:<).any_number_of_times.and_return(false)
+ Complex(real, imaginary).inspect.should == "(1+2i)"
+ end
+
+ it "adds an `*' before the `i' if the last character of the imaginary part is not numeric" do
+ real = NumericSpecs::Subclass.new
+ real.should_receive(:inspect).and_return("(1)")
+ imaginary = NumericSpecs::Subclass.new
+ imaginary.should_receive(:inspect).and_return("(2)")
+ imaginary.should_receive(:<).any_number_of_times.and_return(false)
+ Complex(real, imaginary).inspect.should == "((1)+(2)*i)"
+ end
end
diff --git a/spec/ruby/core/complex/to_s_spec.rb b/spec/ruby/core/complex/to_s_spec.rb
index 989a7ae0b7..7677dcd0b5 100644
--- a/spec/ruby/core/complex/to_s_spec.rb
+++ b/spec/ruby/core/complex/to_s_spec.rb
@@ -1,4 +1,5 @@
require_relative '../../spec_helper'
+require_relative '../numeric/fixtures/classes'
describe "Complex#to_s" do
describe "when self's real component is 0" do
@@ -41,4 +42,13 @@ describe "Complex#to_s" do
it "returns 1+NaN*i for Complex(1, NaN)" do
Complex(1, nan_value).to_s.should == "1+NaN*i"
end
+
+ it "treats real and imaginary parts as strings" do
+ real = NumericSpecs::Subclass.new
+ real.should_receive(:to_s).and_return("1")
+ imaginary = NumericSpecs::Subclass.new
+ imaginary.should_receive(:to_s).and_return("2")
+ imaginary.should_receive(:<).any_number_of_times.and_return(false)
+ Complex(real, imaginary).to_s.should == "1+2i"
+ end
end
diff --git a/spec/ruby/core/data/define_spec.rb b/spec/ruby/core/data/define_spec.rb
index abfdd3e6a7..2aa2c50d4c 100644
--- a/spec/ruby/core/data/define_spec.rb
+++ b/spec/ruby/core/data/define_spec.rb
@@ -9,18 +9,28 @@ ruby_version_is "3.2" do
end
it "accepts symbols" do
- movie_with_symbol = Data.define(:title, :year)
- movie_with_symbol.members.should == [:title, :year]
+ movie = Data.define(:title, :year)
+ movie.members.should == [:title, :year]
end
it "accepts strings" do
- movie_with_string = Data.define("title", "year")
- movie_with_string.members.should == [:title, :year]
+ movie = Data.define("title", "year")
+ movie.members.should == [:title, :year]
end
it "accepts a mix of strings and symbols" do
- blockbuster_movie = Data.define("title", :year, "genre")
- blockbuster_movie.members.should == [:title, :year, :genre]
+ movie = Data.define("title", :year, "genre")
+ movie.members.should == [:title, :year, :genre]
+ end
+
+ it "accepts a block" do
+ movie = Data.define(:title, :year) do
+ def title_with_year
+ "#{title} (#{year})"
+ end
+ end
+ movie.members.should == [:title, :year]
+ movie.new("Matrix", 1999).title_with_year.should == "Matrix (1999)"
end
end
end
diff --git a/spec/ruby/core/dir/fchdir_spec.rb b/spec/ruby/core/dir/fchdir_spec.rb
index dde459e98e..08b1cdfc7e 100644
--- a/spec/ruby/core/dir/fchdir_spec.rb
+++ b/spec/ruby/core/dir/fchdir_spec.rb
@@ -6,15 +6,13 @@ ruby_version_is '3.3' do
dir = Dir.new('.')
Dir.fchdir(dir.fileno)
true
- rescue NotImplementedError
+ rescue NotImplementedError, NoMethodError
false
- rescue Exception
- true
ensure
dir.close
end
- if has_fchdir
+ guard -> { has_fchdir } do
describe "Dir.fchdir" do
before :all do
DirSpecs.create_mock_dirs
@@ -58,7 +56,7 @@ ruby_version_is '3.3' do
end
it "raises a SystemCallError if the file descriptor given is not valid" do
- -> { Dir.fchdir -1 }.should raise_error(SystemCallError)
+ -> { Dir.fchdir(-1) }.should raise_error(SystemCallError)
-> { Dir.fchdir(-1) { } }.should raise_error(SystemCallError)
end
@@ -67,7 +65,9 @@ ruby_version_is '3.3' do
-> { Dir.fchdir($stdout.fileno) { } }.should raise_error(SystemCallError)
end
end
- else
+ end
+
+ guard_not -> { has_fchdir } do
describe "Dir.fchdir" do
it "raises NotImplementedError" do
-> { Dir.fchdir 1 }.should raise_error(NotImplementedError)
diff --git a/spec/ruby/core/dir/home_spec.rb b/spec/ruby/core/dir/home_spec.rb
index bbe347ba9e..90a008faf1 100644
--- a/spec/ruby/core/dir/home_spec.rb
+++ b/spec/ruby/core/dir/home_spec.rb
@@ -85,4 +85,10 @@ describe "Dir.home" do
it "raises an ArgumentError if the named user doesn't exist" do
-> { Dir.home('geuw2n288dh2k') }.should raise_error(ArgumentError)
end
+
+ describe "when called with a nil user name" do
+ it "returns the current user's home directory, reading $HOME first" do
+ Dir.home(nil).should == "/rubyspec_home"
+ end
+ end
end
diff --git a/spec/ruby/core/enumerable/shared/inject.rb b/spec/ruby/core/enumerable/shared/inject.rb
index a934d039c5..693d34d675 100644
--- a/spec/ruby/core/enumerable/shared/inject.rb
+++ b/spec/ruby/core/enumerable/shared/inject.rb
@@ -28,6 +28,15 @@ describe :enumerable_inject, shared: true do
}.should complain(/#{__FILE__}:#{__LINE__-1}: warning: given block not used/, verbose: true)
end
+ it "does not warn when given a Symbol with $VERBOSE true" do
+ -> {
+ [1, 2].send(@method, 0, :+)
+ [1, 2].send(@method, :+)
+ EnumerableSpecs::Numerous.new(1, 2).send(@method, 0, :+)
+ EnumerableSpecs::Numerous.new(1, 2).send(@method, :+)
+ }.should_not complain(verbose: true)
+ end
+
it "can take a symbol argument" do
EnumerableSpecs::Numerous.new(10, 1, 2, 3).send(@method, :-).should == 4
end
diff --git a/spec/ruby/core/enumerable/tally_spec.rb b/spec/ruby/core/enumerable/tally_spec.rb
index f09a8f533a..e0edc8dc75 100644
--- a/spec/ruby/core/enumerable/tally_spec.rb
+++ b/spec/ruby/core/enumerable/tally_spec.rb
@@ -49,6 +49,13 @@ ruby_version_is "3.1" do
enum.tally(hash).should equal(hash)
end
+ it "calls #to_hash to convert argument to Hash implicitly if passed not a Hash" do
+ enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
+ object = Object.new
+ def object.to_hash; { 'foo' => 1 }; end
+ enum.tally(object).should == { 'foo' => 3, 'bar' => 1, 'baz' => 1}
+ end
+
it "raises a FrozenError and does not update the given hash when the hash is frozen" do
enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
hash = { 'foo' => 1 }.freeze
@@ -56,6 +63,12 @@ ruby_version_is "3.1" do
hash.should == { 'foo' => 1 }
end
+ it "raises a FrozenError even if enumerable is empty" do
+ enum = EnumerableSpecs::Numerous.new()
+ hash = { 'foo' => 1 }.freeze
+ -> { enum.tally(hash) }.should raise_error(FrozenError)
+ end
+
it "does not call given block" do
enum = EnumerableSpecs::Numerous.new('foo', 'bar', 'foo', 'baz')
enum.tally({ 'foo' => 1 }) { |v| ScratchPad << v }
diff --git a/spec/ruby/core/fiber/inspect_spec.rb b/spec/ruby/core/fiber/inspect_spec.rb
new file mode 100644
index 0000000000..ee53af3a39
--- /dev/null
+++ b/spec/ruby/core/fiber/inspect_spec.rb
@@ -0,0 +1,38 @@
+require_relative '../../spec_helper'
+require 'fiber'
+
+describe "Fiber#inspect" do
+ describe "status" do
+ it "is resumed for the root Fiber of a Thread" do
+ inspected = Thread.new { Fiber.current.inspect }.value
+ inspected.should =~ /\A#<Fiber:0x\h+ .*\(resumed\)>\z/
+ end
+
+ it "is created for a Fiber which did not run yet" do
+ inspected = Fiber.new {}.inspect
+ inspected.should =~ /\A#<Fiber:0x\h+ .+ \(created\)>\z/
+ end
+
+ it "is resumed for a Fiber which was resumed" do
+ inspected = Fiber.new { Fiber.current.inspect }.resume
+ inspected.should =~ /\A#<Fiber:0x\h+ .+ \(resumed\)>\z/
+ end
+
+ ruby_version_is "3.0" do
+ it "is resumed for a Fiber which was transferred" do
+ inspected = Fiber.new { Fiber.current.inspect }.transfer
+ inspected.should =~ /\A#<Fiber:0x\h+ .+ \(resumed\)>\z/
+ end
+ end
+
+ it "is suspended for a Fiber which was resumed and yielded" do
+ inspected = Fiber.new { Fiber.yield }.tap(&:resume).inspect
+ inspected.should =~ /\A#<Fiber:0x\h+ .+ \(suspended\)>\z/
+ end
+
+ it "is terminated for a Fiber which has terminated" do
+ inspected = Fiber.new {}.tap(&:resume).inspect
+ inspected.should =~ /\A#<Fiber:0x\h+ .+ \(terminated\)>\z/
+ end
+ end
+end
diff --git a/spec/ruby/core/file/dirname_spec.rb b/spec/ruby/core/file/dirname_spec.rb
index cf0f909f59..8dd6c4ca88 100644
--- a/spec/ruby/core/file/dirname_spec.rb
+++ b/spec/ruby/core/file/dirname_spec.rb
@@ -12,18 +12,33 @@ describe "File.dirname" do
end
ruby_version_is '3.1' do
- it "returns all the components of filename except the last parts by the level" do
- File.dirname('/home/jason', 2).should == '/'
- File.dirname('/home/jason/poot.txt', 2).should == '/home'
- end
-
- it "returns the same string if the level is 0" do
- File.dirname('poot.txt', 0).should == 'poot.txt'
- File.dirname('/', 0).should == '/'
- end
-
- it "raises ArgumentError if the level is negative" do
- -> {File.dirname('/home/jason', -1)}.should raise_error(ArgumentError)
+ context "when level is passed" do
+ it "returns all the components of filename except the last parts by the level" do
+ File.dirname('/home/jason', 2).should == '/'
+ File.dirname('/home/jason/poot.txt', 2).should == '/home'
+ end
+
+ it "returns the same String if the level is 0" do
+ File.dirname('poot.txt', 0).should == 'poot.txt'
+ File.dirname('/', 0).should == '/'
+ end
+
+ it "raises ArgumentError if the level is negative" do
+ -> {
+ File.dirname('/home/jason', -1)
+ }.should raise_error(ArgumentError, "negative level: -1")
+ end
+
+ it "returns '/' when level exceeds the number of segments in the path" do
+ File.dirname("/home/jason", 100).should == '/'
+ end
+
+ it "calls #to_int if passed not numeric value" do
+ object = Object.new
+ def object.to_int; 2; end
+
+ File.dirname("/a/b/c/d", object).should == '/a/b'
+ end
end
end
diff --git a/spec/ruby/core/hash/try_convert_spec.rb b/spec/ruby/core/hash/try_convert_spec.rb
index 44195c5010..d359ae49d8 100644
--- a/spec/ruby/core/hash/try_convert_spec.rb
+++ b/spec/ruby/core/hash/try_convert_spec.rb
@@ -39,7 +39,7 @@ describe "Hash.try_convert" do
it "sends #to_hash to the argument and raises TypeError if it's not a kind of Hash" do
obj = mock("to_hash")
obj.should_receive(:to_hash).and_return(Object.new)
- -> { Hash.try_convert obj }.should raise_error(TypeError)
+ -> { Hash.try_convert obj }.should raise_error(TypeError, "can't convert MockObject to Hash (MockObject#to_hash gives Object)")
end
it "does not rescue exceptions raised by #to_hash" do
diff --git a/spec/ruby/core/integer/bit_and_spec.rb b/spec/ruby/core/integer/bit_and_spec.rb
index 8de5a14aaa..e7face39ac 100644
--- a/spec/ruby/core/integer/bit_and_spec.rb
+++ b/spec/ruby/core/integer/bit_and_spec.rb
@@ -30,7 +30,7 @@ describe "Integer#&" do
it "coerces the rhs and calls #coerce" do
obj = mock("fixnum bit and")
- obj.should_receive(:coerce).with(6).and_return([3, 6])
+ obj.should_receive(:coerce).with(6).and_return([6, 3])
(6 & obj).should == 2
end
diff --git a/spec/ruby/core/integer/bit_or_spec.rb b/spec/ruby/core/integer/bit_or_spec.rb
index 6f4279c170..fdf8a191e5 100644
--- a/spec/ruby/core/integer/bit_or_spec.rb
+++ b/spec/ruby/core/integer/bit_or_spec.rb
@@ -30,9 +30,9 @@ describe "Integer#|" do
end
it "coerces the rhs and calls #coerce" do
- obj = mock("fixnum bit and")
- obj.should_receive(:coerce).with(6).and_return([3, 6])
- (6 & obj).should == 2
+ obj = mock("fixnum bit or")
+ obj.should_receive(:coerce).with(6).and_return([6, 3])
+ (6 | obj).should == 7
end
it "raises a TypeError when passed a Float" do
diff --git a/spec/ruby/core/integer/bit_xor_spec.rb b/spec/ruby/core/integer/bit_xor_spec.rb
index f1150a20d5..1f46bc52f3 100644
--- a/spec/ruby/core/integer/bit_xor_spec.rb
+++ b/spec/ruby/core/integer/bit_xor_spec.rb
@@ -28,8 +28,8 @@ describe "Integer#^" do
end
it "coerces the rhs and calls #coerce" do
- obj = mock("fixnum bit and")
- obj.should_receive(:coerce).with(6).and_return([3, 6])
+ obj = mock("fixnum bit xor")
+ obj.should_receive(:coerce).with(6).and_return([6, 3])
(6 ^ obj).should == 5
end
diff --git a/spec/ruby/core/integer/ceildiv_spec.rb b/spec/ruby/core/integer/ceildiv_spec.rb
new file mode 100644
index 0000000000..18d07c66d0
--- /dev/null
+++ b/spec/ruby/core/integer/ceildiv_spec.rb
@@ -0,0 +1,22 @@
+require_relative '../../spec_helper'
+
+describe "Integer#ceildiv" do
+ ruby_version_is '3.2' do
+ it "returns a quotient of division which is rounded up to the nearest integer" do
+ 0.ceildiv(3).should eql(0)
+ 1.ceildiv(3).should eql(1)
+ 3.ceildiv(3).should eql(1)
+ 4.ceildiv(3).should eql(2)
+
+ 4.ceildiv(-3).should eql(-1)
+ -4.ceildiv(3).should eql(-1)
+ -4.ceildiv(-3).should eql(2)
+
+ 3.ceildiv(1.2).should eql(3)
+ 3.ceildiv(6/5r).should eql(3)
+
+ (10**100-11).ceildiv(10**99-1).should eql(10)
+ (10**100-9).ceildiv(10**99-1).should eql(11)
+ end
+ end
+end
diff --git a/spec/ruby/core/integer/try_convert_spec.rb b/spec/ruby/core/integer/try_convert_spec.rb
index 45c66eec79..4bc7d3851a 100644
--- a/spec/ruby/core/integer/try_convert_spec.rb
+++ b/spec/ruby/core/integer/try_convert_spec.rb
@@ -28,7 +28,17 @@ ruby_version_is "3.1" do
it "sends #to_int to the argument and raises TypeError if it's not a kind of Integer" do
obj = mock("to_int")
obj.should_receive(:to_int).and_return(Object.new)
- -> { Integer.try_convert obj }.should raise_error(TypeError)
+ -> {
+ Integer.try_convert obj
+ }.should raise_error(TypeError, "can't convert MockObject to Integer (MockObject#to_int gives Object)")
+ end
+
+ it "responds with a different error message when it raises a TypeError, depending on the type of the non-Integer object :to_int returns" do
+ obj = mock("to_int")
+ obj.should_receive(:to_int).and_return("A String")
+ -> {
+ Integer.try_convert obj
+ }.should raise_error(TypeError, "can't convert MockObject to Integer (MockObject#to_int gives String)")
end
it "does not rescue exceptions raised by #to_int" do
diff --git a/spec/ruby/core/io/gets_spec.rb b/spec/ruby/core/io/gets_spec.rb
index 1f1c3bb254..f38e3d3974 100644
--- a/spec/ruby/core/io/gets_spec.rb
+++ b/spec/ruby/core/io/gets_spec.rb
@@ -113,6 +113,35 @@ describe "IO#gets" do
$..should == @count += 1
end
end
+
+ describe "that consists of multiple bytes" do
+ platform_is_not :windows do
+ it "should match the separator even if the buffer is filled over successive reads" do
+ IO.pipe do |read, write|
+
+ # Write part of the string with the separator split between two write calls. We want
+ # the read to intertwine such that when the read starts the full data isn't yet
+ # available in the buffer.
+ write.write("Aquí está la línea tres\r\n")
+
+ t = Thread.new do
+ # Continue reading until the separator is encountered or the pipe is closed.
+ read.gets("\r\n\r\n")
+ end
+
+ # Write the other half of the separator, which should cause the `gets` call to now
+ # match. Explicitly close the pipe for good measure so a bug in `gets` doesn't block forever.
+ Thread.pass until t.stop?
+
+ write.write("\r\nelse\r\n\r\n")
+ write.close
+
+ t.value.bytes.should == "Aquí está la línea tres\r\n\r\n".bytes
+ read.read(8).bytes.should == "else\r\n\r\n".bytes
+ end
+ end
+ end
+ end
end
describe "when passed chomp" do
diff --git a/spec/ruby/core/io/shared/write.rb b/spec/ruby/core/io/shared/write.rb
index a4d1259971..964064746a 100644
--- a/spec/ruby/core/io/shared/write.rb
+++ b/spec/ruby/core/io/shared/write.rb
@@ -97,3 +97,58 @@ describe :io_write, shared: true do
end
end
end
+
+describe :io_write_transcode, shared: true do
+ before :each do
+ @transcode_filename = tmp("io_write_transcode")
+ end
+
+ after :each do
+ rm_r @transcode_filename
+ end
+
+ it "transcodes the given string when the external encoding is set and neither is BINARY" do
+ utf8_str = "hello"
+
+ File.open(@transcode_filename, "w", external_encoding: Encoding::UTF_16BE) do |file|
+ file.external_encoding.should == Encoding::UTF_16BE
+ file.send(@method, utf8_str)
+ end
+
+ result = File.binread(@transcode_filename)
+ expected = [0, 104, 0, 101, 0, 108, 0, 108, 0, 111] # UTF-16BE bytes for "hello"
+
+ result.bytes.should == expected
+ end
+
+ it "transcodes the given string when the external encoding is set and the string encoding is BINARY" do
+ str = "été".b
+
+ File.open(@transcode_filename, "w", external_encoding: Encoding::UTF_16BE) do |file|
+ file.external_encoding.should == Encoding::UTF_16BE
+ -> { file.send(@method, str) }.should raise_error(Encoding::UndefinedConversionError)
+ end
+ end
+end
+
+describe :io_write_no_transcode, shared: true do
+ before :each do
+ @transcode_filename = tmp("io_write_no_transcode")
+ end
+
+ after :each do
+ rm_r @transcode_filename
+ end
+
+ it "does not transcode the given string even when the external encoding is set" do
+ utf8_str = "hello"
+
+ File.open(@transcode_filename, "w", external_encoding: Encoding::UTF_16BE) do |file|
+ file.external_encoding.should == Encoding::UTF_16BE
+ file.send(@method, utf8_str)
+ end
+
+ result = File.binread(@transcode_filename)
+ result.bytes.should == utf8_str.bytes
+ end
+end
diff --git a/spec/ruby/core/io/syswrite_spec.rb b/spec/ruby/core/io/syswrite_spec.rb
index eeb8d302a7..8bf61a27c3 100644
--- a/spec/ruby/core/io/syswrite_spec.rb
+++ b/spec/ruby/core/io/syswrite_spec.rb
@@ -78,4 +78,5 @@ end
describe "IO#syswrite" do
it_behaves_like :io_write, :syswrite
+ it_behaves_like :io_write_no_transcode, :syswrite
end
diff --git a/spec/ruby/core/io/try_convert_spec.rb b/spec/ruby/core/io/try_convert_spec.rb
index 5fbd10b6fa..a9e99de7aa 100644
--- a/spec/ruby/core/io/try_convert_spec.rb
+++ b/spec/ruby/core/io/try_convert_spec.rb
@@ -38,7 +38,7 @@ describe "IO.try_convert" do
it "raises a TypeError if the object does not return an IO from #to_io" do
obj = mock("io")
obj.should_receive(:to_io).and_return("io")
- -> { IO.try_convert(obj) }.should raise_error(TypeError)
+ -> { IO.try_convert(obj) }.should raise_error(TypeError, "can't convert MockObject to IO (MockObject#to_io gives String)")
end
it "propagates an exception raised by #to_io" do
diff --git a/spec/ruby/core/io/write_nonblock_spec.rb b/spec/ruby/core/io/write_nonblock_spec.rb
index 5532556d8a..c403c864fd 100644
--- a/spec/ruby/core/io/write_nonblock_spec.rb
+++ b/spec/ruby/core/io/write_nonblock_spec.rb
@@ -50,6 +50,7 @@ platform_is_not :windows do
describe "IO#write_nonblock" do
it_behaves_like :io_write, :write_nonblock
+ it_behaves_like :io_write_no_transcode, :write_nonblock
end
end
diff --git a/spec/ruby/core/io/write_spec.rb b/spec/ruby/core/io/write_spec.rb
index 6e89c7cd9e..bf23634372 100644
--- a/spec/ruby/core/io/write_spec.rb
+++ b/spec/ruby/core/io/write_spec.rb
@@ -220,6 +220,7 @@ end
describe "IO#write" do
it_behaves_like :io_write, :write
+ it_behaves_like :io_write_transcode, :write
it "accepts multiple arguments" do
IO.pipe do |r, w|
diff --git a/spec/ruby/core/kernel/Complex_spec.rb b/spec/ruby/core/kernel/Complex_spec.rb
index cc8177fa02..346d50ab5e 100644
--- a/spec/ruby/core/kernel/Complex_spec.rb
+++ b/spec/ruby/core/kernel/Complex_spec.rb
@@ -269,4 +269,8 @@ describe "Kernel.Complex()" do
end
end
end
+
+ it "freezes its result" do
+ Complex(1).frozen?.should == true
+ end
end
diff --git a/spec/ruby/core/kernel/define_singleton_method_spec.rb b/spec/ruby/core/kernel/define_singleton_method_spec.rb
index 2d8b1bf413..24acec84f5 100644
--- a/spec/ruby/core/kernel/define_singleton_method_spec.rb
+++ b/spec/ruby/core/kernel/define_singleton_method_spec.rb
@@ -111,4 +111,10 @@ describe "Kernel#define_singleton_method" do
cls.foo.should == :ok
}.should_not raise_error(NoMethodError)
end
+
+ it "cannot define a singleton method with a frozen singleton class" do
+ o = Object.new
+ o.freeze
+ -> { o.define_singleton_method(:foo) { 1 } }.should raise_error(FrozenError)
+ end
end
diff --git a/spec/ruby/core/kernel/method_spec.rb b/spec/ruby/core/kernel/method_spec.rb
index caf2ec948b..3fc566d6a6 100644
--- a/spec/ruby/core/kernel/method_spec.rb
+++ b/spec/ruby/core/kernel/method_spec.rb
@@ -29,7 +29,7 @@ describe "Kernel#method" do
m.call.should == :defined
end
- it "can be called even if we only repond_to_missing? method, true" do
+ it "can be called even if we only respond_to_missing? method, true" do
m = KernelSpecs::RespondViaMissing.new.method(:handled_privately)
m.should be_an_instance_of(Method)
m.call(1, 2, 3).should == "Done handled_privately([1, 2, 3])"
@@ -58,4 +58,23 @@ describe "Kernel#method" do
m = cls.new.method(:bar)
m.call.should == :bar
end
+
+ describe "converts the given name to a String using #to_str" do
+ it "calls #to_str to convert the given name to a String" do
+ name = mock("method-name")
+ name.should_receive(:to_str).and_return("hash")
+ Object.method(name).should == Object.method(:hash)
+ end
+
+ it "raises a TypeError if the given name can't be converted to a String" do
+ -> { Object.method(nil) }.should raise_error(TypeError)
+ -> { Object.method([]) }.should raise_error(TypeError)
+ end
+
+ it "raises a NoMethodError if the given argument raises a NoMethodError during type coercion to a String" do
+ name = mock("method-name")
+ name.should_receive(:to_str).and_raise(NoMethodError)
+ -> { Object.method(name) }.should raise_error(NoMethodError)
+ end
+ end
end
diff --git a/spec/ruby/core/kernel/require_spec.rb b/spec/ruby/core/kernel/require_spec.rb
index dc3da4b7e6..b0af8b297d 100644
--- a/spec/ruby/core/kernel/require_spec.rb
+++ b/spec/ruby/core/kernel/require_spec.rb
@@ -16,6 +16,22 @@ describe "Kernel#require" do
Kernel.should have_private_instance_method(:require)
end
+ provided = %w[complex enumerator rational thread ruby2_keywords]
+ ruby_version_is "3.1" do
+ provided << "fiber"
+ end
+
+ it "#{provided.join(', ')} are already required" do
+ out = ruby_exe("puts $LOADED_FEATURES", options: '--disable-gems --disable-did-you-mean')
+ features = out.lines.map { |line| File.basename(line.chomp, '.*') }
+ features -= %w[encdb transdb] # Ignore CRuby internals
+ features.sort.should == provided.sort
+
+ code = provided.map { |f| "puts require #{f.inspect}\n" }.join
+ required = ruby_exe(code, options: '--disable-gems')
+ required.should == "false\n" * provided.size
+ end
+
it_behaves_like :kernel_require_basic, :require, CodeLoadingSpecs::Method.new
it_behaves_like :kernel_require, :require, CodeLoadingSpecs::Method.new
end
diff --git a/spec/ruby/core/kernel/shared/require.rb b/spec/ruby/core/kernel/shared/require.rb
index ae814aa317..5cbc11c9ec 100644
--- a/spec/ruby/core/kernel/shared/require.rb
+++ b/spec/ruby/core/kernel/shared/require.rb
@@ -557,20 +557,6 @@ describe :kernel_require, shared: true do
ScratchPad.recorded.should == []
end
- provided = %w[complex enumerator rational thread]
- provided << 'ruby2_keywords'
-
- it "#{provided.join(', ')} are already required" do
- features = ruby_exe("puts $LOADED_FEATURES", options: '--disable-gems')
- provided.each { |feature|
- features.should =~ /\b#{feature}\.(rb|so|jar)$/
- }
-
- code = provided.map { |f| "puts require #{f.inspect}\n" }.join
- required = ruby_exe(code, options: '--disable-gems')
- required.should == "false\n" * provided.size
- end
-
it "unicode_normalize is part of core and not $LOADED_FEATURES" do
features = ruby_exe("puts $LOADED_FEATURES", options: '--disable-gems')
features.lines.each { |feature|
diff --git a/spec/ruby/core/marshal/dump_spec.rb b/spec/ruby/core/marshal/dump_spec.rb
index 879ea287ce..f38250b513 100644
--- a/spec/ruby/core/marshal/dump_spec.rb
+++ b/spec/ruby/core/marshal/dump_spec.rb
@@ -104,19 +104,42 @@ describe "Marshal.dump" do
UserMarshal.should_not_receive(:name)
Marshal.dump(UserMarshal.new)
end
+
+ it "raises TypeError if an Object is an instance of an anonymous class" do
+ -> { Marshal.dump(Class.new(UserMarshal).new) }.should raise_error(TypeError, /can't dump anonymous class/)
+ end
end
describe "with an object responding to #_dump" do
- it "dumps the object returned by #_dump" do
+ it "dumps the String returned by #_dump" do
Marshal.dump(UserDefined.new).should == "\004\bu:\020UserDefined\022\004\b[\a:\nstuff;\000"
end
+ it "dumps the String in non US-ASCII and non UTF-8 encoding" do
+ object = UserDefinedString.new("a".encode("windows-1251"))
+ Marshal.dump(object).should == "\x04\bIu:\x16UserDefinedString\x06a\x06:\rencoding\"\x11Windows-1251"
+ end
+
+ it "dumps the String in multibyte encoding" do
+ object = UserDefinedString.new("a".encode("utf-32le"))
+ Marshal.dump(object).should == "\x04\bIu:\x16UserDefinedString\ta\x00\x00\x00\x06:\rencoding\"\rUTF-32LE"
+ end
+
+ it "ignores overridden name method" do
+ obj = MarshalSpec::UserDefinedWithOverriddenName.new
+ Marshal.dump(obj).should == "\x04\bu:/MarshalSpec::UserDefinedWithOverriddenName\x12\x04\b[\a:\nstuff;\x00"
+ end
+
it "raises a TypeError if _dump returns a non-string" do
m = mock("marshaled")
m.should_receive(:_dump).and_return(0)
-> { Marshal.dump(m) }.should raise_error(TypeError)
end
+ it "raises TypeError if an Object is an instance of an anonymous class" do
+ -> { Marshal.dump(Class.new(UserDefined).new) }.should raise_error(TypeError, /can't dump anonymous class/)
+ end
+
it "favors marshal_dump over _dump" do
m = mock("marshaled")
m.should_receive(:marshal_dump).and_return(0)
@@ -166,8 +189,17 @@ describe "Marshal.dump" do
Marshal.dump(UserDefined::Nested).should == "\004\bc\030UserDefined::Nested"
end
+ it "ignores overridden name method" do
+ Marshal.dump(MarshalSpec::ClassWithOverriddenName).should == "\x04\bc)MarshalSpec::ClassWithOverriddenName"
+ end
+
+ it "dumps a class with multibyte characters in name" do
+ source_object = eval("MarshalSpec::MultibyteぁあぃいClass".force_encoding(Encoding::UTF_8))
+ Marshal.dump(source_object).should == "\x04\bc,MarshalSpec::Multibyte\xE3\x81\x81\xE3\x81\x82\xE3\x81\x83\xE3\x81\x84Class"
+ end
+
it "raises TypeError with an anonymous Class" do
- -> { Marshal.dump(Class.new) }.should raise_error(TypeError)
+ -> { Marshal.dump(Class.new) }.should raise_error(TypeError, /can't dump anonymous class/)
end
it "raises TypeError with a singleton Class" do
@@ -180,8 +212,17 @@ describe "Marshal.dump" do
Marshal.dump(Marshal).should == "\004\bm\fMarshal"
end
+ it "ignores overridden name method" do
+ Marshal.dump(MarshalSpec::ModuleWithOverriddenName).should == "\x04\bc*MarshalSpec::ModuleWithOverriddenName"
+ end
+
+ it "dumps a module with multibyte characters in name" do
+ source_object = eval("MarshalSpec::MultibyteけげこごModule".force_encoding(Encoding::UTF_8))
+ Marshal.dump(source_object).should == "\x04\bm-MarshalSpec::Multibyte\xE3\x81\x91\xE3\x81\x92\xE3\x81\x93\xE3\x81\x94Module"
+ end
+
it "raises TypeError with an anonymous Module" do
- -> { Marshal.dump(Module.new) }.should raise_error(TypeError)
+ -> { Marshal.dump(Module.new) }.should raise_error(TypeError, /can't dump anonymous module/)
end
end
@@ -255,6 +296,11 @@ describe "Marshal.dump" do
Marshal.dump(UserString.new.extend(Meths).force_encoding("binary")).should == "\004\be:\nMethsC:\017UserString\"\000"
end
+ it "ignores overridden name method when dumps a String subclass" do
+ obj = MarshalSpec::StringWithOverriddenName.new
+ Marshal.dump(obj).should == "\x04\bC:*MarshalSpec::StringWithOverriddenName\"\x00"
+ end
+
it "dumps a String with instance variables" do
str = ""
str.instance_variable_set("@foo", "bar")
@@ -310,14 +356,42 @@ describe "Marshal.dump" do
Marshal.dump(o).should == "\x04\b/\x00\x10"
end
+ it "dumps an ascii-compatible Regexp" do
+ o = Regexp.new("a".encode("us-ascii"), Regexp::FIXEDENCODING)
+ Marshal.dump(o).should == "\x04\bI/\x06a\x10\x06:\x06EF"
+
+ o = Regexp.new("a".encode("us-ascii"))
+ Marshal.dump(o).should == "\x04\bI/\x06a\x00\x06:\x06EF"
+
+ o = Regexp.new("a".encode("windows-1251"), Regexp::FIXEDENCODING)
+ Marshal.dump(o).should == "\x04\bI/\x06a\x10\x06:\rencoding\"\x11Windows-1251"
+
+ o = Regexp.new("a".encode("windows-1251"))
+ Marshal.dump(o).should == "\x04\bI/\x06a\x00\x06:\x06EF"
+ end
+
it "dumps a UTF-8 Regexp" do
o = Regexp.new("".force_encoding("utf-8"), Regexp::FIXEDENCODING)
Marshal.dump(o).should == "\x04\bI/\x00\x10\x06:\x06ET"
+
+ o = Regexp.new("a".force_encoding("utf-8"), Regexp::FIXEDENCODING)
+ Marshal.dump(o).should == "\x04\bI/\x06a\x10\x06:\x06ET"
+
+ o = Regexp.new("\u3042".force_encoding("utf-8"), Regexp::FIXEDENCODING)
+ Marshal.dump(o).should == "\x04\bI/\b\xE3\x81\x82\x10\x06:\x06ET"
end
it "dumps a Regexp in another encoding" do
o = Regexp.new("".force_encoding("utf-16le"), Regexp::FIXEDENCODING)
Marshal.dump(o).should == "\x04\bI/\x00\x10\x06:\rencoding\"\rUTF-16LE"
+
+ o = Regexp.new("a".encode("utf-16le"), Regexp::FIXEDENCODING)
+ Marshal.dump(o).should == "\x04\bI/\aa\x00\x10\x06:\rencoding\"\rUTF-16LE"
+ end
+
+ it "ignores overridden name method when dumps a Regexp subclass" do
+ obj = MarshalSpec::RegexpWithOverriddenName.new("")
+ Marshal.dump(obj).should == "\x04\bIC:*MarshalSpec::RegexpWithOverriddenName/\x00\x00\x06:\x06EF"
end
end
@@ -349,6 +423,11 @@ describe "Marshal.dump" do
it "dumps an extended Array" do
Marshal.dump([].extend(Meths)).should == "\004\be:\nMeths[\000"
end
+
+ it "ignores overridden name method when dumps an Array subclass" do
+ obj = MarshalSpec::ArrayWithOverriddenName.new
+ Marshal.dump(obj).should == "\x04\bC:)MarshalSpec::ArrayWithOverriddenName[\x00"
+ end
end
describe "with a Hash" do
@@ -356,6 +435,10 @@ describe "Marshal.dump" do
Marshal.dump({}).should == "\004\b{\000"
end
+ it "dumps a non-empty Hash" do
+ Marshal.dump({a: 1}).should == "\x04\b{\x06:\x06ai\x06"
+ end
+
it "dumps a Hash subclass" do
Marshal.dump(UserHash.new).should == "\004\bC:\rUserHash{\000"
end
@@ -364,8 +447,24 @@ describe "Marshal.dump" do
Marshal.dump(Hash.new(1)).should == "\004\b}\000i\006"
end
+ ruby_version_is "3.1" do
+ it "dumps a Hash with compare_by_identity" do
+ h = {}
+ h.compare_by_identity
+
+ Marshal.dump(h).should == "\004\bC:\tHash{\x00"
+ end
+
+ it "dumps a Hash subclass with compare_by_identity" do
+ h = UserHash.new
+ h.compare_by_identity
+
+ Marshal.dump(h).should == "\x04\bC:\rUserHashC:\tHash{\x00"
+ end
+ end
+
it "raises a TypeError with hash having default proc" do
- -> { Marshal.dump(Hash.new {}) }.should raise_error(TypeError)
+ -> { Marshal.dump(Hash.new {}) }.should raise_error(TypeError, "can't dump hash with default proc")
end
it "dumps a Hash with instance variables" do
@@ -381,6 +480,11 @@ describe "Marshal.dump" do
it "dumps an Hash subclass with a parameter to initialize" do
Marshal.dump(UserHashInitParams.new(1)).should == "\004\bIC:\027UserHashInitParams{\000\006:\a@ai\006"
end
+
+ it "ignores overridden name method when dumps a Hash subclass" do
+ obj = MarshalSpec::HashWithOverriddenName.new
+ Marshal.dump(obj).should == "\x04\bC:(MarshalSpec::HashWithOverriddenName{\x00"
+ end
end
describe "with a Struct" do
@@ -409,6 +513,15 @@ describe "Marshal.dump" do
Marshal.dump(obj).should == "\004\be:\nMethsS:\025Struct::Extended\a:\006a[\a;\a\"\ahi:\006b[\a;\000@\a"
Struct.send(:remove_const, :Extended)
end
+
+ it "ignores overridden name method" do
+ obj = MarshalSpec::StructWithOverriddenName.new("member")
+ Marshal.dump(obj).should == "\x04\bS:*MarshalSpec::StructWithOverriddenName\x06:\x06a\"\vmember"
+ end
+
+ it "raises TypeError with an anonymous Struct" do
+ -> { Marshal.dump(Struct.new(:a).new(1)) }.should raise_error(TypeError, /can't dump anonymous class/)
+ end
end
describe "with an Object" do
@@ -440,13 +553,18 @@ describe "Marshal.dump" do
Marshal.dump(obj).should == "\004\bo:\x0BObject\x00"
end
- it "dumps an Object if it has a singleton class but no singleton methods" do
+ it "dumps an Object if it has a singleton class but no singleton methods and no singleton instance variables" do
obj = Object.new
obj.singleton_class
Marshal.dump(obj).should == "\004\bo:\x0BObject\x00"
end
- it "raises if an Object has a singleton class and singleton methods" do
+ it "ignores overridden name method" do
+ obj = MarshalSpec::ClassWithOverriddenName.new
+ Marshal.dump(obj).should == "\x04\bo:)MarshalSpec::ClassWithOverriddenName\x00"
+ end
+
+ it "raises TypeError if an Object has a singleton class and singleton methods" do
obj = Object.new
def obj.foo; end
-> {
@@ -454,10 +572,45 @@ describe "Marshal.dump" do
}.should raise_error(TypeError, "singleton can't be dumped")
end
+ it "raises TypeError if an Object has a singleton class and singleton instance variables" do
+ obj = Object.new
+ class << obj
+ @v = 1
+ end
+
+ -> {
+ Marshal.dump(obj)
+ }.should raise_error(TypeError, "singleton can't be dumped")
+ end
+
+ it "raises TypeError if an Object is an instance of an anonymous class" do
+ anonymous_class = Class.new
+ obj = anonymous_class.new
+
+ -> { Marshal.dump(obj) }.should raise_error(TypeError, /can't dump anonymous class/)
+ end
+
+ it "raises TypeError if an Object extends an anonymous module" do
+ anonymous_module = Module.new
+ obj = Object.new
+ obj.extend(anonymous_module)
+
+ -> { Marshal.dump(obj) }.should raise_error(TypeError, /can't dump anonymous class/)
+ end
+
it "dumps a BasicObject subclass if it defines respond_to?" do
obj = MarshalSpec::BasicObjectSubWithRespondToFalse.new
Marshal.dump(obj).should == "\x04\bo:2MarshalSpec::BasicObjectSubWithRespondToFalse\x00"
end
+
+ it "dumps without marshaling any attached finalizer" do
+ obj = Object.new
+ finalizer = Object.new
+ def finalizer.noop(_)
+ end
+ ObjectSpace.define_finalizer(obj, finalizer.method(:noop))
+ Marshal.load(Marshal.dump(obj)).class.should == Object
+ end
end
describe "with a Range" do
@@ -483,6 +636,10 @@ describe "Marshal.dump" do
load.instance_variable_get(:@foo).should == 42
end
end
+
+ it "raises TypeError with an anonymous Range subclass" do
+ -> { Marshal.dump(Class.new(Range).new(1, 2)) }.should raise_error(TypeError, /can't dump anonymous class/)
+ end
end
describe "with a Time" do
@@ -520,6 +677,20 @@ describe "Marshal.dump" do
zone = ":\tzoneI\"\bUTC\x06:\x06EF" # Last is 'F' (US-ASCII)
dump.should == "\x04\bIu:\tTime\r#{@utc_dump}\x06#{zone}"
end
+
+ it "ignores overridden name method" do
+ obj = MarshalSpec::TimeWithOverriddenName.new
+ Marshal.dump(obj).should include("MarshalSpec::TimeWithOverriddenName")
+ end
+
+ it "dumps a Time subclass with multibyte characters in name" do
+ source_object = eval("MarshalSpec::MultibyteぁあぃいTime".force_encoding(Encoding::UTF_8))
+ Marshal.dump(source_object).should == "\x04\bc+MarshalSpec::Multibyte\xE3\x81\x81\xE3\x81\x82\xE3\x81\x83\xE3\x81\x84Time"
+ end
+
+ it "raises TypeError with an anonymous Time subclass" do
+ -> { Marshal.dump(Class.new(Time).now) }.should raise_error(TypeError)
+ end
end
describe "with an Exception" do
@@ -560,6 +731,23 @@ describe "Marshal.dump" do
reloaded.cause.should be_an_instance_of(StandardError)
reloaded.cause.message.should == "the cause"
end
+
+ # NoMethodError uses an exception formatter on TruffleRuby and computes a message lazily
+ it "dumps the message for the raised NoMethodError exception" do
+ begin
+ "".foo
+ rescue => e
+ end
+
+ Marshal.dump(e).should =~ /undefined method `foo' for ("":String|an instance of String)/
+ end
+
+ it "raises TypeError if an Object is an instance of an anonymous class" do
+ anonymous_class = Class.new(Exception)
+ obj = anonymous_class.new
+
+ -> { Marshal.dump(obj) }.should raise_error(TypeError, /can't dump anonymous class/)
+ end
end
it "dumps subsequent appearances of a symbol as a link" do
diff --git a/spec/ruby/core/marshal/fixtures/marshal_data.rb b/spec/ruby/core/marshal/fixtures/marshal_data.rb
index 9373ef7ba8..680cb08ac7 100644
--- a/spec/ruby/core/marshal/fixtures/marshal_data.rb
+++ b/spec/ruby/core/marshal/fixtures/marshal_data.rb
@@ -78,6 +78,22 @@ class UserDefinedImmediate
end
end
+class UserDefinedString
+ attr_reader :string
+
+ def initialize(string)
+ @string = string
+ end
+
+ def _dump(depth)
+ @string
+ end
+
+ def self._load(data)
+ new(data)
+ end
+end
+
class UserPreviouslyDefinedWithInitializedIvar
attr_accessor :field1, :field2
end
@@ -167,12 +183,17 @@ module MarshalSpec
end
end
+ StructToDump = Struct.new(:a, :b)
+
class BasicObjectSubWithRespondToFalse < BasicObject
def respond_to?(method_name, include_all=false)
false
end
end
+ module ModuleToExtendBy
+ end
+
def self.random_data
randomizer = Random.new(42)
1000.times{randomizer.rand} # Make sure we exhaust his first state of 624 random words
@@ -192,6 +213,81 @@ module MarshalSpec
set_swapped_class(nil)
end
+ class ClassWithOverriddenName
+ def self.name
+ "Foo"
+ end
+ end
+
+ class ModuleWithOverriddenName
+ def self.name
+ "Foo"
+ end
+ end
+
+ class TimeWithOverriddenName < Time
+ def self.name
+ "Foo"
+ end
+ end
+
+ class StructWithOverriddenName < Struct.new(:a)
+ def self.name
+ "Foo"
+ end
+ end
+
+ class UserDefinedWithOverriddenName < UserDefined
+ def self.name
+ "Foo"
+ end
+ end
+
+ class StringWithOverriddenName < String
+ def self.name
+ "Foo"
+ end
+ end
+
+ class ArrayWithOverriddenName < Array
+ def self.name
+ "Foo"
+ end
+ end
+
+ class HashWithOverriddenName < Hash
+ def self.name
+ "Foo"
+ end
+ end
+
+ class RegexpWithOverriddenName < Regexp
+ def self.name
+ "Foo"
+ end
+ end
+
+ module_eval(<<~ruby.force_encoding(Encoding::UTF_8))
+ class MultibyteぁあぃいClass
+ end
+
+ module MultibyteけげこごModule
+ end
+
+ class MultibyteぁあぃいTime < Time
+ end
+ ruby
+
+ class ObjectWithFreezeRaisingException < Object
+ def freeze
+ raise
+ end
+ end
+
+ class ObjectWithoutFreeze < Object
+ undef freeze
+ end
+
DATA = {
"nil" => [nil, "\004\b0"],
"1..2" => [(1..2),
diff --git a/spec/ruby/core/marshal/shared/load.rb b/spec/ruby/core/marshal/shared/load.rb
index 08261e65d7..74e21995ec 100644
--- a/spec/ruby/core/marshal/shared/load.rb
+++ b/spec/ruby/core/marshal/shared/load.rb
@@ -54,22 +54,77 @@ describe :marshal_load, shared: true do
regexp.should.frozen?
end
+ it "returns frozen structs" do
+ struct = Marshal.send(@method, Marshal.dump(MarshalSpec::StructToDump.new(1, 2)), freeze: true)
+ struct.should == MarshalSpec::StructToDump.new(1, 2)
+ struct.should.frozen?
+ end
+
it "returns frozen objects" do
source_object = Object.new
- source_object.instance_variable_set(:@foo, "bar")
object = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
object.should.frozen?
- object.instance_variable_get(:@foo).should.frozen?
+ end
+
+ describe "deep freezing" do
+ it "returns hashes with frozen keys and values" do
+ key = Object.new
+ value = Object.new
+ source_object = {key => value}
+
+ hash = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
+ hash.size.should == 1
+ hash.keys[0].should.frozen?
+ hash.values[0].should.frozen?
+ end
+
+ it "returns arrays with frozen elements" do
+ object = Object.new
+ source_object = [object]
+
+ array = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
+ array.size.should == 1
+ array[0].should.frozen?
+ end
+
+ it "returns structs with frozen members" do
+ object1 = Object.new
+ object2 = Object.new
+ source_object = MarshalSpec::StructToDump.new(object1, object2)
+
+ struct = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
+ struct.a.should.frozen?
+ struct.b.should.frozen?
+ end
+
+ it "returns objects with frozen instance variables" do
+ source_object = Object.new
+ instance_variable = Object.new
+ source_object.instance_variable_set(:@a, instance_variable)
+
+ object = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
+ object.instance_variable_get(:@a).should != nil
+ object.instance_variable_get(:@a).should.frozen?
+ end
+
+ it "deduplicates frozen strings" do
+ source_object = ["foo" + "bar", "foobar"]
+ object = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
+
+ object[0].should equal(object[1])
+ end
end
it "does not freeze modules" do
- Marshal.send(@method, Marshal.dump(Kernel), freeze: true)
+ object = Marshal.send(@method, Marshal.dump(Kernel), freeze: true)
+ object.should_not.frozen?
Kernel.should_not.frozen?
end
it "does not freeze classes" do
- Marshal.send(@method, Marshal.dump(Object), freeze: true)
+ object = Marshal.send(@method, Marshal.dump(Object), freeze: true)
+ object.should_not.frozen?
Object.should_not.frozen?
end
@@ -85,6 +140,48 @@ describe :marshal_load, shared: true do
end
end
+ ruby_bug "#19427", "3.1"..."3.3" do
+ ruby_bug "#19427", "3.1"..."3.4" do # https://bugs.ruby-lang.org/issues/19427#note-15
+ it "returns frozen object having #_dump method" do
+ object = Marshal.send(@method, Marshal.dump(UserDefined.new), freeze: true)
+ object.should.frozen?
+ end
+
+ it "returns frozen object responding to #marshal_dump and #marshal_load" do
+ object = Marshal.send(@method, Marshal.dump(UserMarshal.new), freeze: true)
+ object.should.frozen?
+ end
+ end
+
+ it "returns frozen object extended by a module" do
+ object = Object.new
+ object.extend(MarshalSpec::ModuleToExtendBy)
+
+ object = Marshal.send(@method, Marshal.dump(object), freeze: true)
+ object.should.frozen?
+ end
+ end
+
+ it "does not call freeze method" do
+ object = MarshalSpec::ObjectWithFreezeRaisingException.new
+ object = Marshal.send(@method, Marshal.dump(object), freeze: true)
+ object.should.frozen?
+ end
+
+ it "returns frozen object even if object does not respond to freeze method" do
+ object = MarshalSpec::ObjectWithoutFreeze.new
+ object = Marshal.send(@method, Marshal.dump(object), freeze: true)
+ object.should.frozen?
+ end
+
+ it "returns a frozen object when is an instance of String/Array/Regexp/Hash subclass and has instance variables" do
+ source_object = UserString.new
+ source_object.instance_variable_set(:@foo, "bar")
+
+ object = Marshal.send(@method, Marshal.dump(source_object), freeze: true)
+ object.should.frozen?
+ end
+
describe "when called with a proc" do
it "call the proc with frozen objects" do
arr = []
@@ -219,7 +316,19 @@ describe :marshal_load, shared: true do
marshaled_obj.field2.should be_nil
end
- describe "that return an immediate value" do
+ it "loads the String in non US-ASCII and non UTF-8 encoding" do
+ source_object = UserDefinedString.new("a".encode("windows-1251"))
+ object = Marshal.send(@method, Marshal.dump(source_object))
+ object.string.should == "a".encode("windows-1251")
+ end
+
+ it "loads the String in multibyte encoding" do
+ source_object = UserDefinedString.new("a".encode("utf-32le"))
+ object = Marshal.send(@method, Marshal.dump(source_object))
+ object.string.should == "a".encode("utf-32le")
+ end
+
+ describe "that returns an immediate value" do
it "loads an array containing an instance of the object, followed by multiple instances of another object" do
str = "string"
@@ -418,6 +527,38 @@ describe :marshal_load, shared: true do
unmarshalled.instance_variable_get(:@hash_ivar).should == 'hash ivar'
unmarshalled[:key].instance_variable_get(:@string_ivar).should == 'string ivar'
end
+
+ ruby_version_is "3.1" do
+ it "preserves compare_by_identity behaviour" do
+ h = { a: 1 }
+ h.compare_by_identity
+ unmarshalled = Marshal.send(@method, Marshal.dump(h))
+ unmarshalled.should.compare_by_identity?
+
+ h = { a: 1 }
+ unmarshalled = Marshal.send(@method, Marshal.dump(h))
+ unmarshalled.should_not.compare_by_identity?
+ end
+
+ it "preserves compare_by_identity behaviour for a Hash subclass" do
+ h = UserHash.new(a: 1)
+ h.compare_by_identity
+ unmarshalled = Marshal.send(@method, Marshal.dump(h))
+ unmarshalled.should.compare_by_identity?
+
+ h = UserHash.new(a: 1)
+ unmarshalled = Marshal.send(@method, Marshal.dump(h))
+ unmarshalled.should_not.compare_by_identity?
+ end
+ end
+
+ it "allocates an instance of the proper class when Hash subclass with compare_by_identity behaviour" do
+ h = UserHash.new(a: 1)
+ h.compare_by_identity
+
+ unmarshalled = Marshal.send(@method, Marshal.dump(h))
+ unmarshalled.should.kind_of?(UserHash)
+ end
end
describe "for a Symbol" do
@@ -499,6 +640,12 @@ describe :marshal_load, shared: true do
Marshal.send(@method, StringIO.new(Marshal.dump(obj))).should == obj
end
+ it "sets binmode if it is loading through StringIO stream" do
+ io = StringIO.new("\004\b:\vsymbol")
+ def io.binmode; raise "binmode"; end
+ -> { Marshal.load(io) }.should raise_error(RuntimeError, "binmode")
+ end
+
it "loads a string with an ivar" do
str = Marshal.send(@method, "\x04\bI\"\x00\x06:\t@fooI\"\bbar\x06:\x06EF")
str.instance_variable_get("@foo").should == "bar"
@@ -732,7 +879,7 @@ describe :marshal_load, shared: true do
[Meths, MethsMore, Regexp]
end
- it "loads a extended_user_regexp having ivar" do
+ it "loads a Regexp subclass instance variables when it is extended with a module" do
obj = UserRegexp.new('').extend(Meths)
obj.instance_variable_set(:@noise, 'much')
@@ -755,6 +902,14 @@ describe :marshal_load, shared: true do
new_obj.instance_variable_get(:@regexp_ivar).should == [42]
end
end
+
+ it "preserves Regexp encoding" do
+ source_object = Regexp.new("a".encode("utf-32le"))
+ regexp = Marshal.send(@method, Marshal.dump(source_object))
+
+ regexp.encoding.should == Encoding::UTF_32LE
+ regexp.source.should == "a".encode("utf-32le")
+ end
end
describe "for a Float" do
@@ -888,17 +1043,47 @@ describe :marshal_load, shared: true do
t1.should equal t2
end
- it "loads the zone" do
+ it "keeps the local zone" do
with_timezone 'AST', 3 do
t = Time.local(2012, 1, 1)
Marshal.send(@method, Marshal.dump(t)).zone.should == t.zone
end
end
- it "loads nanoseconds" do
+ it "keeps UTC zone" do
+ t = Time.now.utc
+ t2 = Marshal.send(@method, Marshal.dump(t))
+ t2.should.utc?
+ end
+
+ it "keeps the zone" do
+ t = nil
+
+ with_timezone 'AST', 4 do
+ t = Time.local(2012, 1, 1)
+ end
+
+ with_timezone 'EET', -2 do
+ Marshal.send(@method, Marshal.dump(t)).zone.should == 'AST'
+ end
+ end
+
+ it "keeps utc offset" do
+ t = Time.new(2007,11,1,15,25,0, "+09:00")
+ t2 = Marshal.send(@method, Marshal.dump(t))
+ t2.utc_offset.should == 32400
+ end
+
+ it "keeps nanoseconds" do
t = Time.now
Marshal.send(@method, Marshal.dump(t)).nsec.should == t.nsec
end
+
+ it "does not add any additional instance variable" do
+ t = Time.now
+ t2 = Marshal.send(@method, Marshal.dump(t))
+ t2.instance_variables.should.empty?
+ end
end
describe "for nil" do
diff --git a/spec/ruby/core/matchdata/element_reference_spec.rb b/spec/ruby/core/matchdata/element_reference_spec.rb
index 7c0f089bb4..0e0d3991cb 100644
--- a/spec/ruby/core/matchdata/element_reference_spec.rb
+++ b/spec/ruby/core/matchdata/element_reference_spec.rb
@@ -22,6 +22,11 @@ describe "MatchData#[]" do
# length argument larger than number of match values is capped to match value length
/(.)(.)(\d+)(\d)/.match("THX1138.")[3, 10].should == %w|113 8|
+
+ /(.)(.)(\d+)(\d)/.match("THX1138.")[3, 0].should == []
+
+ /(.)(.)(\d+)(\d)/.match("THX1138.")[3, -1].should == nil
+ /(.)(.)(\d+)(\d)/.match("THX1138.")[3, -30].should == nil
end
it "supports ranges [start..end]" do
diff --git a/spec/ruby/core/math/cos_spec.rb b/spec/ruby/core/math/cos_spec.rb
index 3ba7a54c38..006afeb2cc 100644
--- a/spec/ruby/core/math/cos_spec.rb
+++ b/spec/ruby/core/math/cos_spec.rb
@@ -15,7 +15,6 @@ describe "Math.cos" do
Math.cos(2*Math::PI).should be_close(1.0, TOLERANCE)
end
-
it "raises a TypeError unless the argument is Numeric and has #to_f" do
-> { Math.cos("test") }.should raise_error(TypeError)
end
@@ -24,14 +23,23 @@ describe "Math.cos" do
Math.cos(nan_value).nan?.should be_true
end
- it "raises a TypeError if the argument is nil" do
- -> { Math.cos(nil) }.should raise_error(TypeError)
- end
-
- it "coerces its argument with #to_f" do
- f = mock_numeric('8.2')
- f.should_receive(:to_f).and_return(8.2)
- Math.cos(f).should == Math.cos(8.2)
+ describe "coerces its argument with #to_f" do
+ it "coerces its argument with #to_f" do
+ f = mock_numeric('8.2')
+ f.should_receive(:to_f).and_return(8.2)
+ Math.cos(f).should == Math.cos(8.2)
+ end
+
+ it "raises a TypeError if the given argument can't be converted to a Float" do
+ -> { Math.cos(nil) }.should raise_error(TypeError)
+ -> { Math.cos(:abc) }.should raise_error(TypeError)
+ end
+
+ it "raises a NoMethodError if the given argument raises a NoMethodError during type coercion to a Float" do
+ object = mock_numeric('mock-float')
+ object.should_receive(:to_f).and_raise(NoMethodError)
+ -> { Math.cos(object) }.should raise_error(NoMethodError)
+ end
end
end
diff --git a/spec/ruby/core/method/parameters_spec.rb b/spec/ruby/core/method/parameters_spec.rb
index e6d51d1b4d..0f730fe013 100644
--- a/spec/ruby/core/method/parameters_spec.rb
+++ b/spec/ruby/core/method/parameters_spec.rb
@@ -20,6 +20,8 @@ describe "Method#parameters" do
local_is_not_parameter = {}
end
+ def underscore_parameters(_, _, _ = 1, *_, _:, _: 2, **_, &_); end
+
define_method(:one_optional_defined_method) {|x = 1|}
end
@@ -251,6 +253,20 @@ describe "Method#parameters" do
m.method(:writer=).parameters.should == [[:req]]
end
+ it "returns all parameters defined with the name _ as _" do
+ m = MethodSpecs::Methods.instance_method(:underscore_parameters)
+ m.parameters.should == [
+ [:req, :_],
+ [:req, :_],
+ [:opt, :_],
+ [:rest, :_],
+ [:keyreq, :_],
+ [:key, :_],
+ [:keyrest, :_],
+ [:block, :_]
+ ]
+ end
+
it "returns [[:rest]] for core methods with variable-length argument lists" do
# delete! takes rest args
"foo".method(:delete!).parameters.should == [[:rest]]
diff --git a/spec/ruby/core/module/alias_method_spec.rb b/spec/ruby/core/module/alias_method_spec.rb
index 5d3d0c23d9..391efa227a 100644
--- a/spec/ruby/core/module/alias_method_spec.rb
+++ b/spec/ruby/core/module/alias_method_spec.rb
@@ -81,6 +81,12 @@ describe "Module#alias_method" do
-> { @class.make_alias mock('x'), :public_one }.should raise_error(TypeError)
end
+ it "raises a NoMethodError if the given name raises a NoMethodError during type coercion using to_str" do
+ obj = mock("mock-name")
+ obj.should_receive(:to_str).and_raise(NoMethodError)
+ -> { @class.make_alias obj, :public_one }.should raise_error(NoMethodError)
+ end
+
it "is a public method" do
Module.should have_public_instance_method(:alias_method, false)
end
diff --git a/spec/ruby/core/module/const_defined_spec.rb b/spec/ruby/core/module/const_defined_spec.rb
index 0c15629c08..027cf5a245 100644
--- a/spec/ruby/core/module/const_defined_spec.rb
+++ b/spec/ruby/core/module/const_defined_spec.rb
@@ -80,10 +80,23 @@ describe "Module#const_defined?" do
ConstantSpecs::ClassA.const_defined?(:CS_CONSTX).should == false
end
- it "calls #to_str to convert the given name to a String" do
- name = mock("ClassA")
- name.should_receive(:to_str).and_return("ClassA")
- ConstantSpecs.const_defined?(name).should == true
+ describe "converts the given name to a String using #to_str" do
+ it "calls #to_str to convert the given name to a String" do
+ name = mock("ClassA")
+ name.should_receive(:to_str).and_return("ClassA")
+ ConstantSpecs.const_defined?(name).should == true
+ end
+
+ it "raises a TypeError if the given name can't be converted to a String" do
+ -> { ConstantSpecs.const_defined?(nil) }.should raise_error(TypeError)
+ -> { ConstantSpecs.const_defined?([]) }.should raise_error(TypeError)
+ end
+
+ it "raises a NoMethodError if the given argument raises a NoMethodError during type coercion to a String" do
+ name = mock("classA")
+ name.should_receive(:to_str).and_raise(NoMethodError)
+ -> { ConstantSpecs.const_defined?(name) }.should raise_error(NoMethodError)
+ end
end
it "special cases Object and checks it's included Modules" do
diff --git a/spec/ruby/core/module/refine_spec.rb b/spec/ruby/core/module/refine_spec.rb
index 841900cf87..11085c325b 100644
--- a/spec/ruby/core/module/refine_spec.rb
+++ b/spec/ruby/core/module/refine_spec.rb
@@ -71,7 +71,7 @@ describe "Module#refine" do
Module.new do
refine("foo") {}
end
- end.should raise_error(TypeError)
+ end.should raise_error(TypeError, "wrong argument type String (expected Class or Module)")
end
it "accepts a module as argument" do
diff --git a/spec/ruby/core/proc/parameters_spec.rb b/spec/ruby/core/proc/parameters_spec.rb
index 3a56b613cd..1ffaf17315 100644
--- a/spec/ruby/core/proc/parameters_spec.rb
+++ b/spec/ruby/core/proc/parameters_spec.rb
@@ -115,4 +115,30 @@ describe "Proc#parameters" do
local_is_not_parameter = {}
end.parameters.should == [[:rest, :args], [:block, :blk]]
end
+
+ it "returns all parameters defined with the name _ as _" do
+ proc = proc {|_, _, _ = 1, *_, _:, _: 2, **_, &_| }
+ proc.parameters.should == [
+ [:opt, :_],
+ [:opt, :_],
+ [:opt, :_],
+ [:rest, :_],
+ [:keyreq, :_],
+ [:key, :_],
+ [:keyrest, :_],
+ [:block, :_]
+ ]
+
+ lambda = -> _, _, _ = 1, *_, _:, _: 2, **_, &_ {}
+ lambda.parameters.should == [
+ [:req, :_],
+ [:req, :_],
+ [:opt, :_],
+ [:rest, :_],
+ [:keyreq, :_],
+ [:key, :_],
+ [:keyrest, :_],
+ [:block, :_]
+ ]
+ end
end
diff --git a/spec/ruby/core/process/argv0_spec.rb b/spec/ruby/core/process/argv0_spec.rb
new file mode 100644
index 0000000000..0d02248b6d
--- /dev/null
+++ b/spec/ruby/core/process/argv0_spec.rb
@@ -0,0 +1,23 @@
+require_relative '../../spec_helper'
+
+describe "Process.argv0" do
+ it "returns a String" do
+ Process.argv0.should be_kind_of(String)
+ end
+
+ it "is the path given as the main script and the same as __FILE__" do
+ script = "fixtures/argv0.rb"
+
+ Dir.chdir(File.dirname(__FILE__)) do
+ ruby_exe(script).should == "#{script}\n#{script}\nOK"
+ end
+ end
+
+ it "returns a non frozen object" do
+ Process.argv0.should_not.frozen?
+ end
+
+ it "returns every time the same object" do
+ Process.argv0.should.equal?(Process.argv0)
+ end
+end
diff --git a/spec/ruby/core/process/fixtures/argv0.rb b/spec/ruby/core/process/fixtures/argv0.rb
new file mode 100644
index 0000000000..847a3e903e
--- /dev/null
+++ b/spec/ruby/core/process/fixtures/argv0.rb
@@ -0,0 +1,6 @@
+puts Process.argv0
+puts __FILE__
+
+if Process.argv0 == __FILE__
+ print "OK"
+end
diff --git a/spec/ruby/core/queue/initialize_spec.rb b/spec/ruby/core/queue/initialize_spec.rb
index c45abcd29d..c6c1ae63c5 100644
--- a/spec/ruby/core/queue/initialize_spec.rb
+++ b/spec/ruby/core/queue/initialize_spec.rb
@@ -22,16 +22,29 @@ describe "Queue#initialize" do
q.should.empty?
end
- it "uses #to_a on the provided Enumerable" do
- enumerable = MockObject.new('mock-enumerable')
- enumerable.should_receive(:to_a).and_return([1, 2, 3])
- q = Queue.new(enumerable)
- q.size.should == 3
- q.should_not.empty?
- q.pop.should == 1
- q.pop.should == 2
- q.pop.should == 3
- q.should.empty?
+ describe "converts the given argument to an Array using #to_a" do
+ it "uses #to_a on the provided Enumerable" do
+ enumerable = MockObject.new('mock-enumerable')
+ enumerable.should_receive(:to_a).and_return([1, 2, 3])
+ q = Queue.new(enumerable)
+ q.size.should == 3
+ q.should_not.empty?
+ q.pop.should == 1
+ q.pop.should == 2
+ q.pop.should == 3
+ q.should.empty?
+ end
+
+ it "raises a TypeError if the given argument can't be converted to an Array" do
+ -> { Queue.new(42) }.should raise_error(TypeError)
+ -> { Queue.new(:abc) }.should raise_error(TypeError)
+ end
+
+ it "raises a NoMethodError if the given argument raises a NoMethodError during type coercion to an Array" do
+ enumerable = MockObject.new('mock-enumerable')
+ enumerable.should_receive(:to_a).and_raise(NoMethodError)
+ -> { Queue.new(enumerable) }.should raise_error(NoMethodError)
+ end
end
it "raises TypeError if the provided Enumerable does not respond to #to_a" do
diff --git a/spec/ruby/core/range/size_spec.rb b/spec/ruby/core/range/size_spec.rb
index 9b625c9963..81ea5a3846 100644
--- a/spec/ruby/core/range/size_spec.rb
+++ b/spec/ruby/core/range/size_spec.rb
@@ -44,12 +44,12 @@ describe "Range#size" do
end
ruby_version_is "3.2" do
- it 'returns Float::INFINITY for all beginless ranges if the start is numeric' do
+ it 'returns Float::INFINITY for all beginless ranges if the end is numeric' do
(..1).size.should == Float::INFINITY
(...0.5).size.should == Float::INFINITY
end
- it 'returns nil for all beginless ranges if the start is numeric' do
+ it 'returns nil for all beginless ranges if the end is not numeric' do
(...'o').size.should == nil
end
diff --git a/spec/ruby/core/refinement/fixtures/classes.rb b/spec/ruby/core/refinement/fixtures/classes.rb
new file mode 100644
index 0000000000..94324db47c
--- /dev/null
+++ b/spec/ruby/core/refinement/fixtures/classes.rb
@@ -0,0 +1,10 @@
+module RefinementSpec
+
+ module ModuleWithAncestors
+ include Module.new do
+ def indent(level)
+ " " * level + self
+ end
+ end
+ end
+end
diff --git a/spec/ruby/core/refinement/import_methods_spec.rb b/spec/ruby/core/refinement/import_methods_spec.rb
index 1c526f5822..05973b2380 100644
--- a/spec/ruby/core/refinement/import_methods_spec.rb
+++ b/spec/ruby/core/refinement/import_methods_spec.rb
@@ -1,4 +1,5 @@
require_relative '../../spec_helper'
+require_relative 'fixtures/classes'
describe "Refinement#import_methods" do
ruby_version_is "3.1" do
@@ -17,6 +18,229 @@ describe "Refinement#import_methods" do
end
end
end
+
+ it "throws an exception when argument is not a module" do
+ Module.new do
+ refine String do
+ -> {
+ import_methods Integer
+ }.should raise_error(TypeError, "wrong argument type Class (expected Module)")
+ end
+ end
+ end
+
+ it "imports methods from multiple modules" do
+ str_utils = Module.new do
+ def indent(level)
+ " " * level + self
+ end
+ end
+
+ str_utils_fancy = Module.new do
+ def indent_star(level)
+ "*" * level + self
+ end
+ end
+
+ Module.new do
+ refine String do
+ import_methods str_utils, str_utils_fancy
+ "foo".indent(3).should == " foo"
+ "foo".indent_star(3).should == "***foo"
+ end
+ end
+ end
+
+ it "imports a method defined in the last module if method with same name is defined in multiple modules" do
+ str_utils = Module.new do
+ def indent(level)
+ " " * level + self
+ end
+ end
+
+ str_utils_fancy = Module.new do
+ def indent(level)
+ "*" * level + self
+ end
+ end
+
+ Module.new do
+ refine String do
+ import_methods str_utils, str_utils_fancy
+ "foo".indent(3).should == "***foo"
+ end
+ end
+ end
+
+ it "still imports methods of modules listed before a module that contains method not defined in Ruby" do
+ str_utils = Module.new do
+ def indent(level)
+ " " * level + self
+ end
+ end
+
+ string_refined = Module.new do
+ refine String do
+ -> {
+ import_methods str_utils, Kernel
+ }.should raise_error(ArgumentError)
+ end
+ end
+
+ Module.new do
+ using string_refined
+ "foo".indent(3).should == " foo"
+ end
+ end
+ end
+
+ it "warns if a module includes/prepends some other module" do
+ module1 = Module.new do
+ end
+
+ module2 = Module.new do
+ include module1
+ end
+
+ Module.new do
+ refine String do
+ -> {
+ import_methods module2
+ }.should complain(/warning: #<Module:\w*> has ancestors, but Refinement#import_methods doesn't import their methods/)
+ end
+ end
+
+ Module.new do
+ refine String do
+ -> {
+ import_methods RefinementSpec::ModuleWithAncestors
+ }.should complain(/warning: RefinementSpec::ModuleWithAncestors has ancestors, but Refinement#import_methods doesn't import their methods/)
+ end
+ end
+ end
+
+ it "doesn't import methods from included/prepended modules" do
+ Module.new do
+ refine String do
+ suppress_warning { import_methods RefinementSpec::ModuleWithAncestors }
+ end
+
+ using self
+ -> {
+ "foo".indent(3)
+ }.should raise_error(NoMethodError, /undefined method `indent' for ("foo":String|an instance of String)/)
+ end
+ end
+
+ it "doesn't import any methods if one of the arguments is not a module" do
+ str_utils = Module.new do
+ def indent(level)
+ " " * level + self
+ end
+ end
+
+ string_refined = Module.new do
+ refine String do
+ -> {
+ import_methods str_utils, Integer
+ }.should raise_error(TypeError)
+ end
+ end
+
+ Module.new do
+ using string_refined
+ -> {
+ "foo".indent(3)
+ }.should raise_error(NoMethodError)
+ end
+ end
+
+ it "imports methods from multiple modules so that methods see other's module's methods" do
+ str_utils = Module.new do
+ def indent(level)
+ " " * level + self
+ end
+ end
+
+ str_utils_normal = Module.new do
+ def indent_normal(level)
+ self.indent(level)
+ end
+ end
+
+ Module.new do
+ refine String do
+ import_methods str_utils, str_utils_normal
+ end
+
+ using self
+ "foo".indent_normal(3).should == " foo"
+ end
+ end
+
+ it "imports methods from module so that methods can see each other" do
+ str_utils = Module.new do
+ def indent(level)
+ " " * level + self
+ end
+
+ def indent_with_dot(level)
+ self.indent(level) + "."
+ end
+ end
+
+ Module.new do
+ refine String do
+ import_methods str_utils
+ end
+
+ using self
+ "foo".indent_with_dot(3).should == " foo."
+ end
+ end
+
+ it "doesn't import module's class methods" do
+ str_utils = Module.new do
+ def self.indent(level)
+ " " * level + self
+ end
+ end
+
+ Module.new do
+ refine String do
+ import_methods str_utils
+ end
+
+ using self
+ -> {
+ String.indent(3)
+ }.should raise_error(NoMethodError, /undefined method `indent' for (String:Class|class String)/)
+ end
+ end
+
+ it "imports module methods with super" do
+ class_to_refine = Class.new do
+ def foo(number)
+ 2 * number
+ end
+ end
+
+ extension = Module.new do
+ def foo(number)
+ super * 2
+ end
+ end
+
+ refinement = Module.new do
+ refine class_to_refine do
+ import_methods extension
+ end
+ end
+
+ Module.new do
+ using refinement
+ class_to_refine.new.foo(2).should == 8
+ end
end
context "when methods are not defined in Ruby code" do
@@ -29,6 +253,17 @@ describe "Refinement#import_methods" do
end
end
end
+
+ it "raises ArgumentError when importing methods from C extension" do
+ require 'zlib'
+ Module.new do
+ refine String do
+ -> {
+ import_methods Zlib
+ }.should raise_error(ArgumentError, /Can't import method which is not defined with Ruby code: Zlib#*/)
+ end
+ end
+ end
end
end
end
diff --git a/spec/ruby/core/regexp/shared/new.rb b/spec/ruby/core/regexp/shared/new.rb
index 058a51b1aa..773882e495 100644
--- a/spec/ruby/core/regexp/shared/new.rb
+++ b/spec/ruby/core/regexp/shared/new.rb
@@ -432,6 +432,10 @@ describe :regexp_new_string, shared: true do
Regexp.send(@method, "\056\x42\u3042\x52\076").should == /#{"\x2e\x42\u3042\x52\x3e"}/
end
+ it "accepts a multiple byte character which need not be escaped" do
+ Regexp.send(@method, "\�").should == /#{"�"}/
+ end
+
it "raises a RegexpError if less than four digits are given for \\uHHHH" do
-> { Regexp.send(@method, "\\" + "u304") }.should raise_error(RegexpError)
end
diff --git a/spec/ruby/core/regexp/try_convert_spec.rb b/spec/ruby/core/regexp/try_convert_spec.rb
index be567e2130..e775dbe971 100644
--- a/spec/ruby/core/regexp/try_convert_spec.rb
+++ b/spec/ruby/core/regexp/try_convert_spec.rb
@@ -18,4 +18,10 @@ describe "Regexp.try_convert" do
rex.should_receive(:to_regexp).and_return(/(p(a)t[e]rn)/)
Regexp.try_convert(rex).should == /(p(a)t[e]rn)/
end
+
+ it "raises a TypeError if the object does not return an Regexp from #to_regexp" do
+ obj = mock("regexp")
+ obj.should_receive(:to_regexp).and_return("string")
+ -> { Regexp.try_convert(obj) }.should raise_error(TypeError, "can't convert MockObject to Regexp (MockObject#to_regexp gives String)")
+ end
end
diff --git a/spec/ruby/core/string/append_spec.rb b/spec/ruby/core/string/append_spec.rb
index e001257621..8497ce8262 100644
--- a/spec/ruby/core/string/append_spec.rb
+++ b/spec/ruby/core/string/append_spec.rb
@@ -5,6 +5,7 @@ require_relative 'shared/concat'
describe "String#<<" do
it_behaves_like :string_concat, :<<
it_behaves_like :string_concat_encoding, :<<
+ it_behaves_like :string_concat_type_coercion, :<<
it "raises an ArgumentError when given the incorrect number of arguments" do
-> { "hello".send(:<<) }.should raise_error(ArgumentError)
diff --git a/spec/ruby/core/string/concat_spec.rb b/spec/ruby/core/string/concat_spec.rb
index 5f6daadad7..6f487eaa3a 100644
--- a/spec/ruby/core/string/concat_spec.rb
+++ b/spec/ruby/core/string/concat_spec.rb
@@ -5,6 +5,7 @@ require_relative 'shared/concat'
describe "String#concat" do
it_behaves_like :string_concat, :concat
it_behaves_like :string_concat_encoding, :concat
+ it_behaves_like :string_concat_type_coercion, :concat
it "takes multiple arguments" do
str = "hello "
diff --git a/spec/ruby/core/string/plus_spec.rb b/spec/ruby/core/string/plus_spec.rb
index 5ff198f07e..9da17451c6 100644
--- a/spec/ruby/core/string/plus_spec.rb
+++ b/spec/ruby/core/string/plus_spec.rb
@@ -3,6 +3,9 @@ require_relative 'fixtures/classes'
require_relative 'shared/concat'
describe "String#+" do
+ it_behaves_like :string_concat_encoding, :+
+ it_behaves_like :string_concat_type_coercion, :+
+
it "returns a new string containing the given string concatenated to self" do
("" + "").should == ""
("" + "Hello").should == "Hello"
@@ -31,6 +34,4 @@ describe "String#+" do
("hello" + StringSpecs::MyString.new("foo")).should be_an_instance_of(String)
("hello" + StringSpecs::MyString.new("")).should be_an_instance_of(String)
end
-
- it_behaves_like :string_concat_encoding, :+
end
diff --git a/spec/ruby/core/string/shared/concat.rb b/spec/ruby/core/string/shared/concat.rb
index 54ac1035d3..ee5ef2a98f 100644
--- a/spec/ruby/core/string/shared/concat.rb
+++ b/spec/ruby/core/string/shared/concat.rb
@@ -5,18 +5,6 @@ describe :string_concat, shared: true do
str.should == "hello world"
end
- it "converts the given argument to a String using to_str" do
- obj = mock('world!')
- obj.should_receive(:to_str).and_return("world!")
- a = 'hello '.send(@method, obj)
- a.should == 'hello world!'
- end
-
- it "raises a TypeError if the given argument can't be converted to a String" do
- -> { 'hello '.send(@method, []) }.should raise_error(TypeError)
- -> { 'hello '.send(@method, mock('x')) }.should raise_error(TypeError)
- end
-
it "raises a FrozenError when self is frozen" do
a = "hello"
a.freeze
@@ -148,3 +136,23 @@ describe :string_concat_encoding, shared: true do
end
end
end
+
+describe :string_concat_type_coercion, shared: true do
+ it "converts the given argument to a String using to_str" do
+ obj = mock('world!')
+ obj.should_receive(:to_str).and_return("world!")
+ a = 'hello '.send(@method, obj)
+ a.should == 'hello world!'
+ end
+
+ it "raises a TypeError if the given argument can't be converted to a String" do
+ -> { 'hello '.send(@method, []) }.should raise_error(TypeError)
+ -> { 'hello '.send(@method, mock('x')) }.should raise_error(TypeError)
+ end
+
+ it "raises a NoMethodError if the given argument raises a NoMethodError during type coercion to a String" do
+ obj = mock('world!')
+ obj.should_receive(:to_str).and_raise(NoMethodError)
+ -> { 'hello '.send(@method, obj) }.should raise_error(NoMethodError)
+ end
+end
diff --git a/spec/ruby/core/string/try_convert_spec.rb b/spec/ruby/core/string/try_convert_spec.rb
index 84415c4a75..72ce5dd8b2 100644
--- a/spec/ruby/core/string/try_convert_spec.rb
+++ b/spec/ruby/core/string/try_convert_spec.rb
@@ -39,7 +39,7 @@ describe "String.try_convert" do
it "sends #to_str to the argument and raises TypeError if it's not a kind of String" do
obj = mock("to_str")
obj.should_receive(:to_str).and_return(Object.new)
- -> { String.try_convert obj }.should raise_error(TypeError)
+ -> { String.try_convert obj }.should raise_error(TypeError, "can't convert MockObject to String (MockObject#to_str gives Object)")
end
it "does not rescue exceptions raised by #to_str" do
diff --git a/spec/ruby/core/string/unpack/b_spec.rb b/spec/ruby/core/string/unpack/b_spec.rb
index 2cf5ebad34..5c53eff721 100644
--- a/spec/ruby/core/string/unpack/b_spec.rb
+++ b/spec/ruby/core/string/unpack/b_spec.rb
@@ -88,7 +88,9 @@ describe "String#unpack with format 'B'" do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- "\x80\x00".unpack("B\x00B").should == ["1", "0"]
+ suppress_warning do
+ "\x80\x00".unpack("B\x00B").should == ["1", "0"]
+ end
end
end
@@ -194,7 +196,9 @@ describe "String#unpack with format 'b'" do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- "\x01\x00".unpack("b\x00b").should == ["1", "0"]
+ suppress_warning do
+ "\x01\x00".unpack("b\x00b").should == ["1", "0"]
+ end
end
end
diff --git a/spec/ruby/core/string/unpack/c_spec.rb b/spec/ruby/core/string/unpack/c_spec.rb
index dbcbacc74d..c2bf813954 100644
--- a/spec/ruby/core/string/unpack/c_spec.rb
+++ b/spec/ruby/core/string/unpack/c_spec.rb
@@ -37,7 +37,9 @@ describe :string_unpack_8bit, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- "abc".unpack(unpack_format("\000", 2)).should == [97, 98]
+ suppress_warning do
+ "abc".unpack(unpack_format("\000", 2)).should == [97, 98]
+ end
end
end
diff --git a/spec/ruby/core/string/unpack/h_spec.rb b/spec/ruby/core/string/unpack/h_spec.rb
index ee08d20926..19c4d63664 100644
--- a/spec/ruby/core/string/unpack/h_spec.rb
+++ b/spec/ruby/core/string/unpack/h_spec.rb
@@ -58,7 +58,9 @@ describe "String#unpack with format 'H'" do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- "\x01\x10".unpack("H\x00H").should == ["0", "1"]
+ suppress_warning do
+ "\x01\x10".unpack("H\x00H").should == ["0", "1"]
+ end
end
end
@@ -133,7 +135,9 @@ describe "String#unpack with format 'h'" do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- "\x01\x10".unpack("h\x00h").should == ["1", "0"]
+ suppress_warning do
+ "\x01\x10".unpack("h\x00h").should == ["1", "0"]
+ end
end
end
diff --git a/spec/ruby/core/string/unpack/shared/float.rb b/spec/ruby/core/string/unpack/shared/float.rb
index ccddf94f99..93282bf4c9 100644
--- a/spec/ruby/core/string/unpack/shared/float.rb
+++ b/spec/ruby/core/string/unpack/shared/float.rb
@@ -58,8 +58,10 @@ describe :string_unpack_float_le, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- array = "\x9a\x999@33\xb3?".unpack(unpack_format("\000", 2))
- array.should == [2.9000000953674316, 1.399999976158142]
+ suppress_warning do
+ array = "\x9a\x999@33\xb3?".unpack(unpack_format("\000", 2))
+ array.should == [2.9000000953674316, 1.399999976158142]
+ end
end
end
@@ -135,8 +137,10 @@ describe :string_unpack_float_be, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- array = "@9\x99\x9a?\xb333".unpack(unpack_format("\000", 2))
- array.should == [2.9000000953674316, 1.399999976158142]
+ suppress_warning do
+ array = "@9\x99\x9a?\xb333".unpack(unpack_format("\000", 2))
+ array.should == [2.9000000953674316, 1.399999976158142]
+ end
end
end
@@ -215,7 +219,9 @@ describe :string_unpack_double_le, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- "333333\x07@ffffff\xf6?".unpack(unpack_format("\000", 2)).should == [2.9, 1.4]
+ suppress_warning do
+ "333333\x07@ffffff\xf6?".unpack(unpack_format("\000", 2)).should == [2.9, 1.4]
+ end
end
end
@@ -293,7 +299,9 @@ describe :string_unpack_double_be, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- "@\x07333333?\xf6ffffff".unpack(unpack_format("\000", 2)).should == [2.9, 1.4]
+ suppress_warning do
+ "@\x07333333?\xf6ffffff".unpack(unpack_format("\000", 2)).should == [2.9, 1.4]
+ end
end
end
diff --git a/spec/ruby/core/string/unpack/shared/integer.rb b/spec/ruby/core/string/unpack/shared/integer.rb
index ba4f149dad..d71a2cf00d 100644
--- a/spec/ruby/core/string/unpack/shared/integer.rb
+++ b/spec/ruby/core/string/unpack/shared/integer.rb
@@ -34,7 +34,9 @@ describe :string_unpack_16bit_le, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- "abcd".unpack(unpack_format("\000", 2)).should == [25185, 25699]
+ suppress_warning do
+ "abcd".unpack(unpack_format("\000", 2)).should == [25185, 25699]
+ end
end
end
@@ -97,7 +99,9 @@ describe :string_unpack_16bit_be, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- "badc".unpack(unpack_format("\000", 2)).should == [25185, 25699]
+ suppress_warning do
+ "badc".unpack(unpack_format("\000", 2)).should == [25185, 25699]
+ end
end
end
@@ -161,7 +165,9 @@ describe :string_unpack_32bit_le, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- "abcdefgh".unpack(unpack_format("\000", 2)).should == [1684234849, 1751606885]
+ suppress_warning do
+ "abcdefgh".unpack(unpack_format("\000", 2)).should == [1684234849, 1751606885]
+ end
end
end
@@ -225,7 +231,9 @@ describe :string_unpack_32bit_be, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- "dcbahgfe".unpack(unpack_format("\000", 2)).should == [1684234849, 1751606885]
+ suppress_warning do
+ "dcbahgfe".unpack(unpack_format("\000", 2)).should == [1684234849, 1751606885]
+ end
end
end
@@ -285,8 +293,10 @@ describe :string_unpack_64bit_le, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- array = "abcdefghabghefcd".unpack(unpack_format("\000", 2))
- array.should == [7523094288207667809, 7233738012216484449]
+ suppress_warning do
+ array = "abcdefghabghefcd".unpack(unpack_format("\000", 2))
+ array.should == [7523094288207667809, 7233738012216484449]
+ end
end
end
@@ -357,8 +367,10 @@ describe :string_unpack_64bit_be, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- array = "hgfedcbadcfehgba".unpack(unpack_format("\000", 2))
- array.should == [7523094288207667809, 7233738012216484449]
+ suppress_warning do
+ array = "hgfedcbadcfehgba".unpack(unpack_format("\000", 2))
+ array.should == [7523094288207667809, 7233738012216484449]
+ end
end
end
diff --git a/spec/ruby/core/string/unpack/shared/unicode.rb b/spec/ruby/core/string/unpack/shared/unicode.rb
index ce1f29fe87..9fe07f53ae 100644
--- a/spec/ruby/core/string/unpack/shared/unicode.rb
+++ b/spec/ruby/core/string/unpack/shared/unicode.rb
@@ -52,7 +52,9 @@ describe :string_unpack_unicode, shared: true do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- "\x01\x02".unpack("U\x00U").should == [1, 2]
+ suppress_warning do
+ "\x01\x02".unpack("U\x00U").should == [1, 2]
+ end
end
end
diff --git a/spec/ruby/core/string/unpack/w_spec.rb b/spec/ruby/core/string/unpack/w_spec.rb
index b213b32921..6a1cff1965 100644
--- a/spec/ruby/core/string/unpack/w_spec.rb
+++ b/spec/ruby/core/string/unpack/w_spec.rb
@@ -17,7 +17,9 @@ describe "String#unpack with directive 'w'" do
ruby_version_is ""..."3.3" do
it "ignores NULL bytes between directives" do
- "\x01\x02\x03".unpack("w\x00w").should == [1, 2]
+ suppress_warning do
+ "\x01\x02\x03".unpack("w\x00w").should == [1, 2]
+ end
end
end
diff --git a/spec/ruby/core/struct/fixtures/classes.rb b/spec/ruby/core/struct/fixtures/classes.rb
index 6d620f9060..bf838d05df 100644
--- a/spec/ruby/core/struct/fixtures/classes.rb
+++ b/spec/ruby/core/struct/fixtures/classes.rb
@@ -13,6 +13,12 @@ module StructClasses
end
end
+ class StructWithOverriddenName < Struct.new(:a)
+ def self.name
+ "A"
+ end
+ end
+
class SubclassX < Struct
end
diff --git a/spec/ruby/core/struct/keyword_init_spec.rb b/spec/ruby/core/struct/keyword_init_spec.rb
index 061f4c56e0..8de4c14351 100644
--- a/spec/ruby/core/struct/keyword_init_spec.rb
+++ b/spec/ruby/core/struct/keyword_init_spec.rb
@@ -17,5 +17,24 @@ ruby_version_is "3.1" do
struct = Struct.new(:arg)
struct.keyword_init?.should be_nil
end
+
+ it "returns nil for a struct that does specify keyword_init to be nil" do
+ struct = Struct.new(:arg, keyword_init: nil)
+ struct.keyword_init?.should be_nil
+ end
+
+ it "returns true for any truthy value, not just for true" do
+ struct = Struct.new(:arg, keyword_init: 1)
+ struct.keyword_init?.should be_true
+
+ struct = Struct.new(:arg, keyword_init: "")
+ struct.keyword_init?.should be_true
+
+ struct = Struct.new(:arg, keyword_init: [])
+ struct.keyword_init?.should be_true
+
+ struct = Struct.new(:arg, keyword_init: {})
+ struct.keyword_init?.should be_true
+ end
end
end
diff --git a/spec/ruby/core/struct/new_spec.rb b/spec/ruby/core/struct/new_spec.rb
index 4aeaa066e1..8758051a81 100644
--- a/spec/ruby/core/struct/new_spec.rb
+++ b/spec/ruby/core/struct/new_spec.rb
@@ -47,6 +47,11 @@ describe "Struct.new" do
Struct.const_defined?("Animal2").should be_false
end
+ it "allows non-ASCII member name" do
+ name = "r\xe9sum\xe9".force_encoding(Encoding::ISO_8859_1).to_sym
+ struct = Struct.new(name)
+ struct.new("foo").send(name).should == "foo"
+ end
it "fails with invalid constant name as first argument" do
-> { Struct.new('animal', :name, :legs, :eyeballs) }.should raise_error(NameError)
diff --git a/spec/ruby/core/struct/shared/inspect.rb b/spec/ruby/core/struct/shared/inspect.rb
index e65a4fb45d..1a0fb6a6b2 100644
--- a/spec/ruby/core/struct/shared/inspect.rb
+++ b/spec/ruby/core/struct/shared/inspect.rb
@@ -25,4 +25,16 @@ describe :struct_inspect, shared: true do
m::Foo.new("").send(@method).should == '#<struct a="">'
end
+
+ it "does not call #name method" do
+ struct = StructClasses::StructWithOverriddenName.new("")
+ struct.send(@method).should == '#<struct StructClasses::StructWithOverriddenName a="">'
+ end
+
+ it "does not call #name method when struct is anonymous" do
+ struct = Struct.new(:a)
+ def struct.name; "A"; end
+
+ struct.new("").send(@method).should == '#<struct a="">'
+ end
end
diff --git a/spec/ruby/core/symbol/inspect_spec.rb b/spec/ruby/core/symbol/inspect_spec.rb
index 58402ab261..6dbb36c2ad 100644
--- a/spec/ruby/core/symbol/inspect_spec.rb
+++ b/spec/ruby/core/symbol/inspect_spec.rb
@@ -5,6 +5,8 @@ describe "Symbol#inspect" do
fred: ":fred",
:fred? => ":fred?",
:fred! => ":fred!",
+ :BAD! => ":BAD!",
+ :_BAD! => ":_BAD!",
:$ruby => ":$ruby",
:@ruby => ":@ruby",
:@@ruby => ":@@ruby",
diff --git a/spec/ruby/core/time/new_spec.rb b/spec/ruby/core/time/new_spec.rb
index 727fdf92c2..69ec7bee5d 100644
--- a/spec/ruby/core/time/new_spec.rb
+++ b/spec/ruby/core/time/new_spec.rb
@@ -431,6 +431,10 @@ describe "Time.new with a timezone argument" do
time.zone.should == nil
end
+ it "returns a Time with UTC offset specified as a single letter military timezone" do
+ Time.new(2000, 1, 1, 0, 0, 0, in: "W").utc_offset.should == 3600 * -10
+ end
+
it "could be a timezone object" do
zone = TimeSpecs::TimezoneWithName.new(name: "Asia/Colombo")
time = Time.new(2000, 1, 1, 12, 0, 0, in: zone)
@@ -445,13 +449,29 @@ describe "Time.new with a timezone argument" do
time.zone.should == zone
end
+ it "allows omitting minor arguments" do
+ Time.new(2000, 1, 1, 12, 1, 1, in: "+05:00").should == Time.new(2000, 1, 1, 12, 1, 1, "+05:00")
+ Time.new(2000, 1, 1, 12, 1, in: "+05:00").should == Time.new(2000, 1, 1, 12, 1, 0, "+05:00")
+ Time.new(2000, 1, 1, 12, in: "+05:00").should == Time.new(2000, 1, 1, 12, 0, 0, "+05:00")
+ Time.new(2000, 1, 1, in: "+05:00").should == Time.new(2000, 1, 1, 0, 0, 0, "+05:00")
+ Time.new(2000, 1, in: "+05:00").should == Time.new(2000, 1, 1, 0, 0, 0, "+05:00")
+ Time.new(2000, in: "+05:00").should == Time.new(2000, 1, 1, 0, 0, 0, "+05:00")
+ Time.new(in: "+05:00").should be_close(Time.now.getlocal("+05:00"), TIME_TOLERANCE)
+ end
+
+ it "converts to a provided timezone if all the positional arguments are omitted" do
+ Time.new(in: "+05:00").utc_offset.should == 5*3600
+ end
+
it "raises ArgumentError if format is invalid" do
-> { Time.new(2000, 1, 1, 12, 0, 0, in: "+09:99") }.should raise_error(ArgumentError)
-> { Time.new(2000, 1, 1, 12, 0, 0, in: "ABC") }.should raise_error(ArgumentError)
end
it "raises ArgumentError if two offset arguments are given" do
- -> { Time.new(2000, 1, 1, 12, 0, 0, "+05:00", in: "+05:00") }.should raise_error(ArgumentError)
+ -> {
+ Time.new(2000, 1, 1, 12, 0, 0, "+05:00", in: "+05:00")
+ }.should raise_error(ArgumentError, "timezone argument given as positional and keyword arguments")
end
end
end
diff --git a/spec/ruby/core/time/now_spec.rb b/spec/ruby/core/time/now_spec.rb
index 2b2e53a17c..d47f00723e 100644
--- a/spec/ruby/core/time/now_spec.rb
+++ b/spec/ruby/core/time/now_spec.rb
@@ -4,48 +4,54 @@ require_relative 'shared/now'
describe "Time.now" do
it_behaves_like :time_now, :now
- describe ":in keyword argument" do
- it "could be UTC offset as a String in '+HH:MM or '-HH:MM' format" do
- time = Time.now(in: "+05:00")
+ ruby_version_is '3.1' do # https://bugs.ruby-lang.org/issues/17485
+ describe ":in keyword argument" do
+ it "could be UTC offset as a String in '+HH:MM or '-HH:MM' format" do
+ time = Time.now(in: "+05:00")
- time.utc_offset.should == 5*60*60
- time.zone.should == nil
+ time.utc_offset.should == 5*60*60
+ time.zone.should == nil
- time = Time.now(in: "-09:00")
+ time = Time.now(in: "-09:00")
- time.utc_offset.should == -9*60*60
- time.zone.should == nil
- end
+ time.utc_offset.should == -9*60*60
+ time.zone.should == nil
+ end
- it "could be UTC offset as a number of seconds" do
- time = Time.now(in: 5*60*60)
+ it "could be UTC offset as a number of seconds" do
+ time = Time.now(in: 5*60*60)
- time.utc_offset.should == 5*60*60
- time.zone.should == nil
+ time.utc_offset.should == 5*60*60
+ time.zone.should == nil
- time = Time.now(in: -9*60*60)
+ time = Time.now(in: -9*60*60)
- time.utc_offset.should == -9*60*60
- time.zone.should == nil
- end
+ time.utc_offset.should == -9*60*60
+ time.zone.should == nil
+ end
- it "could be a timezone object" do
- zone = TimeSpecs::TimezoneWithName.new(name: "Asia/Colombo")
- time = Time.now(in: zone)
+ it "returns a Time with UTC offset specified as a single letter military timezone" do
+ Time.now(in: "W").utc_offset.should == 3600 * -10
+ end
- time.utc_offset.should == 5*3600+30*60
- time.zone.should == zone
+ it "could be a timezone object" do
+ zone = TimeSpecs::TimezoneWithName.new(name: "Asia/Colombo")
+ time = Time.now(in: zone)
- zone = TimeSpecs::TimezoneWithName.new(name: "PST")
- time = Time.now(in: zone)
+ time.utc_offset.should == 5*3600+30*60
+ time.zone.should == zone
- time.utc_offset.should == -9*60*60
- time.zone.should == zone
- end
+ zone = TimeSpecs::TimezoneWithName.new(name: "PST")
+ time = Time.now(in: zone)
+
+ time.utc_offset.should == -9*60*60
+ time.zone.should == zone
+ end
- it "raises ArgumentError if format is invalid" do
- -> { Time.now(in: "+09:99") }.should raise_error(ArgumentError)
- -> { Time.now(in: "ABC") }.should raise_error(ArgumentError)
+ it "raises ArgumentError if format is invalid" do
+ -> { Time.now(in: "+09:99") }.should raise_error(ArgumentError)
+ -> { Time.now(in: "ABC") }.should raise_error(ArgumentError)
+ end
end
end
end
diff --git a/spec/ruby/core/time/utc_spec.rb b/spec/ruby/core/time/utc_spec.rb
index 809accc809..566509fd33 100644
--- a/spec/ruby/core/time/utc_spec.rb
+++ b/spec/ruby/core/time/utc_spec.rb
@@ -21,12 +21,22 @@ describe "Time#utc?" do
Time.new(2022, 1, 1, 0, 0, 0, "UTC").utc?.should == true
Time.now.localtime("UTC").utc?.should == true
Time.at(Time.now, in: 'UTC').utc?.should == true
+
+ ruby_version_is "3.1" do
+ Time.new(2022, 1, 1, 0, 0, 0, in: "UTC").utc?.should == true
+ Time.now(in: "UTC").utc?.should == true
+ end
end
it "does treat time with Z offset as UTC" do
Time.new(2022, 1, 1, 0, 0, 0, "Z").utc?.should == true
Time.now.localtime("Z").utc?.should == true
Time.at(Time.now, in: 'Z').utc?.should == true
+
+ ruby_version_is "3.1" do
+ Time.new(2022, 1, 1, 0, 0, 0, in: "Z").utc?.should == true
+ Time.now(in: "Z").utc?.should == true
+ end
end
ruby_version_is "3.1" do
diff --git a/spec/ruby/core/time/zone_spec.rb b/spec/ruby/core/time/zone_spec.rb
index cbb0977f24..63c92602d1 100644
--- a/spec/ruby/core/time/zone_spec.rb
+++ b/spec/ruby/core/time/zone_spec.rb
@@ -74,6 +74,17 @@ describe "Time#zone" do
Time.now.localtime("-00:00").zone.should == "UTC"
Time.at(Time.now, in: '-00:00').zone.should == "UTC"
end
+
+ ruby_version_is "3.1" do
+ Time.new(2022, 1, 1, 0, 0, 0, in: "UTC").zone.should == "UTC"
+ Time.new(2022, 1, 1, 0, 0, 0, in: "Z").zone.should == "UTC"
+
+ Time.now(in: 'UTC').zone.should == "UTC"
+ Time.now(in: 'Z').zone.should == "UTC"
+
+ Time.at(Time.now, in: 'UTC').zone.should == "UTC"
+ Time.at(Time.now, in: 'Z').zone.should == "UTC"
+ end
end
platform_is_not :aix, :windows do
diff --git a/spec/ruby/core/warning/warn_spec.rb b/spec/ruby/core/warning/warn_spec.rb
index 5ccff3aa2b..e2fcfbf93f 100644
--- a/spec/ruby/core/warning/warn_spec.rb
+++ b/spec/ruby/core/warning/warn_spec.rb
@@ -73,6 +73,66 @@ describe "Warning.warn" do
$VERBOSE = verbose
end
end
+
+ it "warns when category is :deprecated and Warning[:deprecated] is true" do
+ warn_deprecated = Warning[:deprecated]
+ Warning[:deprecated] = true
+ begin
+ -> {
+ Warning.warn("foo", category: :deprecated)
+ }.should complain("foo")
+ ensure
+ Warning[:deprecated] = warn_deprecated
+ end
+ end
+
+ it "warns when category is :experimental and Warning[:experimental] is true" do
+ warn_experimental = Warning[:experimental]
+ Warning[:experimental] = true
+ begin
+ -> {
+ Warning.warn("foo", category: :experimental)
+ }.should complain("foo")
+ ensure
+ Warning[:experimental] = warn_experimental
+ end
+ end
+
+ it "doesn't print message when category is :deprecated but Warning[:deprecated] is false" do
+ warn_deprecated = Warning[:deprecated]
+ Warning[:deprecated] = false
+ begin
+ -> {
+ Warning.warn("foo", category: :deprecated)
+ }.should_not complain
+ ensure
+ Warning[:deprecated] = warn_deprecated
+ end
+ end
+
+ it "doesn't print message when category is :experimental but Warning[:experimental] is false" do
+ warn_experimental = Warning[:experimental]
+ Warning[:experimental] = false
+ begin
+ -> {
+ Warning.warn("foo", category: :experimental)
+ }.should_not complain
+ ensure
+ Warning[:experimental] = warn_experimental
+ end
+ end
+
+ it "prints the message when VERBOSE is false" do
+ -> { Warning.warn("foo") }.should complain("foo")
+ end
+
+ it "prints the message when VERBOSE is nil" do
+ -> { Warning.warn("foo") }.should complain("foo", verbose: nil)
+ end
+
+ it "prints the message when VERBOSE is true" do
+ -> { Warning.warn("foo") }.should complain("foo", verbose: true)
+ end
end
ruby_version_is ''...'3.0' do