diff options
Diffstat (limited to 'test')
305 files changed, 9650 insertions, 3228 deletions
diff --git a/test/-ext-/bignum/test_big2str.rb b/test/-ext-/bignum/test_big2str.rb index f8d6320338..88e35a7294 100644 --- a/test/-ext-/bignum/test_big2str.rb +++ b/test/-ext-/bignum/test_big2str.rb @@ -2,29 +2,27 @@ require 'test/unit' require "-test-/bignum" -class Test_Bignum < Test::Unit::TestCase - class TestBig2str < Test::Unit::TestCase +class TestBignum_Big2str < Test::Unit::TestCase - SIZEOF_BDIGIT = Bug::Bignum::SIZEOF_BDIGIT - BITSPERDIG = Bug::Bignum::BITSPERDIG - BDIGMAX = (1 << BITSPERDIG) - 1 + SIZEOF_BDIGIT = Bug::Bignum::SIZEOF_BDIGIT + BITSPERDIG = Bug::Bignum::BITSPERDIG + BDIGMAX = (1 << BITSPERDIG) - 1 - def test_big2str_generic - x = 10**1000 - assert_equal("1" + "0" * 1000, Bug::Bignum.big2str_generic(x, 10)) - end - - def test_big2str_poweroftwo - e = BITSPERDIG*2 - x = 0b10**e - assert_equal("1" + "0" * e, Bug::Bignum.big2str_poweroftwo(x, 2)) - end + def test_big2str_generic + x = 10**1000 + assert_equal("1" + "0" * 1000, Bug::Bignum.big2str_generic(x, 10)) + end - def test_big2str_gmp - x = 10**1000 - assert_equal("1" + "0" * 1000, Bug::Bignum.big2str_gmp(x, 10)) - rescue NotImplementedError - end + def test_big2str_poweroftwo + e = BITSPERDIG*2 + x = 0b10**e + assert_equal("1" + "0" * e, Bug::Bignum.big2str_poweroftwo(x, 2)) + end + def test_big2str_gmp + x = 10**1000 + assert_equal("1" + "0" * 1000, Bug::Bignum.big2str_gmp(x, 10)) + rescue NotImplementedError end + end diff --git a/test/-ext-/bignum/test_bigzero.rb b/test/-ext-/bignum/test_bigzero.rb index cf34964acd..6dfa3486c1 100644 --- a/test/-ext-/bignum/test_bigzero.rb +++ b/test/-ext-/bignum/test_bigzero.rb @@ -2,19 +2,17 @@ require 'test/unit' require "-test-/bignum" -class Test_Bignum < Test::Unit::TestCase - class TestBigZero < Test::Unit::TestCase - def test_equal_0 - bug8204 = '[ruby-core:53893] [Bug #8204]' - (0..10).each do |i| - assert_equal(0, Bug::Bignum.zero(i), "#{bug8204} Bignum.zero(#{i})") - end +class TestBignum_BigZero < Test::Unit::TestCase + def test_equal_0 + bug8204 = '[ruby-core:53893] [Bug #8204]' + (0..10).each do |i| + assert_equal(0, Bug::Bignum.zero(i), "#{bug8204} Bignum.zero(#{i})") end + end - def test_zero? - (0..10).each do |i| - assert_equal(true, Bug::Bignum.zero(i).zero?) - end + def test_zero? + (0..10).each do |i| + assert_equal(true, Bug::Bignum.zero(i).zero?) end end end diff --git a/test/-ext-/bignum/test_div.rb b/test/-ext-/bignum/test_div.rb index e61fc2ced5..0c6f635ae8 100644 --- a/test/-ext-/bignum/test_div.rb +++ b/test/-ext-/bignum/test_div.rb @@ -2,28 +2,26 @@ require 'test/unit' require "-test-/bignum" -class Test_Bignum < Test::Unit::TestCase - class TestDiv < Test::Unit::TestCase +class TestBignum_Div < Test::Unit::TestCase - SIZEOF_BDIGIT = Bug::Bignum::SIZEOF_BDIGIT - BITSPERDIG = Bug::Bignum::BITSPERDIG - BDIGMAX = (1 << BITSPERDIG) - 1 + SIZEOF_BDIGIT = Bug::Bignum::SIZEOF_BDIGIT + BITSPERDIG = Bug::Bignum::BITSPERDIG + BDIGMAX = (1 << BITSPERDIG) - 1 - def test_divrem_normal - x = (1 << (BITSPERDIG*2)) | (2 << BITSPERDIG) | 3 - y = (1 << BITSPERDIG) | 1 - q = (1 << BITSPERDIG) | 1 - r = 2 - assert_equal([q, r], Bug::Bignum.big_divrem_normal(x, y)) - end + def test_divrem_normal + x = (1 << (BITSPERDIG*2)) | (2 << BITSPERDIG) | 3 + y = (1 << BITSPERDIG) | 1 + q = (1 << BITSPERDIG) | 1 + r = 2 + assert_equal([q, r], Bug::Bignum.big_divrem_normal(x, y)) + end - def test_divrem_gmp - x = (1 << (BITSPERDIG*2)) | (2 << BITSPERDIG) | 3 - y = (1 << BITSPERDIG) | 1 - q = (1 << BITSPERDIG) | 1 - r = 2 - assert_equal([q, r], Bug::Bignum.big_divrem_gmp(x, y)) - rescue NotImplementedError - end + def test_divrem_gmp + x = (1 << (BITSPERDIG*2)) | (2 << BITSPERDIG) | 3 + y = (1 << BITSPERDIG) | 1 + q = (1 << BITSPERDIG) | 1 + r = 2 + assert_equal([q, r], Bug::Bignum.big_divrem_gmp(x, y)) + rescue NotImplementedError end end diff --git a/test/-ext-/bignum/test_mul.rb b/test/-ext-/bignum/test_mul.rb index 7653a8e37a..95186bbf76 100644 --- a/test/-ext-/bignum/test_mul.rb +++ b/test/-ext-/bignum/test_mul.rb @@ -2,137 +2,135 @@ require 'test/unit' require "-test-/bignum" -class Test_Bignum < Test::Unit::TestCase - class TestMul < Test::Unit::TestCase - - SIZEOF_BDIGIT = Bug::Bignum::SIZEOF_BDIGIT - BITSPERDIG = Bug::Bignum::BITSPERDIG - BDIGMAX = (1 << BITSPERDIG) - 1 - - def test_mul_normal - x = (1 << BITSPERDIG) | 1 - y = (1 << BITSPERDIG) | 1 - z = (1 << (BITSPERDIG*2)) | (2 << BITSPERDIG) | 1 - assert_equal(z, Bug::Bignum.big_mul_normal(x, y)) - end - - def test_mul_normal_zero_in_x - x = (1 << (2*BITSPERDIG)) | 1 - y = (1 << BITSPERDIG) | 1 - z = (1 << (BITSPERDIG*3)) | (1 << (BITSPERDIG*2)) | (1 << BITSPERDIG) | 1 - assert_equal(z, Bug::Bignum.big_mul_normal(x, y)) - end - - def test_mul_normal_zero_in_y - x = (1 << BITSPERDIG) | 1 - y = (1 << (2*BITSPERDIG)) | 1 - z = (1 << (BITSPERDIG*3)) | (1 << (BITSPERDIG*2)) | (1 << BITSPERDIG) | 1 - assert_equal(z, Bug::Bignum.big_mul_normal(x, y)) - end - - def test_mul_normal_max_max - x = (1 << (2*BITSPERDIG)) - 1 - y = (1 << (2*BITSPERDIG)) - 1 - z = (1 << (4*BITSPERDIG)) - (1 << (2*BITSPERDIG+1)) + 1 - assert_equal(z, Bug::Bignum.big_mul_normal(x, y)) - end - - def test_sq_fast - x = (1 << BITSPERDIG) | 1 - z = (1 << 2*BITSPERDIG) | (2 << BITSPERDIG) | 1 - assert_equal(z, Bug::Bignum.big_sq_fast(x)) - end - - def test_sq_fast_max2 - x = (BDIGMAX << BITSPERDIG) | BDIGMAX - assert_equal(Bug::Bignum.big_mul_normal(x, x), Bug::Bignum.big_sq_fast(x)) - end - - def test_sq_fast_zero_in_middle - x = (BDIGMAX << 2*BITSPERDIG) | BDIGMAX - assert_equal(Bug::Bignum.big_mul_normal(x, x), Bug::Bignum.big_sq_fast(x)) - end - - def test_mul_balance - x = (1 << BITSPERDIG) | 1 - y = (1 << BITSPERDIG) | 1 - z = (1 << (BITSPERDIG*2)) | (2 << BITSPERDIG) | 1 - assert_equal(z, Bug::Bignum.big_mul_balance(x, y)) - end - - def test_mul_balance_2x16 - x = (1 << BITSPERDIG) | 1 - y = (1 << BITSPERDIG*16) | 1 - assert_equal(Bug::Bignum.big_mul_normal(x, y), Bug::Bignum.big_mul_balance(x, y)) - end - - def test_mul_balance_2x17 - x = (1 << BITSPERDIG) | 1 - y = (1 << BITSPERDIG*17) | 1 - assert_equal(Bug::Bignum.big_mul_normal(x, y), Bug::Bignum.big_mul_balance(x, y)) - end - - def test_mul_karatsuba - x = (1 << BITSPERDIG) | 1 - y = (1 << BITSPERDIG) | 1 - z = (1 << (BITSPERDIG*2)) | (2 << BITSPERDIG) | 1 - assert_equal(z, Bug::Bignum.big_mul_karatsuba(x, y)) - end - - def test_mul_karatsuba_odd_y - x = (1 << BITSPERDIG) | 1 - y = (1 << (2*BITSPERDIG)) | 1 - assert_equal(Bug::Bignum.big_mul_normal(x, y), Bug::Bignum.big_mul_karatsuba(x, y)) - end - - def test_mul_karatsuba_odd_xy - x = (1 << (2*BITSPERDIG)) | 1 - y = (1 << (2*BITSPERDIG)) | 1 - assert_equal(Bug::Bignum.big_mul_normal(x, y), Bug::Bignum.big_mul_karatsuba(x, y)) - end - - def test_mul_karatsuba_x1_gt_x0 - x = (2 << BITSPERDIG) | 1 - y = (1 << BITSPERDIG) | 2 - assert_equal(Bug::Bignum.big_mul_normal(x, y), Bug::Bignum.big_mul_karatsuba(x, y)) - end - - def test_mul_karatsuba_y1_gt_y0 - x = (1 << BITSPERDIG) | 2 - y = (2 << BITSPERDIG) | 1 - assert_equal(Bug::Bignum.big_mul_normal(x, y), Bug::Bignum.big_mul_karatsuba(x, y)) - end - - def test_mul_karatsuba_x1_gt_x0_and_y1_gt_y0 - x = (2 << BITSPERDIG) | 1 - y = (2 << BITSPERDIG) | 1 - assert_equal(Bug::Bignum.big_mul_normal(x, y), Bug::Bignum.big_mul_karatsuba(x, y)) - end - - def test_mul_karatsuba_carry2 - x = (1 << BITSPERDIG) | BDIGMAX - y = (1 << BITSPERDIG) | BDIGMAX - assert_equal(Bug::Bignum.big_mul_normal(x, y), Bug::Bignum.big_mul_karatsuba(x, y)) - end - - def test_mul_karatsuba_borrow - x = (BDIGMAX << BITSPERDIG) | 1 - y = (BDIGMAX << BITSPERDIG) | 1 - assert_equal(Bug::Bignum.big_mul_normal(x, y), Bug::Bignum.big_mul_karatsuba(x, y)) - end - - def test_mul_toom3 - x = (1 << 2*BITSPERDIG) | (1 << BITSPERDIG) | 1 - y = (1 << 2*BITSPERDIG) | (1 << BITSPERDIG) | 1 - assert_equal(Bug::Bignum.big_mul_normal(x, y), Bug::Bignum.big_mul_toom3(x, y)) - end - - def test_mul_gmp - x = (1 << 2*BITSPERDIG) | (1 << BITSPERDIG) | 1 - y = (1 << 2*BITSPERDIG) | (1 << BITSPERDIG) | 1 - assert_equal(Bug::Bignum.big_mul_normal(x, y), Bug::Bignum.big_mul_gmp(x, y)) - rescue NotImplementedError - end +class TestBignum_Mul < Test::Unit::TestCase + SIZEOF_BDIGIT = Bug::Bignum::SIZEOF_BDIGIT + BITSPERDIG = Bug::Bignum::BITSPERDIG + BDIGMAX = (1 << BITSPERDIG) - 1 + + def test_mul_normal + x = (1 << BITSPERDIG) | 1 + y = (1 << BITSPERDIG) | 1 + z = (1 << (BITSPERDIG*2)) | (2 << BITSPERDIG) | 1 + assert_equal(z, Bug::Bignum.big_mul_normal(x, y)) + end + + def test_mul_normal_zero_in_x + x = (1 << (2*BITSPERDIG)) | 1 + y = (1 << BITSPERDIG) | 1 + z = (1 << (BITSPERDIG*3)) | (1 << (BITSPERDIG*2)) | (1 << BITSPERDIG) | 1 + assert_equal(z, Bug::Bignum.big_mul_normal(x, y)) + end + + def test_mul_normal_zero_in_y + x = (1 << BITSPERDIG) | 1 + y = (1 << (2*BITSPERDIG)) | 1 + z = (1 << (BITSPERDIG*3)) | (1 << (BITSPERDIG*2)) | (1 << BITSPERDIG) | 1 + assert_equal(z, Bug::Bignum.big_mul_normal(x, y)) + end + + def test_mul_normal_max_max + x = (1 << (2*BITSPERDIG)) - 1 + y = (1 << (2*BITSPERDIG)) - 1 + z = (1 << (4*BITSPERDIG)) - (1 << (2*BITSPERDIG+1)) + 1 + assert_equal(z, Bug::Bignum.big_mul_normal(x, y)) + end + + def test_sq_fast + x = (1 << BITSPERDIG) | 1 + z = (1 << 2*BITSPERDIG) | (2 << BITSPERDIG) | 1 + assert_equal(z, Bug::Bignum.big_sq_fast(x)) + end + + def test_sq_fast_max2 + x = (BDIGMAX << BITSPERDIG) | BDIGMAX + assert_equal(Bug::Bignum.big_mul_normal(x, x), Bug::Bignum.big_sq_fast(x)) + end + + def test_sq_fast_zero_in_middle + x = (BDIGMAX << 2*BITSPERDIG) | BDIGMAX + assert_equal(Bug::Bignum.big_mul_normal(x, x), Bug::Bignum.big_sq_fast(x)) + end + + def test_mul_balance + x = (1 << BITSPERDIG) | 1 + y = (1 << BITSPERDIG) | 1 + z = (1 << (BITSPERDIG*2)) | (2 << BITSPERDIG) | 1 + assert_equal(z, Bug::Bignum.big_mul_balance(x, y)) + end + + def test_mul_balance_2x16 + x = (1 << BITSPERDIG) | 1 + y = (1 << BITSPERDIG*16) | 1 + assert_equal(Bug::Bignum.big_mul_normal(x, y), Bug::Bignum.big_mul_balance(x, y)) + end + + def test_mul_balance_2x17 + x = (1 << BITSPERDIG) | 1 + y = (1 << BITSPERDIG*17) | 1 + assert_equal(Bug::Bignum.big_mul_normal(x, y), Bug::Bignum.big_mul_balance(x, y)) + end + + def test_mul_karatsuba + x = (1 << BITSPERDIG) | 1 + y = (1 << BITSPERDIG) | 1 + z = (1 << (BITSPERDIG*2)) | (2 << BITSPERDIG) | 1 + assert_equal(z, Bug::Bignum.big_mul_karatsuba(x, y)) + end + + def test_mul_karatsuba_odd_y + x = (1 << BITSPERDIG) | 1 + y = (1 << (2*BITSPERDIG)) | 1 + assert_equal(Bug::Bignum.big_mul_normal(x, y), Bug::Bignum.big_mul_karatsuba(x, y)) + end + + def test_mul_karatsuba_odd_xy + x = (1 << (2*BITSPERDIG)) | 1 + y = (1 << (2*BITSPERDIG)) | 1 + assert_equal(Bug::Bignum.big_mul_normal(x, y), Bug::Bignum.big_mul_karatsuba(x, y)) + end + + def test_mul_karatsuba_x1_gt_x0 + x = (2 << BITSPERDIG) | 1 + y = (1 << BITSPERDIG) | 2 + assert_equal(Bug::Bignum.big_mul_normal(x, y), Bug::Bignum.big_mul_karatsuba(x, y)) + end + + def test_mul_karatsuba_y1_gt_y0 + x = (1 << BITSPERDIG) | 2 + y = (2 << BITSPERDIG) | 1 + assert_equal(Bug::Bignum.big_mul_normal(x, y), Bug::Bignum.big_mul_karatsuba(x, y)) + end + + def test_mul_karatsuba_x1_gt_x0_and_y1_gt_y0 + x = (2 << BITSPERDIG) | 1 + y = (2 << BITSPERDIG) | 1 + assert_equal(Bug::Bignum.big_mul_normal(x, y), Bug::Bignum.big_mul_karatsuba(x, y)) + end + + def test_mul_karatsuba_carry2 + x = (1 << BITSPERDIG) | BDIGMAX + y = (1 << BITSPERDIG) | BDIGMAX + assert_equal(Bug::Bignum.big_mul_normal(x, y), Bug::Bignum.big_mul_karatsuba(x, y)) + end + + def test_mul_karatsuba_borrow + x = (BDIGMAX << BITSPERDIG) | 1 + y = (BDIGMAX << BITSPERDIG) | 1 + assert_equal(Bug::Bignum.big_mul_normal(x, y), Bug::Bignum.big_mul_karatsuba(x, y)) end + + def test_mul_toom3 + x = (1 << 2*BITSPERDIG) | (1 << BITSPERDIG) | 1 + y = (1 << 2*BITSPERDIG) | (1 << BITSPERDIG) | 1 + assert_equal(Bug::Bignum.big_mul_normal(x, y), Bug::Bignum.big_mul_toom3(x, y)) + end + + def test_mul_gmp + x = (1 << 2*BITSPERDIG) | (1 << BITSPERDIG) | 1 + y = (1 << 2*BITSPERDIG) | (1 << BITSPERDIG) | 1 + assert_equal(Bug::Bignum.big_mul_normal(x, y), Bug::Bignum.big_mul_gmp(x, y)) + rescue NotImplementedError + end + end diff --git a/test/-ext-/bignum/test_pack.rb b/test/-ext-/bignum/test_pack.rb index d5605236f7..b7aea9ab68 100644 --- a/test/-ext-/bignum/test_pack.rb +++ b/test/-ext-/bignum/test_pack.rb @@ -4,348 +4,346 @@ require 'test/unit' require "-test-/bignum" -class Test_Bignum < Test::Unit::TestCase - class TestPack < Test::Unit::TestCase - - MSWORD_FIRST = Bug::Bignum::INTEGER_PACK_MSWORD_FIRST - LSWORD_FIRST = Bug::Bignum::INTEGER_PACK_LSWORD_FIRST - MSBYTE_FIRST = Bug::Bignum::INTEGER_PACK_MSBYTE_FIRST - LSBYTE_FIRST = Bug::Bignum::INTEGER_PACK_LSBYTE_FIRST - NATIVE_BYTE_ORDER = Bug::Bignum::INTEGER_PACK_NATIVE_BYTE_ORDER - TWOCOMP = Bug::Bignum::INTEGER_PACK_2COMP - LITTLE_ENDIAN = Bug::Bignum::INTEGER_PACK_LITTLE_ENDIAN - BIG_ENDIAN = Bug::Bignum::INTEGER_PACK_BIG_ENDIAN - NEGATIVE = Bug::Bignum::INTEGER_PACK_NEGATIVE - GENERIC = Bug::Bignum::INTEGER_PACK_FORCE_GENERIC_IMPLEMENTATION - - def test_pack_zero - assert_equal([0, ""], Bug::Bignum.test_pack(0, 0, 1, 0, BIG_ENDIAN)) - end - - def test_pack_argument_check - assert_raise(ArgumentError) { Bug::Bignum.test_pack_raw(0, "", 2, 1, 0, MSBYTE_FIRST) } - assert_raise(ArgumentError) { Bug::Bignum.test_pack_raw(0, "", 0, 1, 0, MSWORD_FIRST) } - assert_raise(ArgumentError) { Bug::Bignum.test_pack_raw(0, "", 0, 0, 0, BIG_ENDIAN) } - assert_raise(ArgumentError) { Bug::Bignum.test_pack_raw(0, "", 0, 1, 8, BIG_ENDIAN) } - - # assume sizeof(ssize_t) == sizeof(intptr_t) - assert_raise(ArgumentError) { Bug::Bignum.test_pack_raw(0, "", 1 << ([""].pack("p").length * 8 - 1), 0, BIG_ENDIAN) } - end - - def test_pack_wordsize - assert_equal([1, "\x01"], Bug::Bignum.test_pack(1, 1, 1, 0, BIG_ENDIAN)) - assert_equal([1, "\x00\x01"], Bug::Bignum.test_pack(1, 1, 2, 0, BIG_ENDIAN)) - assert_equal([1, "\x00\x00\x01"], Bug::Bignum.test_pack(1, 1, 3, 0, BIG_ENDIAN)) - assert_equal([1, "\x01"], Bug::Bignum.test_pack(1, 1, 1, 0, LITTLE_ENDIAN)) - assert_equal([1, "\x01\x00"], Bug::Bignum.test_pack(1, 1, 2, 0, LITTLE_ENDIAN)) - assert_equal([1, "\x01\x00\x00"], Bug::Bignum.test_pack(1, 1, 3, 0, LITTLE_ENDIAN)) - end - - def test_pack_fixed_buffer - assert_equal([0, "\x00\x00"], Bug::Bignum.test_pack(0, 2, 1, 0, BIG_ENDIAN)) - assert_equal([1, "\x00\x01"], Bug::Bignum.test_pack(0x01, 2, 1, 0, BIG_ENDIAN)) - assert_equal([1, "\x02\x01"], Bug::Bignum.test_pack(0x0201, 2, 1, 0, BIG_ENDIAN)) - assert_equal([2, "\x02\x01"], Bug::Bignum.test_pack(0x030201, 2, 1, 0, BIG_ENDIAN)) - assert_equal([2, "\x02\x01"], Bug::Bignum.test_pack(0x04030201, 2, 1, 0, BIG_ENDIAN)) - assert_equal([0, "\x00\x00"], Bug::Bignum.test_pack(0, 2, 1, 0, LITTLE_ENDIAN)) - assert_equal([1, "\x01\x00"], Bug::Bignum.test_pack(0x01, 2, 1, 0, LITTLE_ENDIAN)) - assert_equal([1, "\x01\x02"], Bug::Bignum.test_pack(0x0201, 2, 1, 0, LITTLE_ENDIAN)) - assert_equal([2, "\x01\x02"], Bug::Bignum.test_pack(0x030201, 2, 1, 0, LITTLE_ENDIAN)) - assert_equal([2, "\x01\x02"], Bug::Bignum.test_pack(0x04030201, 2, 1, 0, LITTLE_ENDIAN)) - end - - def test_pack_wordorder_and_endian - assert_equal([1, "\x12\x34\x56\x78"], Bug::Bignum.test_pack(0x12345678, 2, 2, 0, MSWORD_FIRST|MSBYTE_FIRST)) - assert_equal([1, "\x34\x12\x78\x56"], Bug::Bignum.test_pack(0x12345678, 2, 2, 0, MSWORD_FIRST|LSBYTE_FIRST)) - assert_equal([1, "\x56\x78\x12\x34"], Bug::Bignum.test_pack(0x12345678, 2, 2, 0, LSWORD_FIRST|MSBYTE_FIRST)) - assert_equal([1, "\x78\x56\x34\x12"], Bug::Bignum.test_pack(0x12345678, 2, 2, 0, LSWORD_FIRST|LSBYTE_FIRST)) - end - - def test_pack_native_endian - assert_equal([1, [0x1234].pack("S!")], Bug::Bignum.test_pack(0x1234, 1, 2, 0, MSWORD_FIRST|NATIVE_BYTE_ORDER)) - end - - def test_pack_nail - assert_equal([1, "\x01\x00\x00\x00\x01\x01"], Bug::Bignum.test_pack(0b100011, 6, 1, 7, BIG_ENDIAN)) - assert_equal([1, "\x01\x02\x03\x04\x05\x06\x07\x08"], Bug::Bignum.test_pack(0x12345678, 8, 1, 4, BIG_ENDIAN)) - assert_equal([1, "\x00\x12\x00\x34\x00\x56\x00\x78"], Bug::Bignum.test_pack(0x12345678, 4, 2, 8, BIG_ENDIAN)) - end - - def test_pack_overflow - assert_equal([-2, "\x1"], Bug::Bignum.test_pack((-0x11), 1, 1, 4, BIG_ENDIAN)) - assert_equal([-2, "\x0"], Bug::Bignum.test_pack((-0x10), 1, 1, 4, BIG_ENDIAN)) - assert_equal([-1, "\xF"], Bug::Bignum.test_pack((-0x0F), 1, 1, 4, BIG_ENDIAN)) - assert_equal([+1, "\xF"], Bug::Bignum.test_pack((+0x0F), 1, 1, 4, BIG_ENDIAN)) - assert_equal([+2, "\x0"], Bug::Bignum.test_pack((+0x10), 1, 1, 4, BIG_ENDIAN)) - assert_equal([+2, "\x1"], Bug::Bignum.test_pack((+0x11), 1, 1, 4, BIG_ENDIAN)) - - assert_equal([-2, "\x01"], Bug::Bignum.test_pack((-0x101), 1, 1, 0, BIG_ENDIAN)) - assert_equal([-2, "\x00"], Bug::Bignum.test_pack((-0x100), 1, 1, 0, BIG_ENDIAN)) - assert_equal([-1, "\xFF"], Bug::Bignum.test_pack((-0x0FF), 1, 1, 0, BIG_ENDIAN)) - assert_equal([+1, "\xFF"], Bug::Bignum.test_pack((+0x0FF), 1, 1, 0, BIG_ENDIAN)) - assert_equal([+2, "\x00"], Bug::Bignum.test_pack((+0x100), 1, 1, 0, BIG_ENDIAN)) - assert_equal([+2, "\x01"], Bug::Bignum.test_pack((+0x101), 1, 1, 0, BIG_ENDIAN)) - - assert_equal([-2, "\x00\x00\x00\x00\x00\x00\x00\x01"], Bug::Bignum.test_pack((-0x10000000000000001), 2, 4, 0, BIG_ENDIAN)) - assert_equal([-2, "\x00\x00\x00\x00\x00\x00\x00\x00"], Bug::Bignum.test_pack((-0x10000000000000000), 2, 4, 0, BIG_ENDIAN)) - assert_equal([-1, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"], Bug::Bignum.test_pack((-0x0FFFFFFFFFFFFFFFF), 2, 4, 0, BIG_ENDIAN)) - assert_equal([+1, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"], Bug::Bignum.test_pack((+0x0FFFFFFFFFFFFFFFF), 2, 4, 0, BIG_ENDIAN)) - assert_equal([+2, "\x00\x00\x00\x00\x00\x00\x00\x00"], Bug::Bignum.test_pack((+0x10000000000000000), 2, 4, 0, BIG_ENDIAN)) - assert_equal([+2, "\x00\x00\x00\x00\x00\x00\x00\x01"], Bug::Bignum.test_pack((+0x10000000000000001), 2, 4, 0, BIG_ENDIAN)) - - 1.upto(16) {|wordsize| - 1.upto(20) {|numwords| - w = numwords*wordsize - n = 256**w - assert_equal([-2, "\x00"*(w-1)+"\x01"], Bug::Bignum.test_pack((-n-1), numwords, wordsize, 0, BIG_ENDIAN)) - assert_equal([-2, "\x00"*w], Bug::Bignum.test_pack((-n ), numwords, wordsize, 0, BIG_ENDIAN)) - assert_equal([-1, "\xFF"*w], Bug::Bignum.test_pack((-n+1), numwords, wordsize, 0, BIG_ENDIAN)) - assert_equal([+1, "\xFF"*w], Bug::Bignum.test_pack((+n-1), numwords, wordsize, 0, BIG_ENDIAN)) - assert_equal([+2, "\x00"*w], Bug::Bignum.test_pack((+n ), numwords, wordsize, 0, BIG_ENDIAN)) - assert_equal([+2, "\x00"*(w-1)+"\x01"], Bug::Bignum.test_pack((+n+1), numwords, wordsize, 0, BIG_ENDIAN)) - } - } +class TestBignum_Pack < Test::Unit::TestCase + + MSWORD_FIRST = Bug::Bignum::INTEGER_PACK_MSWORD_FIRST + LSWORD_FIRST = Bug::Bignum::INTEGER_PACK_LSWORD_FIRST + MSBYTE_FIRST = Bug::Bignum::INTEGER_PACK_MSBYTE_FIRST + LSBYTE_FIRST = Bug::Bignum::INTEGER_PACK_LSBYTE_FIRST + NATIVE_BYTE_ORDER = Bug::Bignum::INTEGER_PACK_NATIVE_BYTE_ORDER + TWOCOMP = Bug::Bignum::INTEGER_PACK_2COMP + LITTLE_ENDIAN = Bug::Bignum::INTEGER_PACK_LITTLE_ENDIAN + BIG_ENDIAN = Bug::Bignum::INTEGER_PACK_BIG_ENDIAN + NEGATIVE = Bug::Bignum::INTEGER_PACK_NEGATIVE + GENERIC = Bug::Bignum::INTEGER_PACK_FORCE_GENERIC_IMPLEMENTATION + + def test_pack_zero + assert_equal([0, ""], Bug::Bignum.test_pack(0, 0, 1, 0, BIG_ENDIAN)) + end - 1.upto(16) {|wordsize| - 1.upto(20) {|numwords| - w = numwords*wordsize - n = 256**w - assert_equal([-2, "\x01"+"\x00"*(w-1)], Bug::Bignum.test_pack((-n-1), numwords, wordsize, 0, LITTLE_ENDIAN)) - assert_equal([-2, "\x00"*w], Bug::Bignum.test_pack((-n ), numwords, wordsize, 0, LITTLE_ENDIAN)) - assert_equal([-1, "\xFF"*w], Bug::Bignum.test_pack((-n+1), numwords, wordsize, 0, LITTLE_ENDIAN)) - assert_equal([+1, "\xFF"*w], Bug::Bignum.test_pack((+n-1), numwords, wordsize, 0, LITTLE_ENDIAN)) - assert_equal([+2, "\x00"*w], Bug::Bignum.test_pack((+n ), numwords, wordsize, 0, LITTLE_ENDIAN)) - assert_equal([+2, "\x01"+"\x00"*(w-1)], Bug::Bignum.test_pack((+n+1), numwords, wordsize, 0, LITTLE_ENDIAN)) - } + def test_pack_argument_check + assert_raise(ArgumentError) { Bug::Bignum.test_pack_raw(0, "", 2, 1, 0, MSBYTE_FIRST) } + assert_raise(ArgumentError) { Bug::Bignum.test_pack_raw(0, "", 0, 1, 0, MSWORD_FIRST) } + assert_raise(ArgumentError) { Bug::Bignum.test_pack_raw(0, "", 0, 0, 0, BIG_ENDIAN) } + assert_raise(ArgumentError) { Bug::Bignum.test_pack_raw(0, "", 0, 1, 8, BIG_ENDIAN) } + + # assume sizeof(ssize_t) == sizeof(intptr_t) + assert_raise(ArgumentError) { Bug::Bignum.test_pack_raw(0, "", 1 << ([""].pack("p").length * 8 - 1), 0, BIG_ENDIAN) } + end + + def test_pack_wordsize + assert_equal([1, "\x01"], Bug::Bignum.test_pack(1, 1, 1, 0, BIG_ENDIAN)) + assert_equal([1, "\x00\x01"], Bug::Bignum.test_pack(1, 1, 2, 0, BIG_ENDIAN)) + assert_equal([1, "\x00\x00\x01"], Bug::Bignum.test_pack(1, 1, 3, 0, BIG_ENDIAN)) + assert_equal([1, "\x01"], Bug::Bignum.test_pack(1, 1, 1, 0, LITTLE_ENDIAN)) + assert_equal([1, "\x01\x00"], Bug::Bignum.test_pack(1, 1, 2, 0, LITTLE_ENDIAN)) + assert_equal([1, "\x01\x00\x00"], Bug::Bignum.test_pack(1, 1, 3, 0, LITTLE_ENDIAN)) + end + + def test_pack_fixed_buffer + assert_equal([0, "\x00\x00"], Bug::Bignum.test_pack(0, 2, 1, 0, BIG_ENDIAN)) + assert_equal([1, "\x00\x01"], Bug::Bignum.test_pack(0x01, 2, 1, 0, BIG_ENDIAN)) + assert_equal([1, "\x02\x01"], Bug::Bignum.test_pack(0x0201, 2, 1, 0, BIG_ENDIAN)) + assert_equal([2, "\x02\x01"], Bug::Bignum.test_pack(0x030201, 2, 1, 0, BIG_ENDIAN)) + assert_equal([2, "\x02\x01"], Bug::Bignum.test_pack(0x04030201, 2, 1, 0, BIG_ENDIAN)) + assert_equal([0, "\x00\x00"], Bug::Bignum.test_pack(0, 2, 1, 0, LITTLE_ENDIAN)) + assert_equal([1, "\x01\x00"], Bug::Bignum.test_pack(0x01, 2, 1, 0, LITTLE_ENDIAN)) + assert_equal([1, "\x01\x02"], Bug::Bignum.test_pack(0x0201, 2, 1, 0, LITTLE_ENDIAN)) + assert_equal([2, "\x01\x02"], Bug::Bignum.test_pack(0x030201, 2, 1, 0, LITTLE_ENDIAN)) + assert_equal([2, "\x01\x02"], Bug::Bignum.test_pack(0x04030201, 2, 1, 0, LITTLE_ENDIAN)) + end + + def test_pack_wordorder_and_endian + assert_equal([1, "\x12\x34\x56\x78"], Bug::Bignum.test_pack(0x12345678, 2, 2, 0, MSWORD_FIRST|MSBYTE_FIRST)) + assert_equal([1, "\x34\x12\x78\x56"], Bug::Bignum.test_pack(0x12345678, 2, 2, 0, MSWORD_FIRST|LSBYTE_FIRST)) + assert_equal([1, "\x56\x78\x12\x34"], Bug::Bignum.test_pack(0x12345678, 2, 2, 0, LSWORD_FIRST|MSBYTE_FIRST)) + assert_equal([1, "\x78\x56\x34\x12"], Bug::Bignum.test_pack(0x12345678, 2, 2, 0, LSWORD_FIRST|LSBYTE_FIRST)) + end + + def test_pack_native_endian + assert_equal([1, [0x1234].pack("S!")], Bug::Bignum.test_pack(0x1234, 1, 2, 0, MSWORD_FIRST|NATIVE_BYTE_ORDER)) + end + + def test_pack_nail + assert_equal([1, "\x01\x00\x00\x00\x01\x01"], Bug::Bignum.test_pack(0b100011, 6, 1, 7, BIG_ENDIAN)) + assert_equal([1, "\x01\x02\x03\x04\x05\x06\x07\x08"], Bug::Bignum.test_pack(0x12345678, 8, 1, 4, BIG_ENDIAN)) + assert_equal([1, "\x00\x12\x00\x34\x00\x56\x00\x78"], Bug::Bignum.test_pack(0x12345678, 4, 2, 8, BIG_ENDIAN)) + end + + def test_pack_overflow + assert_equal([-2, "\x1"], Bug::Bignum.test_pack((-0x11), 1, 1, 4, BIG_ENDIAN)) + assert_equal([-2, "\x0"], Bug::Bignum.test_pack((-0x10), 1, 1, 4, BIG_ENDIAN)) + assert_equal([-1, "\xF"], Bug::Bignum.test_pack((-0x0F), 1, 1, 4, BIG_ENDIAN)) + assert_equal([+1, "\xF"], Bug::Bignum.test_pack((+0x0F), 1, 1, 4, BIG_ENDIAN)) + assert_equal([+2, "\x0"], Bug::Bignum.test_pack((+0x10), 1, 1, 4, BIG_ENDIAN)) + assert_equal([+2, "\x1"], Bug::Bignum.test_pack((+0x11), 1, 1, 4, BIG_ENDIAN)) + + assert_equal([-2, "\x01"], Bug::Bignum.test_pack((-0x101), 1, 1, 0, BIG_ENDIAN)) + assert_equal([-2, "\x00"], Bug::Bignum.test_pack((-0x100), 1, 1, 0, BIG_ENDIAN)) + assert_equal([-1, "\xFF"], Bug::Bignum.test_pack((-0x0FF), 1, 1, 0, BIG_ENDIAN)) + assert_equal([+1, "\xFF"], Bug::Bignum.test_pack((+0x0FF), 1, 1, 0, BIG_ENDIAN)) + assert_equal([+2, "\x00"], Bug::Bignum.test_pack((+0x100), 1, 1, 0, BIG_ENDIAN)) + assert_equal([+2, "\x01"], Bug::Bignum.test_pack((+0x101), 1, 1, 0, BIG_ENDIAN)) + + assert_equal([-2, "\x00\x00\x00\x00\x00\x00\x00\x01"], Bug::Bignum.test_pack((-0x10000000000000001), 2, 4, 0, BIG_ENDIAN)) + assert_equal([-2, "\x00\x00\x00\x00\x00\x00\x00\x00"], Bug::Bignum.test_pack((-0x10000000000000000), 2, 4, 0, BIG_ENDIAN)) + assert_equal([-1, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"], Bug::Bignum.test_pack((-0x0FFFFFFFFFFFFFFFF), 2, 4, 0, BIG_ENDIAN)) + assert_equal([+1, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"], Bug::Bignum.test_pack((+0x0FFFFFFFFFFFFFFFF), 2, 4, 0, BIG_ENDIAN)) + assert_equal([+2, "\x00\x00\x00\x00\x00\x00\x00\x00"], Bug::Bignum.test_pack((+0x10000000000000000), 2, 4, 0, BIG_ENDIAN)) + assert_equal([+2, "\x00\x00\x00\x00\x00\x00\x00\x01"], Bug::Bignum.test_pack((+0x10000000000000001), 2, 4, 0, BIG_ENDIAN)) + + 1.upto(16) {|wordsize| + 1.upto(20) {|numwords| + w = numwords*wordsize + n = 256**w + assert_equal([-2, "\x00"*(w-1)+"\x01"], Bug::Bignum.test_pack((-n-1), numwords, wordsize, 0, BIG_ENDIAN)) + assert_equal([-2, "\x00"*w], Bug::Bignum.test_pack((-n ), numwords, wordsize, 0, BIG_ENDIAN)) + assert_equal([-1, "\xFF"*w], Bug::Bignum.test_pack((-n+1), numwords, wordsize, 0, BIG_ENDIAN)) + assert_equal([+1, "\xFF"*w], Bug::Bignum.test_pack((+n-1), numwords, wordsize, 0, BIG_ENDIAN)) + assert_equal([+2, "\x00"*w], Bug::Bignum.test_pack((+n ), numwords, wordsize, 0, BIG_ENDIAN)) + assert_equal([+2, "\x00"*(w-1)+"\x01"], Bug::Bignum.test_pack((+n+1), numwords, wordsize, 0, BIG_ENDIAN)) } - end - - def test_pack_sign - assert_equal([-1, "\x01"], Bug::Bignum.test_pack((-1), 1, 1, 0, BIG_ENDIAN)) - assert_equal([-1, "\x80\x70\x60\x50\x40\x30\x20\x10"], Bug::Bignum.test_pack((-0x8070605040302010), 8, 1, 0, BIG_ENDIAN)) - end - - def test_pack_orders - [MSWORD_FIRST, LSWORD_FIRST].each {|word_order| - [MSBYTE_FIRST, LSBYTE_FIRST, NATIVE_BYTE_ORDER].each {|byte_order| - 1.upto(16) {|wordsize| - 1.upto(20) {|numwords| - w = numwords*wordsize - n = 0; - 0.upto(w) {|i| - n |= ((i+1) % 256) << (i*8) - } - assert_equal(Bug::Bignum.test_pack(n, numwords, wordsize, 0, word_order|byte_order|GENERIC), - Bug::Bignum.test_pack(n, numwords, wordsize, 0, word_order|byte_order), - "#{'%#x' % n}.test_pack(#{numwords}, #{wordsize}, 0, #{'%#x' % (word_order|byte_order)})") + } + + 1.upto(16) {|wordsize| + 1.upto(20) {|numwords| + w = numwords*wordsize + n = 256**w + assert_equal([-2, "\x01"+"\x00"*(w-1)], Bug::Bignum.test_pack((-n-1), numwords, wordsize, 0, LITTLE_ENDIAN)) + assert_equal([-2, "\x00"*w], Bug::Bignum.test_pack((-n ), numwords, wordsize, 0, LITTLE_ENDIAN)) + assert_equal([-1, "\xFF"*w], Bug::Bignum.test_pack((-n+1), numwords, wordsize, 0, LITTLE_ENDIAN)) + assert_equal([+1, "\xFF"*w], Bug::Bignum.test_pack((+n-1), numwords, wordsize, 0, LITTLE_ENDIAN)) + assert_equal([+2, "\x00"*w], Bug::Bignum.test_pack((+n ), numwords, wordsize, 0, LITTLE_ENDIAN)) + assert_equal([+2, "\x01"+"\x00"*(w-1)], Bug::Bignum.test_pack((+n+1), numwords, wordsize, 0, LITTLE_ENDIAN)) + } + } + end + + def test_pack_sign + assert_equal([-1, "\x01"], Bug::Bignum.test_pack((-1), 1, 1, 0, BIG_ENDIAN)) + assert_equal([-1, "\x80\x70\x60\x50\x40\x30\x20\x10"], Bug::Bignum.test_pack((-0x8070605040302010), 8, 1, 0, BIG_ENDIAN)) + end + + def test_pack_orders + [MSWORD_FIRST, LSWORD_FIRST].each {|word_order| + [MSBYTE_FIRST, LSBYTE_FIRST, NATIVE_BYTE_ORDER].each {|byte_order| + 1.upto(16) {|wordsize| + 1.upto(20) {|numwords| + w = numwords*wordsize + n = 0; + 0.upto(w) {|i| + n |= ((i+1) % 256) << (i*8) } + assert_equal(Bug::Bignum.test_pack(n, numwords, wordsize, 0, word_order|byte_order|GENERIC), + Bug::Bignum.test_pack(n, numwords, wordsize, 0, word_order|byte_order), + "#{'%#x' % n}.test_pack(#{numwords}, #{wordsize}, 0, #{'%#x' % (word_order|byte_order)})") } } } - end - - def test_pack2comp_zero - assert_equal([0, ""], Bug::Bignum.test_pack(0, 0, 1, 0, TWOCOMP|BIG_ENDIAN)) - end - - def test_pack2comp_emptybuf - assert_equal([-2, ""], Bug::Bignum.test_pack((-3), 0, 1, 0, TWOCOMP|BIG_ENDIAN)) - assert_equal([-2, ""], Bug::Bignum.test_pack((-2), 0, 1, 0, TWOCOMP|BIG_ENDIAN)) - assert_equal([-1, ""], Bug::Bignum.test_pack((-1), 0, 1, 0, TWOCOMP|BIG_ENDIAN)) - assert_equal([ 0, ""], Bug::Bignum.test_pack(0, 0, 1, 0, TWOCOMP|BIG_ENDIAN)) - assert_equal([+2, ""], Bug::Bignum.test_pack(1, 0, 1, 0, TWOCOMP|BIG_ENDIAN)) - assert_equal([+2, ""], Bug::Bignum.test_pack(2, 0, 1, 0, TWOCOMP|BIG_ENDIAN)) - end - - def test_pack2comp_nearly_zero - assert_equal([-1, "\xFE"], Bug::Bignum.test_pack((-2), 1, 1, 0, TWOCOMP|BIG_ENDIAN)) - assert_equal([-1, "\xFF"], Bug::Bignum.test_pack((-1), 1, 1, 0, TWOCOMP|BIG_ENDIAN)) - assert_equal([ 0, "\x00"], Bug::Bignum.test_pack(0, 1, 1, 0, TWOCOMP|BIG_ENDIAN)) - assert_equal([+1, "\x01"], Bug::Bignum.test_pack(1, 1, 1, 0, TWOCOMP|BIG_ENDIAN)) - assert_equal([+1, "\x02"], Bug::Bignum.test_pack(2, 1, 1, 0, TWOCOMP|BIG_ENDIAN)) - end - - def test_pack2comp_overflow - assert_equal([-2, "\xF"], Bug::Bignum.test_pack((-0x11), 1, 1, 4, TWOCOMP|BIG_ENDIAN)) - assert_equal([-1, "\x0"], Bug::Bignum.test_pack((-0x10), 1, 1, 4, TWOCOMP|BIG_ENDIAN)) - assert_equal([-1, "\x1"], Bug::Bignum.test_pack((-0x0F), 1, 1, 4, TWOCOMP|BIG_ENDIAN)) - assert_equal([+1, "\xF"], Bug::Bignum.test_pack((+0x0F), 1, 1, 4, TWOCOMP|BIG_ENDIAN)) - assert_equal([+2, "\x0"], Bug::Bignum.test_pack((+0x10), 1, 1, 4, TWOCOMP|BIG_ENDIAN)) - assert_equal([+2, "\x1"], Bug::Bignum.test_pack((+0x11), 1, 1, 4, TWOCOMP|BIG_ENDIAN)) - - assert_equal([-2, "\xFF"], Bug::Bignum.test_pack((-0x101), 1, 1, 0, TWOCOMP|BIG_ENDIAN)) - assert_equal([-1, "\x00"], Bug::Bignum.test_pack((-0x100), 1, 1, 0, TWOCOMP|BIG_ENDIAN)) - assert_equal([-1, "\x01"], Bug::Bignum.test_pack((-0x0FF), 1, 1, 0, TWOCOMP|BIG_ENDIAN)) - assert_equal([+1, "\xFF"], Bug::Bignum.test_pack((+0x0FF), 1, 1, 0, TWOCOMP|BIG_ENDIAN)) - assert_equal([+2, "\x00"], Bug::Bignum.test_pack((+0x100), 1, 1, 0, TWOCOMP|BIG_ENDIAN)) - assert_equal([+2, "\x01"], Bug::Bignum.test_pack((+0x101), 1, 1, 0, TWOCOMP|BIG_ENDIAN)) - - assert_equal([-2, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"], Bug::Bignum.test_pack((-0x10000000000000001), 2, 4, 0, TWOCOMP|BIG_ENDIAN)) - assert_equal([-1, "\x00\x00\x00\x00\x00\x00\x00\x00"], Bug::Bignum.test_pack((-0x10000000000000000), 2, 4, 0, TWOCOMP|BIG_ENDIAN)) - assert_equal([-1, "\x00\x00\x00\x00\x00\x00\x00\x01"], Bug::Bignum.test_pack((-0x0FFFFFFFFFFFFFFFF), 2, 4, 0, TWOCOMP|BIG_ENDIAN)) - assert_equal([+1, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"], Bug::Bignum.test_pack((+0x0FFFFFFFFFFFFFFFF), 2, 4, 0, TWOCOMP|BIG_ENDIAN)) - assert_equal([+2, "\x00\x00\x00\x00\x00\x00\x00\x00"], Bug::Bignum.test_pack((+0x10000000000000000), 2, 4, 0, TWOCOMP|BIG_ENDIAN)) - assert_equal([+2, "\x00\x00\x00\x00\x00\x00\x00\x01"], Bug::Bignum.test_pack((+0x10000000000000001), 2, 4, 0, TWOCOMP|BIG_ENDIAN)) - - 1.upto(16) {|wordsize| - 1.upto(20) {|numwords| - w = numwords*wordsize - n = 256**w - assert_equal([-2, "\xFF"*w ], Bug::Bignum.test_pack((-n-1), numwords, wordsize, 0, TWOCOMP|BIG_ENDIAN)) - assert_equal([-1, "\x00"*w], Bug::Bignum.test_pack((-n ), numwords, wordsize, 0, TWOCOMP|BIG_ENDIAN)) - assert_equal([-1, "\x00"*(w-1)+"\x01"], Bug::Bignum.test_pack((-n+1), numwords, wordsize, 0, TWOCOMP|BIG_ENDIAN)) - assert_equal([+1, "\xFF"*w], Bug::Bignum.test_pack((+n-1), numwords, wordsize, 0, TWOCOMP|BIG_ENDIAN)) - assert_equal([+2, "\x00"*w], Bug::Bignum.test_pack((+n ), numwords, wordsize, 0, TWOCOMP|BIG_ENDIAN)) - assert_equal([+2, "\x00"*(w-1)+"\x01"], Bug::Bignum.test_pack((+n+1), numwords, wordsize, 0, TWOCOMP|BIG_ENDIAN)) - } - } + } + end - 1.upto(16) {|wordsize| - 1.upto(20) {|numwords| - w = numwords*wordsize - n = 256**w - assert_equal([-2, "\xFF"*w ], Bug::Bignum.test_pack((-n-1), numwords, wordsize, 0, TWOCOMP|LITTLE_ENDIAN)) - assert_equal([-1, "\x00"*w], Bug::Bignum.test_pack((-n ), numwords, wordsize, 0, TWOCOMP|LITTLE_ENDIAN)) - assert_equal([-1, "\x01"+"\x00"*(w-1)], Bug::Bignum.test_pack((-n+1), numwords, wordsize, 0, TWOCOMP|LITTLE_ENDIAN)) - assert_equal([+1, "\xFF"*w], Bug::Bignum.test_pack((+n-1), numwords, wordsize, 0, TWOCOMP|LITTLE_ENDIAN)) - assert_equal([+2, "\x00"*w], Bug::Bignum.test_pack((+n ), numwords, wordsize, 0, TWOCOMP|LITTLE_ENDIAN)) - assert_equal([+2, "\x01"+"\x00"*(w-1)], Bug::Bignum.test_pack((+n+1), numwords, wordsize, 0, TWOCOMP|LITTLE_ENDIAN)) - } - } + def test_pack2comp_zero + assert_equal([0, ""], Bug::Bignum.test_pack(0, 0, 1, 0, TWOCOMP|BIG_ENDIAN)) + end - 2.upto(16) {|wordsize| - w = wordsize - b = 8*wordsize-1 - n = 2**b - assert_equal([-2, "\x7F"+"\xFF"*(w-2)+"\xFF"], Bug::Bignum.test_pack((-n-1), 1, wordsize, 1, TWOCOMP|MSBYTE_FIRST)) - assert_equal([-1, "\x00"+"\x00"*(w-2)+"\x00"], Bug::Bignum.test_pack((-n ), 1, wordsize, 1, TWOCOMP|MSBYTE_FIRST)) - assert_equal([-1, "\x00"+"\x00"*(w-2)+"\x01"], Bug::Bignum.test_pack((-n+1), 1, wordsize, 1, TWOCOMP|MSBYTE_FIRST)) - assert_equal([+1, "\x7F"+"\xFF"*(w-2)+"\xFF"], Bug::Bignum.test_pack((+n-1), 1, wordsize, 1, TWOCOMP|MSBYTE_FIRST)) - assert_equal([+2, "\x00"+"\x00"*(w-2)+"\x00"], Bug::Bignum.test_pack((+n ), 1, wordsize, 1, TWOCOMP|MSBYTE_FIRST)) - assert_equal([+2, "\x00"+"\x00"*(w-2)+"\x01"], Bug::Bignum.test_pack((+n+1), 1, wordsize, 1, TWOCOMP|MSBYTE_FIRST)) - } + def test_pack2comp_emptybuf + assert_equal([-2, ""], Bug::Bignum.test_pack((-3), 0, 1, 0, TWOCOMP|BIG_ENDIAN)) + assert_equal([-2, ""], Bug::Bignum.test_pack((-2), 0, 1, 0, TWOCOMP|BIG_ENDIAN)) + assert_equal([-1, ""], Bug::Bignum.test_pack((-1), 0, 1, 0, TWOCOMP|BIG_ENDIAN)) + assert_equal([ 0, ""], Bug::Bignum.test_pack(0, 0, 1, 0, TWOCOMP|BIG_ENDIAN)) + assert_equal([+2, ""], Bug::Bignum.test_pack(1, 0, 1, 0, TWOCOMP|BIG_ENDIAN)) + assert_equal([+2, ""], Bug::Bignum.test_pack(2, 0, 1, 0, TWOCOMP|BIG_ENDIAN)) + end - 2.upto(16) {|wordsize| - w = wordsize - b = 8*wordsize-1 - n = 2**b - assert_equal([-2, "\xFF"+"\xFF"*(w-2)+"\x7F"], Bug::Bignum.test_pack((-n-1), 1, wordsize, 1, TWOCOMP|LSBYTE_FIRST)) - assert_equal([-1, "\x00"+"\x00"*(w-2)+"\x00"], Bug::Bignum.test_pack((-n ), 1, wordsize, 1, TWOCOMP|LSBYTE_FIRST)) - assert_equal([-1, "\x01"+"\x00"*(w-2)+"\x00"], Bug::Bignum.test_pack((-n+1), 1, wordsize, 1, TWOCOMP|LSBYTE_FIRST)) - assert_equal([+1, "\xFF"+"\xFF"*(w-2)+"\x7F"], Bug::Bignum.test_pack((+n-1), 1, wordsize, 1, TWOCOMP|LSBYTE_FIRST)) - assert_equal([+2, "\x00"+"\x00"*(w-2)+"\x00"], Bug::Bignum.test_pack((+n ), 1, wordsize, 1, TWOCOMP|LSBYTE_FIRST)) - assert_equal([+2, "\x01"+"\x00"*(w-2)+"\x00"], Bug::Bignum.test_pack((+n+1), 1, wordsize, 1, TWOCOMP|LSBYTE_FIRST)) + def test_pack2comp_nearly_zero + assert_equal([-1, "\xFE"], Bug::Bignum.test_pack((-2), 1, 1, 0, TWOCOMP|BIG_ENDIAN)) + assert_equal([-1, "\xFF"], Bug::Bignum.test_pack((-1), 1, 1, 0, TWOCOMP|BIG_ENDIAN)) + assert_equal([ 0, "\x00"], Bug::Bignum.test_pack(0, 1, 1, 0, TWOCOMP|BIG_ENDIAN)) + assert_equal([+1, "\x01"], Bug::Bignum.test_pack(1, 1, 1, 0, TWOCOMP|BIG_ENDIAN)) + assert_equal([+1, "\x02"], Bug::Bignum.test_pack(2, 1, 1, 0, TWOCOMP|BIG_ENDIAN)) + end + + def test_pack2comp_overflow + assert_equal([-2, "\xF"], Bug::Bignum.test_pack((-0x11), 1, 1, 4, TWOCOMP|BIG_ENDIAN)) + assert_equal([-1, "\x0"], Bug::Bignum.test_pack((-0x10), 1, 1, 4, TWOCOMP|BIG_ENDIAN)) + assert_equal([-1, "\x1"], Bug::Bignum.test_pack((-0x0F), 1, 1, 4, TWOCOMP|BIG_ENDIAN)) + assert_equal([+1, "\xF"], Bug::Bignum.test_pack((+0x0F), 1, 1, 4, TWOCOMP|BIG_ENDIAN)) + assert_equal([+2, "\x0"], Bug::Bignum.test_pack((+0x10), 1, 1, 4, TWOCOMP|BIG_ENDIAN)) + assert_equal([+2, "\x1"], Bug::Bignum.test_pack((+0x11), 1, 1, 4, TWOCOMP|BIG_ENDIAN)) + + assert_equal([-2, "\xFF"], Bug::Bignum.test_pack((-0x101), 1, 1, 0, TWOCOMP|BIG_ENDIAN)) + assert_equal([-1, "\x00"], Bug::Bignum.test_pack((-0x100), 1, 1, 0, TWOCOMP|BIG_ENDIAN)) + assert_equal([-1, "\x01"], Bug::Bignum.test_pack((-0x0FF), 1, 1, 0, TWOCOMP|BIG_ENDIAN)) + assert_equal([+1, "\xFF"], Bug::Bignum.test_pack((+0x0FF), 1, 1, 0, TWOCOMP|BIG_ENDIAN)) + assert_equal([+2, "\x00"], Bug::Bignum.test_pack((+0x100), 1, 1, 0, TWOCOMP|BIG_ENDIAN)) + assert_equal([+2, "\x01"], Bug::Bignum.test_pack((+0x101), 1, 1, 0, TWOCOMP|BIG_ENDIAN)) + + assert_equal([-2, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"], Bug::Bignum.test_pack((-0x10000000000000001), 2, 4, 0, TWOCOMP|BIG_ENDIAN)) + assert_equal([-1, "\x00\x00\x00\x00\x00\x00\x00\x00"], Bug::Bignum.test_pack((-0x10000000000000000), 2, 4, 0, TWOCOMP|BIG_ENDIAN)) + assert_equal([-1, "\x00\x00\x00\x00\x00\x00\x00\x01"], Bug::Bignum.test_pack((-0x0FFFFFFFFFFFFFFFF), 2, 4, 0, TWOCOMP|BIG_ENDIAN)) + assert_equal([+1, "\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF"], Bug::Bignum.test_pack((+0x0FFFFFFFFFFFFFFFF), 2, 4, 0, TWOCOMP|BIG_ENDIAN)) + assert_equal([+2, "\x00\x00\x00\x00\x00\x00\x00\x00"], Bug::Bignum.test_pack((+0x10000000000000000), 2, 4, 0, TWOCOMP|BIG_ENDIAN)) + assert_equal([+2, "\x00\x00\x00\x00\x00\x00\x00\x01"], Bug::Bignum.test_pack((+0x10000000000000001), 2, 4, 0, TWOCOMP|BIG_ENDIAN)) + + 1.upto(16) {|wordsize| + 1.upto(20) {|numwords| + w = numwords*wordsize + n = 256**w + assert_equal([-2, "\xFF"*w ], Bug::Bignum.test_pack((-n-1), numwords, wordsize, 0, TWOCOMP|BIG_ENDIAN)) + assert_equal([-1, "\x00"*w], Bug::Bignum.test_pack((-n ), numwords, wordsize, 0, TWOCOMP|BIG_ENDIAN)) + assert_equal([-1, "\x00"*(w-1)+"\x01"], Bug::Bignum.test_pack((-n+1), numwords, wordsize, 0, TWOCOMP|BIG_ENDIAN)) + assert_equal([+1, "\xFF"*w], Bug::Bignum.test_pack((+n-1), numwords, wordsize, 0, TWOCOMP|BIG_ENDIAN)) + assert_equal([+2, "\x00"*w], Bug::Bignum.test_pack((+n ), numwords, wordsize, 0, TWOCOMP|BIG_ENDIAN)) + assert_equal([+2, "\x00"*(w-1)+"\x01"], Bug::Bignum.test_pack((+n+1), numwords, wordsize, 0, TWOCOMP|BIG_ENDIAN)) } + } + + 1.upto(16) {|wordsize| + 1.upto(20) {|numwords| + w = numwords*wordsize + n = 256**w + assert_equal([-2, "\xFF"*w ], Bug::Bignum.test_pack((-n-1), numwords, wordsize, 0, TWOCOMP|LITTLE_ENDIAN)) + assert_equal([-1, "\x00"*w], Bug::Bignum.test_pack((-n ), numwords, wordsize, 0, TWOCOMP|LITTLE_ENDIAN)) + assert_equal([-1, "\x01"+"\x00"*(w-1)], Bug::Bignum.test_pack((-n+1), numwords, wordsize, 0, TWOCOMP|LITTLE_ENDIAN)) + assert_equal([+1, "\xFF"*w], Bug::Bignum.test_pack((+n-1), numwords, wordsize, 0, TWOCOMP|LITTLE_ENDIAN)) + assert_equal([+2, "\x00"*w], Bug::Bignum.test_pack((+n ), numwords, wordsize, 0, TWOCOMP|LITTLE_ENDIAN)) + assert_equal([+2, "\x01"+"\x00"*(w-1)], Bug::Bignum.test_pack((+n+1), numwords, wordsize, 0, TWOCOMP|LITTLE_ENDIAN)) + } + } + + 2.upto(16) {|wordsize| + w = wordsize + b = 8*wordsize-1 + n = 2**b + assert_equal([-2, "\x7F"+"\xFF"*(w-2)+"\xFF"], Bug::Bignum.test_pack((-n-1), 1, wordsize, 1, TWOCOMP|MSBYTE_FIRST)) + assert_equal([-1, "\x00"+"\x00"*(w-2)+"\x00"], Bug::Bignum.test_pack((-n ), 1, wordsize, 1, TWOCOMP|MSBYTE_FIRST)) + assert_equal([-1, "\x00"+"\x00"*(w-2)+"\x01"], Bug::Bignum.test_pack((-n+1), 1, wordsize, 1, TWOCOMP|MSBYTE_FIRST)) + assert_equal([+1, "\x7F"+"\xFF"*(w-2)+"\xFF"], Bug::Bignum.test_pack((+n-1), 1, wordsize, 1, TWOCOMP|MSBYTE_FIRST)) + assert_equal([+2, "\x00"+"\x00"*(w-2)+"\x00"], Bug::Bignum.test_pack((+n ), 1, wordsize, 1, TWOCOMP|MSBYTE_FIRST)) + assert_equal([+2, "\x00"+"\x00"*(w-2)+"\x01"], Bug::Bignum.test_pack((+n+1), 1, wordsize, 1, TWOCOMP|MSBYTE_FIRST)) + } + + 2.upto(16) {|wordsize| + w = wordsize + b = 8*wordsize-1 + n = 2**b + assert_equal([-2, "\xFF"+"\xFF"*(w-2)+"\x7F"], Bug::Bignum.test_pack((-n-1), 1, wordsize, 1, TWOCOMP|LSBYTE_FIRST)) + assert_equal([-1, "\x00"+"\x00"*(w-2)+"\x00"], Bug::Bignum.test_pack((-n ), 1, wordsize, 1, TWOCOMP|LSBYTE_FIRST)) + assert_equal([-1, "\x01"+"\x00"*(w-2)+"\x00"], Bug::Bignum.test_pack((-n+1), 1, wordsize, 1, TWOCOMP|LSBYTE_FIRST)) + assert_equal([+1, "\xFF"+"\xFF"*(w-2)+"\x7F"], Bug::Bignum.test_pack((+n-1), 1, wordsize, 1, TWOCOMP|LSBYTE_FIRST)) + assert_equal([+2, "\x00"+"\x00"*(w-2)+"\x00"], Bug::Bignum.test_pack((+n ), 1, wordsize, 1, TWOCOMP|LSBYTE_FIRST)) + assert_equal([+2, "\x01"+"\x00"*(w-2)+"\x00"], Bug::Bignum.test_pack((+n+1), 1, wordsize, 1, TWOCOMP|LSBYTE_FIRST)) + } + + end + + def test_unpack_zero + assert_equal(0, Bug::Bignum.test_unpack("", 0, 1, 0, BIG_ENDIAN)) + end + + def test_unpack_argument_check + assert_raise(ArgumentError) { Bug::Bignum.test_unpack("x", 2, 1, 0, MSBYTE_FIRST) } + assert_raise(ArgumentError) { Bug::Bignum.test_unpack("x", 1, 1, 0, MSWORD_FIRST) } + assert_raise(ArgumentError) { Bug::Bignum.test_unpack("x", 1, 0, 0, BIG_ENDIAN) } + assert_raise(ArgumentError) { Bug::Bignum.test_unpack("x", 1, 1, 8, BIG_ENDIAN) } + + # assume sizeof(ssize_t) == sizeof(intptr_t) + assert_raise(ArgumentError) { Bug::Bignum.test_unpack("x", 1, 1 << ([""].pack("p").length * 8 - 1), 0, BIG_ENDIAN) } + end + + def test_unpack_wordsize + assert_equal(1, Bug::Bignum.test_unpack("\x01", 1, 1, 0, BIG_ENDIAN)) + assert_equal(1, Bug::Bignum.test_unpack("\x00\x01", 1, 2, 0, BIG_ENDIAN)) + assert_equal(1, Bug::Bignum.test_unpack("\x00\x00\x01", 1, 3, 0, BIG_ENDIAN)) + assert_equal(1, Bug::Bignum.test_unpack("\x01", 1, 1, 0, LITTLE_ENDIAN)) + assert_equal(1, Bug::Bignum.test_unpack("\x01\x00", 1, 2, 0, LITTLE_ENDIAN)) + assert_equal(1, Bug::Bignum.test_unpack("\x01\x00\x00", 1, 3, 0, LITTLE_ENDIAN)) + end + + def test_unpack_wordorder_and_endian + assert_equal(0x01020304, Bug::Bignum.test_unpack("\x01\x02\x03\x04", 2, 2, 0, MSWORD_FIRST|MSBYTE_FIRST)) + assert_equal(0x02010403, Bug::Bignum.test_unpack("\x01\x02\x03\x04", 2, 2, 0, MSWORD_FIRST|LSBYTE_FIRST)) + assert_equal(0x03040102, Bug::Bignum.test_unpack("\x01\x02\x03\x04", 2, 2, 0, LSWORD_FIRST|MSBYTE_FIRST)) + assert_equal(0x04030201, Bug::Bignum.test_unpack("\x01\x02\x03\x04", 2, 2, 0, LSWORD_FIRST|LSBYTE_FIRST)) + end + + def test_unpack_native_endian + assert_equal("\x12\x34".unpack("S!")[0], Bug::Bignum.test_unpack("\x12\x34", 1, 2, 0, MSWORD_FIRST|NATIVE_BYTE_ORDER)) + end + + def test_unpack_nail + assert_equal(0b100011, Bug::Bignum.test_unpack("\x01\x00\x00\x00\x01\x01", 6, 1, 7, BIG_ENDIAN)) + assert_equal(0x12345678, Bug::Bignum.test_unpack("\x01\x02\x03\x04\x05\x06\x07\x08", 8, 1, 4, BIG_ENDIAN)) + assert_equal(0x12345678, Bug::Bignum.test_unpack("\x00\x12\x00\x34\x00\x56\x00\x78", 4, 2, 8, BIG_ENDIAN)) + end + + def test_unpack_sign + assert_equal(-1, Bug::Bignum.test_unpack("\x01", 1, 1, 0, BIG_ENDIAN|NEGATIVE)) + assert_equal(-0x8070605040302010, Bug::Bignum.test_unpack("\x80\x70\x60\x50\x40\x30\x20\x10", 8, 1, 0, BIG_ENDIAN|NEGATIVE)) + end - end - - def test_unpack_zero - assert_equal(0, Bug::Bignum.test_unpack("", 0, 1, 0, BIG_ENDIAN)) - end - - def test_unpack_argument_check - assert_raise(ArgumentError) { Bug::Bignum.test_unpack("x", 2, 1, 0, MSBYTE_FIRST) } - assert_raise(ArgumentError) { Bug::Bignum.test_unpack("x", 1, 1, 0, MSWORD_FIRST) } - assert_raise(ArgumentError) { Bug::Bignum.test_unpack("x", 1, 0, 0, BIG_ENDIAN) } - assert_raise(ArgumentError) { Bug::Bignum.test_unpack("x", 1, 1, 8, BIG_ENDIAN) } - - # assume sizeof(ssize_t) == sizeof(intptr_t) - assert_raise(ArgumentError) { Bug::Bignum.test_unpack("x", 1, 1 << ([""].pack("p").length * 8 - 1), 0, BIG_ENDIAN) } - end - - def test_unpack_wordsize - assert_equal(1, Bug::Bignum.test_unpack("\x01", 1, 1, 0, BIG_ENDIAN)) - assert_equal(1, Bug::Bignum.test_unpack("\x00\x01", 1, 2, 0, BIG_ENDIAN)) - assert_equal(1, Bug::Bignum.test_unpack("\x00\x00\x01", 1, 3, 0, BIG_ENDIAN)) - assert_equal(1, Bug::Bignum.test_unpack("\x01", 1, 1, 0, LITTLE_ENDIAN)) - assert_equal(1, Bug::Bignum.test_unpack("\x01\x00", 1, 2, 0, LITTLE_ENDIAN)) - assert_equal(1, Bug::Bignum.test_unpack("\x01\x00\x00", 1, 3, 0, LITTLE_ENDIAN)) - end - - def test_unpack_wordorder_and_endian - assert_equal(0x01020304, Bug::Bignum.test_unpack("\x01\x02\x03\x04", 2, 2, 0, MSWORD_FIRST|MSBYTE_FIRST)) - assert_equal(0x02010403, Bug::Bignum.test_unpack("\x01\x02\x03\x04", 2, 2, 0, MSWORD_FIRST|LSBYTE_FIRST)) - assert_equal(0x03040102, Bug::Bignum.test_unpack("\x01\x02\x03\x04", 2, 2, 0, LSWORD_FIRST|MSBYTE_FIRST)) - assert_equal(0x04030201, Bug::Bignum.test_unpack("\x01\x02\x03\x04", 2, 2, 0, LSWORD_FIRST|LSBYTE_FIRST)) - end - - def test_unpack_native_endian - assert_equal("\x12\x34".unpack("S!")[0], Bug::Bignum.test_unpack("\x12\x34", 1, 2, 0, MSWORD_FIRST|NATIVE_BYTE_ORDER)) - end - - def test_unpack_nail - assert_equal(0b100011, Bug::Bignum.test_unpack("\x01\x00\x00\x00\x01\x01", 6, 1, 7, BIG_ENDIAN)) - assert_equal(0x12345678, Bug::Bignum.test_unpack("\x01\x02\x03\x04\x05\x06\x07\x08", 8, 1, 4, BIG_ENDIAN)) - assert_equal(0x12345678, Bug::Bignum.test_unpack("\x00\x12\x00\x34\x00\x56\x00\x78", 4, 2, 8, BIG_ENDIAN)) - end - - def test_unpack_sign - assert_equal(-1, Bug::Bignum.test_unpack("\x01", 1, 1, 0, BIG_ENDIAN|NEGATIVE)) - assert_equal(-0x8070605040302010, Bug::Bignum.test_unpack("\x80\x70\x60\x50\x40\x30\x20\x10", 8, 1, 0, BIG_ENDIAN|NEGATIVE)) - end - - def test_unpack_orders - [MSWORD_FIRST, LSWORD_FIRST].each {|word_order| - [MSBYTE_FIRST, LSBYTE_FIRST, NATIVE_BYTE_ORDER].each {|byte_order| - 1.upto(16) {|wordsize| - 1.upto(20) {|numwords| - w = numwords*wordsize - ary = [] - 0.upto(w) {|i| - ary << ((i+1) % 256); - } - str = ary.pack("C*") - flags = word_order|byte_order - assert_equal(Bug::Bignum.test_unpack(str, numwords, wordsize, 0, flags|GENERIC), - Bug::Bignum.test_unpack(str, numwords, wordsize, 0, flags), - "Bug::Bignum.test_unpack(#{str.dump}, #{numwords}, #{wordsize}, 0, #{'%#x' % flags})") + def test_unpack_orders + [MSWORD_FIRST, LSWORD_FIRST].each {|word_order| + [MSBYTE_FIRST, LSBYTE_FIRST, NATIVE_BYTE_ORDER].each {|byte_order| + 1.upto(16) {|wordsize| + 1.upto(20) {|numwords| + w = numwords*wordsize + ary = [] + 0.upto(w) {|i| + ary << ((i+1) % 256); } + str = ary.pack("C*") + flags = word_order|byte_order + assert_equal(Bug::Bignum.test_unpack(str, numwords, wordsize, 0, flags|GENERIC), + Bug::Bignum.test_unpack(str, numwords, wordsize, 0, flags), + "Bug::Bignum.test_unpack(#{str.dump}, #{numwords}, #{wordsize}, 0, #{'%#x' % flags})") } } } - end - - def test_unpack2comp_single_byte - assert_equal(-128, Bug::Bignum.test_unpack("\x80", 1, 1, 0, TWOCOMP|BIG_ENDIAN)) - assert_equal( -2, Bug::Bignum.test_unpack("\xFE", 1, 1, 0, TWOCOMP|BIG_ENDIAN)) - assert_equal( -1, Bug::Bignum.test_unpack("\xFF", 1, 1, 0, TWOCOMP|BIG_ENDIAN)) - assert_equal( 0, Bug::Bignum.test_unpack("\x00", 1, 1, 0, TWOCOMP|BIG_ENDIAN)) - assert_equal( 1, Bug::Bignum.test_unpack("\x01", 1, 1, 0, TWOCOMP|BIG_ENDIAN)) - assert_equal( 2, Bug::Bignum.test_unpack("\x02", 1, 1, 0, TWOCOMP|BIG_ENDIAN)) - assert_equal( 127, Bug::Bignum.test_unpack("\x7F", 1, 1, 0, TWOCOMP|BIG_ENDIAN)) - end - - def test_unpack2comp_sequence_of_ff - assert_equal(-1, Bug::Bignum.test_unpack("\xFF"*2, 2, 1, 0, TWOCOMP|BIG_ENDIAN)) - assert_equal(-1, Bug::Bignum.test_unpack("\xFF"*3, 3, 1, 0, TWOCOMP|BIG_ENDIAN)) - assert_equal(-1, Bug::Bignum.test_unpack("\xFF"*4, 4, 1, 0, TWOCOMP|BIG_ENDIAN)) - assert_equal(-1, Bug::Bignum.test_unpack("\xFF"*5, 5, 1, 0, TWOCOMP|BIG_ENDIAN)) - assert_equal(-1, Bug::Bignum.test_unpack("\xFF"*6, 6, 1, 0, TWOCOMP|BIG_ENDIAN)) - assert_equal(-1, Bug::Bignum.test_unpack("\xFF"*7, 7, 1, 0, TWOCOMP|BIG_ENDIAN)) - assert_equal(-1, Bug::Bignum.test_unpack("\xFF"*8, 8, 1, 0, TWOCOMP|BIG_ENDIAN)) - assert_equal(-1, Bug::Bignum.test_unpack("\xFF"*9, 9, 1, 0, TWOCOMP|BIG_ENDIAN)) - end - - def test_unpack2comp_negative_single_byte - assert_equal(-256, Bug::Bignum.test_unpack("\x00", 1, 1, 0, TWOCOMP|BIG_ENDIAN|NEGATIVE)) - assert_equal(-255, Bug::Bignum.test_unpack("\x01", 1, 1, 0, TWOCOMP|BIG_ENDIAN|NEGATIVE)) - assert_equal(-254, Bug::Bignum.test_unpack("\x02", 1, 1, 0, TWOCOMP|BIG_ENDIAN|NEGATIVE)) - assert_equal(-129, Bug::Bignum.test_unpack("\x7F", 1, 1, 0, TWOCOMP|BIG_ENDIAN|NEGATIVE)) - assert_equal(-128, Bug::Bignum.test_unpack("\x80", 1, 1, 0, TWOCOMP|BIG_ENDIAN|NEGATIVE)) - assert_equal( -2, Bug::Bignum.test_unpack("\xFE", 1, 1, 0, TWOCOMP|BIG_ENDIAN|NEGATIVE)) - assert_equal( -1, Bug::Bignum.test_unpack("\xFF", 1, 1, 0, TWOCOMP|BIG_ENDIAN|NEGATIVE)) - end - - def test_unpack2comp_negative_zero - 0.upto(100) {|n| - str = "\x00"*n - flags = TWOCOMP|BIG_ENDIAN|NEGATIVE - assert_equal(-(256**n), Bug::Bignum.test_unpack(str, n, 1, 0, flags)) - flags = TWOCOMP|LITTLE_ENDIAN|NEGATIVE - assert_equal(-(256**n), Bug::Bignum.test_unpack(str, n, 1, 0, flags), - "Bug::Bignum.test_unpack(#{str.dump}, #{n}, 1, 0, #{'%#x' % flags})") - } - end + } + end + + def test_unpack2comp_single_byte + assert_equal(-128, Bug::Bignum.test_unpack("\x80", 1, 1, 0, TWOCOMP|BIG_ENDIAN)) + assert_equal( -2, Bug::Bignum.test_unpack("\xFE", 1, 1, 0, TWOCOMP|BIG_ENDIAN)) + assert_equal( -1, Bug::Bignum.test_unpack("\xFF", 1, 1, 0, TWOCOMP|BIG_ENDIAN)) + assert_equal( 0, Bug::Bignum.test_unpack("\x00", 1, 1, 0, TWOCOMP|BIG_ENDIAN)) + assert_equal( 1, Bug::Bignum.test_unpack("\x01", 1, 1, 0, TWOCOMP|BIG_ENDIAN)) + assert_equal( 2, Bug::Bignum.test_unpack("\x02", 1, 1, 0, TWOCOMP|BIG_ENDIAN)) + assert_equal( 127, Bug::Bignum.test_unpack("\x7F", 1, 1, 0, TWOCOMP|BIG_ENDIAN)) + end + + def test_unpack2comp_sequence_of_ff + assert_equal(-1, Bug::Bignum.test_unpack("\xFF"*2, 2, 1, 0, TWOCOMP|BIG_ENDIAN)) + assert_equal(-1, Bug::Bignum.test_unpack("\xFF"*3, 3, 1, 0, TWOCOMP|BIG_ENDIAN)) + assert_equal(-1, Bug::Bignum.test_unpack("\xFF"*4, 4, 1, 0, TWOCOMP|BIG_ENDIAN)) + assert_equal(-1, Bug::Bignum.test_unpack("\xFF"*5, 5, 1, 0, TWOCOMP|BIG_ENDIAN)) + assert_equal(-1, Bug::Bignum.test_unpack("\xFF"*6, 6, 1, 0, TWOCOMP|BIG_ENDIAN)) + assert_equal(-1, Bug::Bignum.test_unpack("\xFF"*7, 7, 1, 0, TWOCOMP|BIG_ENDIAN)) + assert_equal(-1, Bug::Bignum.test_unpack("\xFF"*8, 8, 1, 0, TWOCOMP|BIG_ENDIAN)) + assert_equal(-1, Bug::Bignum.test_unpack("\xFF"*9, 9, 1, 0, TWOCOMP|BIG_ENDIAN)) + end + + def test_unpack2comp_negative_single_byte + assert_equal(-256, Bug::Bignum.test_unpack("\x00", 1, 1, 0, TWOCOMP|BIG_ENDIAN|NEGATIVE)) + assert_equal(-255, Bug::Bignum.test_unpack("\x01", 1, 1, 0, TWOCOMP|BIG_ENDIAN|NEGATIVE)) + assert_equal(-254, Bug::Bignum.test_unpack("\x02", 1, 1, 0, TWOCOMP|BIG_ENDIAN|NEGATIVE)) + assert_equal(-129, Bug::Bignum.test_unpack("\x7F", 1, 1, 0, TWOCOMP|BIG_ENDIAN|NEGATIVE)) + assert_equal(-128, Bug::Bignum.test_unpack("\x80", 1, 1, 0, TWOCOMP|BIG_ENDIAN|NEGATIVE)) + assert_equal( -2, Bug::Bignum.test_unpack("\xFE", 1, 1, 0, TWOCOMP|BIG_ENDIAN|NEGATIVE)) + assert_equal( -1, Bug::Bignum.test_unpack("\xFF", 1, 1, 0, TWOCOMP|BIG_ENDIAN|NEGATIVE)) + end + + def test_unpack2comp_negative_zero + 0.upto(100) {|n| + str = "\x00"*n + flags = TWOCOMP|BIG_ENDIAN|NEGATIVE + assert_equal(-(256**n), Bug::Bignum.test_unpack(str, n, 1, 0, flags)) + flags = TWOCOMP|LITTLE_ENDIAN|NEGATIVE + assert_equal(-(256**n), Bug::Bignum.test_unpack(str, n, 1, 0, flags), + "Bug::Bignum.test_unpack(#{str.dump}, #{n}, 1, 0, #{'%#x' % flags})") + } end def test_numbits_2comp @@ -395,5 +393,4 @@ class Test_Bignum < Test::Unit::TestCase assert_equal(5, Bug::Bignum.test_numbytes_2comp_with_sign(0x7fffffffff)) assert_equal(6, Bug::Bignum.test_numbytes_2comp_with_sign(0x8000000000)) end - end diff --git a/test/-ext-/bignum/test_str2big.rb b/test/-ext-/bignum/test_str2big.rb index d5bd72a85b..d27e4d23f7 100644 --- a/test/-ext-/bignum/test_str2big.rb +++ b/test/-ext-/bignum/test_str2big.rb @@ -2,37 +2,35 @@ require 'test/unit' require "-test-/bignum" -class Test_Bignum < Test::Unit::TestCase - class TestStr2big < Test::Unit::TestCase +class TestBignum_Str2big < Test::Unit::TestCase - SIZEOF_BDIGIT = Bug::Bignum::SIZEOF_BDIGIT - BITSPERDIG = Bug::Bignum::BITSPERDIG - BDIGMAX = (1 << BITSPERDIG) - 1 + SIZEOF_BDIGIT = Bug::Bignum::SIZEOF_BDIGIT + BITSPERDIG = Bug::Bignum::BITSPERDIG + BDIGMAX = (1 << BITSPERDIG) - 1 - def test_str2big_poweroftwo - s = "1" + "0" * 1000 - n = 16 ** 1000 - assert_equal(n, Bug::Bignum.str2big_poweroftwo(s, 16, true)) - end - - def test_str2big_normal - s = "1" + "0" * 1000 - n = 10 ** 1000 - assert_equal(n, Bug::Bignum.str2big_normal(s, 10, true)) - end + def test_str2big_poweroftwo + s = "1" + "0" * 1000 + n = 16 ** 1000 + assert_equal(n, Bug::Bignum.str2big_poweroftwo(s, 16, true)) + end - def test_str2big_karatsuba - s = "1" + "0" * 1000 - n = 10 ** 1000 - assert_equal(n, Bug::Bignum.str2big_karatsuba(s, 10, true)) - end + def test_str2big_normal + s = "1" + "0" * 1000 + n = 10 ** 1000 + assert_equal(n, Bug::Bignum.str2big_normal(s, 10, true)) + end - def test_str2big_gmp - s = "1" + "0" * 1000 - n = 10 ** 1000 - assert_equal(n, Bug::Bignum.str2big_gmp(s, 10, true)) - rescue NotImplementedError - end + def test_str2big_karatsuba + s = "1" + "0" * 1000 + n = 10 ** 1000 + assert_equal(n, Bug::Bignum.str2big_karatsuba(s, 10, true)) + end + def test_str2big_gmp + s = "1" + "0" * 1000 + n = 10 ** 1000 + assert_equal(n, Bug::Bignum.str2big_gmp(s, 10, true)) + rescue NotImplementedError end + end diff --git a/test/-ext-/bug_reporter/test_bug_reporter.rb b/test/-ext-/bug_reporter/test_bug_reporter.rb index 6d3640eba5..990b6a2cc5 100644 --- a/test/-ext-/bug_reporter/test_bug_reporter.rb +++ b/test/-ext-/bug_reporter/test_bug_reporter.rb @@ -4,10 +4,10 @@ require 'tmpdir' class TestBugReporter < Test::Unit::TestCase def test_bug_reporter_add - skip if ENV['RUBY_ON_BUG'] + omit if ENV['RUBY_ON_BUG'] description = RUBY_DESCRIPTION - description = description.sub(/\+JIT /, '') if defined?(RubyVM::JIT) && RubyVM::JIT.enabled? + description = description.sub(/\+MJIT /, '') if defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? description = description.sub(/\+YJIT /, '') if defined?(RubyVM::YJIT.enabled?) && RubyVM::YJIT.enabled? expected_stderr = [ :*, @@ -19,9 +19,10 @@ class TestBugReporter < Test::Unit::TestCase ] tmpdir = Dir.mktmpdir + no_core = "Process.setrlimit(Process::RLIMIT_CORE, 0); " if defined?(Process.setrlimit) && defined?(Process::RLIMIT_CORE) args = ["--disable-gems", "-r-test-/bug_reporter", "-C", tmpdir] - stdin = "register_sample_bug_reporter(12345); Process.kill :SEGV, $$" + stdin = "#{no_core}register_sample_bug_reporter(12345); Process.kill :SEGV, $$" assert_in_out_err(args, stdin, [], expected_stderr, encoding: "ASCII-8BIT") ensure FileUtils.rm_rf(tmpdir) if tmpdir diff --git a/test/-ext-/float/test_nextafter.rb b/test/-ext-/float/test_nextafter.rb index e0a76935b1..ea8d7c7fc7 100644 --- a/test/-ext-/float/test_nextafter.rb +++ b/test/-ext-/float/test_nextafter.rb @@ -52,7 +52,7 @@ class TestFloatExt < Test::Unit::TestCase "#{'%a' % v2} = Bug::Float.system_nextafter(#{'%a' % n1}, #{'%a' % n2})") rescue Test::Unit::AssertionFailedError if /aix/ =~ RUBY_PLATFORM - skip "Known bug in nextafter(3) on AIX" + omit "Known bug in nextafter(3) on AIX" end raise $! end diff --git a/test/-ext-/funcall/test_funcall.rb b/test/-ext-/funcall/test_funcall.rb deleted file mode 100644 index 01a03bf5ef..0000000000 --- a/test/-ext-/funcall/test_funcall.rb +++ /dev/null @@ -1,11 +0,0 @@ -# frozen_string_literal: true -require 'test/unit' - -class TestFuncall < Test::Unit::TestCase - require '-test-/funcall' - - def test_funcall_extra_args - assert_equal 'TestFuncall', TestFuncall.extra_args_name, - '[ruby-core:85266] [Bug #14425]' - end -end diff --git a/test/-ext-/funcall/test_passing_block.rb b/test/-ext-/funcall/test_passing_block.rb index 71c9d905be..8964403494 100644 --- a/test/-ext-/funcall/test_passing_block.rb +++ b/test/-ext-/funcall/test_passing_block.rb @@ -9,6 +9,11 @@ class TestFuncall < Test::Unit::TestCase end require '-test-/funcall' + def test_funcall_extra_args + assert_equal 'TestFuncall', TestFuncall.extra_args_name, + '[ruby-core:85266] [Bug #14425]' + end + def test_with_funcall2 ok = nil Relay.with_funcall2("feature#4504") {|arg| ok = arg || true} diff --git a/test/-ext-/gvl/test_ubf_async_safe.rb b/test/-ext-/gvl/test_ubf_async_safe.rb index fdaa4d418b..3261b42475 100644 --- a/test/-ext-/gvl/test_ubf_async_safe.rb +++ b/test/-ext-/gvl/test_ubf_async_safe.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true class TestUbfAsyncSafe < Test::Unit::TestCase def test_ubf_async_safe - skip 'need fork for single-threaded test' unless Process.respond_to?(:fork) + omit 'need fork for single-threaded test' unless Process.respond_to?(:fork) IO.pipe do |r, w| pid = fork do require '-test-/gvl/call_without_gvl' diff --git a/test/-ext-/iseq_load/test_iseq_load.rb b/test/-ext-/iseq_load/test_iseq_load.rb index ffa6541c72..6e5bc8e811 100644 --- a/test/-ext-/iseq_load/test_iseq_load.rb +++ b/test/-ext-/iseq_load/test_iseq_load.rb @@ -98,7 +98,7 @@ class TestIseqLoad < Test::Unit::TestCase iseq = ISeq.iseq_load(a) iseq.eval assert_equal false, @next_broke - skip "failing due to stack_max mismatch" + omit "failing due to stack_max mismatch" assert_iseq_roundtrip(src) end @@ -121,7 +121,7 @@ class TestIseqLoad < Test::Unit::TestCase iseq = ISeq.iseq_load(a) iseq.eval assert_equal false, test_break_ensure_def_method - skip "failing due to exception entry sp mismatch" + omit "failing due to exception entry sp mismatch" assert_iseq_roundtrip(src) end @@ -137,7 +137,7 @@ class TestIseqLoad < Test::Unit::TestCase # FIXME: still failing def test_require_integration - skip "iseq loader require integration tests still failing" + omit "iseq loader require integration tests still failing" f = File.expand_path(__FILE__) # $(top_srcdir)/test/ruby/test_....rb 3.times { f = File.dirname(f) } diff --git a/test/-ext-/string/test_capacity.rb b/test/-ext-/string/test_capacity.rb index 583c98fca4..0cb7c00761 100644 --- a/test/-ext-/string/test_capacity.rb +++ b/test/-ext-/string/test_capacity.rb @@ -5,13 +5,14 @@ require 'rbconfig/sizeof' class Test_StringCapacity < Test::Unit::TestCase def test_capacity_embedded - assert_equal GC::INTERNAL_CONSTANTS[:RVALUE_SIZE] - embed_header_size - 1, capa('foo') + assert_equal GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE] - embed_header_size - 1, capa('foo') assert_equal max_embed_len, capa('1' * max_embed_len) assert_equal max_embed_len, capa('1' * (max_embed_len - 1)) end def test_capacity_shared - assert_equal 0, capa(:abcdefghijklmnopqrstuvwxyz.to_s) + sym = ("a" * GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE]).to_sym + assert_equal 0, capa(sym.to_s) end def test_capacity_normal @@ -46,13 +47,13 @@ class Test_StringCapacity < Test::Unit::TestCase def test_capacity_frozen s = String.new("I am testing", capacity: 1000) - s << "fstring capacity" + s << "a" * GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE] s.freeze assert_equal(s.length, capa(s)) end def test_capacity_fstring - s = String.new("a" * max_embed_len, capacity: 1000) + s = String.new("a" * max_embed_len, capacity: max_embed_len * 3) s << "fstring capacity" s = -s assert_equal(s.length, capa(s)) @@ -66,7 +67,7 @@ class Test_StringCapacity < Test::Unit::TestCase def embed_header_size if GC.using_rvargc? - 2 * RbConfig::SIZEOF['void*'] + RbConfig::SIZEOF['short'] + 2 * RbConfig::SIZEOF['void*'] + RbConfig::SIZEOF['long'] else 2 * RbConfig::SIZEOF['void*'] end diff --git a/test/-ext-/string/test_fstring.rb b/test/-ext-/string/test_fstring.rb index 9b4956ecef..5a3456c566 100644 --- a/test/-ext-/string/test_fstring.rb +++ b/test/-ext-/string/test_fstring.rb @@ -57,18 +57,4 @@ class Test_String_Fstring < Test::Unit::TestCase str.freeze assert_fstring(str) {|s| assert_instance_of(S, s)} end - - def test_shared_string_safety - _unused = -('a' * 30).force_encoding(Encoding::ASCII) - begin - verbose_back, $VERBOSE = $VERBOSE, nil - str = ('a' * 30).force_encoding(Encoding::ASCII).taint - ensure - $VERBOSE = verbose_back - end - frozen_str = Bug::String.rb_str_new_frozen(str) - assert_fstring(frozen_str) {|s| assert_equal(str, s)} - GC.start - assert_equal('a' * 30, str, "[Bug #16151]") - end end diff --git a/test/-ext-/string/test_set_len.rb b/test/-ext-/string/test_set_len.rb index 58f51012fb..67ba961194 100644 --- a/test/-ext-/string/test_set_len.rb +++ b/test/-ext-/string/test_set_len.rb @@ -4,23 +4,25 @@ require "-test-/string" class Test_StrSetLen < Test::Unit::TestCase def setup - @s0 = [*"a".."z"].join("").freeze + # Make string long enough so that it is not embedded + @range_end = ("0".ord + GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE]).chr + @s0 = [*"0"..@range_end].join("").freeze @s1 = Bug::String.new(@s0) end def teardown - orig = [*"a".."z"].join("") + orig = [*"0"..@range_end].join("") assert_equal(orig, @s0) end def test_non_shared @s1.modify! - assert_equal("abc", @s1.set_len(3)) + assert_equal("012", @s1.set_len(3)) end def test_shared assert_raise(RuntimeError) { - assert_equal("abc", @s1.set_len(3)) + @s1.set_len(3) } end diff --git a/test/-ext-/test_abi.rb b/test/-ext-/test_abi.rb new file mode 100644 index 0000000000..ec2050ecad --- /dev/null +++ b/test/-ext-/test_abi.rb @@ -0,0 +1,43 @@ +# frozen_string_literal: true + +class TestABI < Test::Unit::TestCase + def test_require_lib_with_incorrect_abi_on_dev_ruby + omit "ABI is not checked" unless abi_checking_supported? + + assert_separately [], <<~RUBY + err = assert_raise(LoadError) { require "-test-/abi" } + assert_match(/ABI version of binary is incompatible with this Ruby/, err.message) + RUBY + end + + def test_disable_abi_check_using_environment_variable + omit "ABI is not checked" unless abi_checking_supported? + + assert_separately [{ "RUBY_ABI_CHECK" => "0" }], <<~RUBY + assert_nothing_raised { require "-test-/abi" } + RUBY + end + + def test_enable_abi_check_using_environment_variable + omit "ABI is not checked" unless abi_checking_supported? + + assert_separately [{ "RUBY_ABI_CHECK" => "1" }], <<~RUBY + err = assert_raise(LoadError) { require "-test-/abi" } + assert_match(/ABI version of binary is incompatible with this Ruby/, err.message) + RUBY + end + + def test_require_lib_with_incorrect_abi_on_release_ruby + omit "ABI is enforced" if abi_checking_supported? + + assert_separately [], <<~RUBY + assert_nothing_raised { require "-test-/abi" } + RUBY + end + + private + + def abi_checking_supported? + !(RUBY_PLATFORM =~ /mswin|mingw/) + end +end diff --git a/test/bigdecimal/helper.rb b/test/bigdecimal/helper.rb index 22b05f09ae..46721fb9a8 100644 --- a/test/bigdecimal/helper.rb +++ b/test/bigdecimal/helper.rb @@ -1,8 +1,19 @@ # frozen_string_literal: false require "test/unit" require "bigdecimal" +require 'rbconfig/sizeof' module TestBigDecimalBase + if RbConfig::SIZEOF.key?("int64_t") + SIZEOF_DECDIG = RbConfig::SIZEOF["int32_t"] + BASE = 1_000_000_000 + BASE_FIG = 9 + else + SIZEOF_DECDIG = RbConfig::SIZEOF["int16_t"] + BASE = 1000 + BASE_FIG = 4 + end + def setup @mode = BigDecimal.mode(BigDecimal::EXCEPTION_ALL) BigDecimal.mode(BigDecimal::EXCEPTION_ALL, true) diff --git a/test/bigdecimal/test_bigdecimal.rb b/test/bigdecimal/test_bigdecimal.rb index 49e6b2a70e..0cd85249ad 100644 --- a/test/bigdecimal/test_bigdecimal.rb +++ b/test/bigdecimal/test_bigdecimal.rb @@ -1,7 +1,6 @@ # frozen_string_literal: false require_relative "helper" require 'bigdecimal/math' -require 'rbconfig/sizeof' class TestBigDecimal < Test::Unit::TestCase include TestBigDecimalBase @@ -12,7 +11,12 @@ class TestBigDecimal < Test::Unit::TestCase require 'fiddle' LONG_MAX = (1 << (Fiddle::SIZEOF_LONG*8 - 1)) - 1 LONG_MIN = [LONG_MAX + 1].pack("L!").unpack("l!")[0] + LLONG_MAX = (1 << (Fiddle::SIZEOF_LONG_LONG*8 - 1)) - 1 + LLONG_MIN = [LLONG_MAX + 1].pack("Q!").unpack("q!")[0] + ULLONG_MAX = (1 << Fiddle::SIZEOF_LONG_LONG*8) - 1 LIMITS = { + "LLONG_MIN" => LLONG_MIN, + "ULLONG_MAX" => ULLONG_MAX, "FIXNUM_MIN" => LONG_MIN / 2, "FIXNUM_MAX" => LONG_MAX / 2, "INT64_MIN" => -9223372036854775808, @@ -96,6 +100,19 @@ class TestBigDecimal < Test::Unit::TestCase assert_not_same(bd, BigDecimal(bd, 1, exception: false)) end + def test_BigDecimal_issue_192 + # https://github.com/ruby/bigdecimal/issues/192 + # https://github.com/rails/rails/pull/42125 + if BASE_FIG == 9 + int = 1_000_000_000_12345_0000 + big = BigDecimal("0.100000000012345e19") + else # BASE_FIG == 4 + int = 1_0000_12_00 + big = BigDecimal("0.1000012e9") + end + assert_equal(BigDecimal(int), big, "[ruby/bigdecimal#192]") + end + def test_BigDecimal_with_invalid_string [ '', '.', 'e1', 'd1', '.e', '.d', '1.e', '1.d', '.1e', '.1d', @@ -936,9 +953,13 @@ class TestBigDecimal < Test::Unit::TestCase assert_equal(2, BigDecimal("2") / 1) assert_equal(-2, BigDecimal("2") / -1) - assert_equal(BigDecimal('1486.868686869'), BigDecimal('1472.0') / BigDecimal('0.99'), '[ruby-core:59365] [#9316]') + assert_equal(BigDecimal('1486.868686869'), + (BigDecimal('1472.0') / BigDecimal('0.99')).round(9), + '[ruby-core:59365] [#9316]') - assert_equal(4.124045235, BigDecimal('0.9932') / (700 * BigDecimal('0.344045') / BigDecimal('1000.0')), '[#9305]') + assert_in_delta(4.124045235, + (BigDecimal('0.9932') / (700 * BigDecimal('0.344045') / BigDecimal('1000.0'))).round(9, half: :up), + 10**Float::MIN_10_EXP, '[#9305]') BigDecimal.mode(BigDecimal::EXCEPTION_INFINITY, false) assert_positive_zero(BigDecimal("1.0") / BigDecimal("Infinity")) @@ -948,8 +969,24 @@ class TestBigDecimal < Test::Unit::TestCase BigDecimal.mode(BigDecimal::EXCEPTION_INFINITY, true) BigDecimal.mode(BigDecimal::EXCEPTION_ZERODIVIDE, false) - assert_raise_with_message(FloatDomainError, "Computation results to 'Infinity'") { BigDecimal("1") / 0 } - assert_raise_with_message(FloatDomainError, "Computation results to '-Infinity'") { BigDecimal("-1") / 0 } + assert_raise_with_message(FloatDomainError, "Computation results in 'Infinity'") { BigDecimal("1") / 0 } + assert_raise_with_message(FloatDomainError, "Computation results in '-Infinity'") { BigDecimal("-1") / 0 } + end + + def test_div_gh220 + x = BigDecimal("1.0") + y = BigDecimal("3672577333.6608990499165058135986328125") + c = BigDecimal("0.272288343892592687909520102748926752911779209181321744700032723729015151607289998e-9") + assert_equal(c, x / y, "[GH-220]") + end + + def test_div_precision + bug13754 = '[ruby-core:82107] [Bug #13754]' + a = BigDecimal('101') + b = BigDecimal('0.9163472602589686') + c = a/b + assert(c.precision > b.precision, + "(101/0.9163472602589686).precision >= (0.9163472602589686).precision #{bug13754}") end def test_div_with_float @@ -1013,6 +1050,19 @@ class TestBigDecimal < Test::Unit::TestCase assert_raise(ZeroDivisionError){BigDecimal("0").divmod(0)} end + def test_divmod_precision + a = BigDecimal('2e55') + b = BigDecimal('1.23456789e10') + q, r = a.divmod(b) + assert_equal((a/b).round(0, :down), q) + assert_equal((a - q*b), r) + + b = BigDecimal('-1.23456789e10') + q, r = a.divmod(b) + assert_equal((a/b).round(0, :down) - 1, q) + assert_equal((a - q*b), r) + end + def test_divmod_error assert_raise(TypeError) { BigDecimal(20).divmod('2') } end @@ -1050,6 +1100,40 @@ class TestBigDecimal < Test::Unit::TestCase end end + def test_div_bigdecimal_with_float_and_precision + x = BigDecimal(5) + y = 5.1 + assert_equal(x.div(BigDecimal(y, 0), 8), + x.div(y, 8)) + + assert_equal(x.div(BigDecimal(y, 0), 100), + x.div(y, 100)) + end + + def test_quo_without_prec + x = BigDecimal(5) + y = BigDecimal(229) + assert_equal(BigDecimal("0.021834061135371179039301310043668122"), x.quo(y)) + end + + def test_quo_with_prec + begin + saved_mode = BigDecimal.mode(BigDecimal::ROUND_MODE) + BigDecimal.mode(BigDecimal::ROUND_MODE, :half_up) + + x = BigDecimal(5) + y = BigDecimal(229) + assert_equal(BigDecimal("0.021834061135371179039301310043668122"), x.quo(y, 0)) + assert_equal(BigDecimal("0.022"), x.quo(y, 2)) + assert_equal(BigDecimal("0.0218"), x.quo(y, 3)) + assert_equal(BigDecimal("0.0218341"), x.quo(y, 6)) + assert_equal(BigDecimal("0.02183406114"), x.quo(y, 10)) + assert_equal(BigDecimal("0.021834061135371179039301310043668122270742358078603"), x.quo(y, 50)) + ensure + BigDecimal.mode(BigDecimal::ROUND_MODE, saved_mode) + end + end + def test_abs_bigdecimal x = BigDecimal((2**100).to_s) assert_equal(1267650600228229401496703205376, x.abs) @@ -1995,10 +2079,14 @@ class TestBigDecimal < Test::Unit::TestCase def test_precision_only_fraction assert_equal(1, BigDecimal("0.1").precision) assert_equal(1, BigDecimal("-0.1").precision) - assert_equal(1, BigDecimal("0.01").precision) - assert_equal(1, BigDecimal("-0.01").precision) + assert_equal(2, BigDecimal("0.01").precision) + assert_equal(2, BigDecimal("-0.01").precision) assert_equal(2, BigDecimal("0.11").precision) assert_equal(2, BigDecimal("-0.11").precision) + assert_equal(9, BigDecimal("0.000_000_001").precision) + assert_equal(9, BigDecimal("-0.000_000_001").precision) + assert_equal(10, BigDecimal("0.000_000_000_1").precision) + assert_equal(10, BigDecimal("-0.000_000_000_1").precision) assert_equal(21, BigDecimal("0.000_000_000_000_000_000_001").precision) assert_equal(21, BigDecimal("-0.000_000_000_000_000_000_001").precision) assert_equal(100, BigDecimal("111e-100").precision) @@ -2006,12 +2094,8 @@ class TestBigDecimal < Test::Unit::TestCase end def test_precision_full - assert_equal(1, BigDecimal("0.1").precision) - assert_equal(1, BigDecimal("-0.1").precision) - assert_equal(1, BigDecimal("0.01").precision) - assert_equal(1, BigDecimal("-0.01").precision) - assert_equal(2, BigDecimal("0.11").precision) - assert_equal(2, BigDecimal("-0.11").precision) + assert_equal(5, BigDecimal("11111e-2").precision) + assert_equal(5, BigDecimal("-11111e-2").precision) assert_equal(5, BigDecimal("11111e-2").precision) assert_equal(5, BigDecimal("-11111e-2").precision) assert_equal(21, BigDecimal("100.000_000_000_000_000_001").precision) @@ -2029,6 +2113,70 @@ class TestBigDecimal < Test::Unit::TestCase end end + def test_scale_only_integer + assert_equal(0, BigDecimal(0).scale) + assert_equal(0, BigDecimal(1).scale) + assert_equal(0, BigDecimal(-1).scale) + assert_equal(0, BigDecimal(10).scale) + assert_equal(0, BigDecimal(-10).scale) + assert_equal(0, BigDecimal(100_000_000).scale) + assert_equal(0, BigDecimal(-100_000_000).scale) + assert_equal(0, BigDecimal(100_000_000_000).scale) + assert_equal(0, BigDecimal(-100_000_000_000).scale) + assert_equal(0, BigDecimal(100_000_000_000_000_000_000).scale) + assert_equal(0, BigDecimal(-100_000_000_000_000_000_000).scale) + assert_equal(0, BigDecimal("111e100").scale) + assert_equal(0, BigDecimal("-111e100").scale) + end + + def test_scale_only_fraction + assert_equal(1, BigDecimal("0.1").scale) + assert_equal(1, BigDecimal("-0.1").scale) + assert_equal(2, BigDecimal("0.01").scale) + assert_equal(2, BigDecimal("-0.01").scale) + assert_equal(2, BigDecimal("0.11").scale) + assert_equal(2, BigDecimal("-0.11").scale) + assert_equal(21, BigDecimal("0.000_000_000_000_000_000_001").scale) + assert_equal(21, BigDecimal("-0.000_000_000_000_000_000_001").scale) + assert_equal(100, BigDecimal("111e-100").scale) + assert_equal(100, BigDecimal("-111e-100").scale) + end + + def test_scale_full + assert_equal(1, BigDecimal("0.1").scale) + assert_equal(1, BigDecimal("-0.1").scale) + assert_equal(2, BigDecimal("0.01").scale) + assert_equal(2, BigDecimal("-0.01").scale) + assert_equal(2, BigDecimal("0.11").scale) + assert_equal(2, BigDecimal("-0.11").scale) + assert_equal(2, BigDecimal("11111e-2").scale) + assert_equal(2, BigDecimal("-11111e-2").scale) + assert_equal(18, BigDecimal("100.000_000_000_000_000_001").scale) + assert_equal(18, BigDecimal("-100.000_000_000_000_000_001").scale) + end + + def test_scale_special + BigDecimal.save_exception_mode do + BigDecimal.mode(BigDecimal::EXCEPTION_OVERFLOW, false) + BigDecimal.mode(BigDecimal::EXCEPTION_NaN, false) + + assert_equal(0, BigDecimal("Infinity").scale) + assert_equal(0, BigDecimal("-Infinity").scale) + assert_equal(0, BigDecimal("NaN").scale) + end + end + + def test_precision_scale + assert_equal([2, 0], BigDecimal("11.0").precision_scale) + assert_equal([2, 1], BigDecimal("1.1").precision_scale) + assert_equal([2, 2], BigDecimal("0.11").precision_scale) + + BigDecimal.save_exception_mode do + BigDecimal.mode(BigDecimal::EXCEPTION_OVERFLOW, false) + assert_equal([0, 0], BigDecimal("Infinity").precision_scale) + end + end + def test_n_significant_digits_only_integer assert_equal(0, BigDecimal(0).n_significant_digits) assert_equal(1, BigDecimal(1).n_significant_digits) @@ -2089,6 +2237,15 @@ class TestBigDecimal < Test::Unit::TestCase assert_raise(err) { bd.send(:initialize_dup, bd2) } end + def test_llong_min_gh_200 + # https://github.com/ruby/bigdecimal/issues/199 + # Between LLONG_MIN and -ULLONG_MAX + assert_equal(BigDecimal(LIMITS["LLONG_MIN"].to_s), BigDecimal(LIMITS["LLONG_MIN"]), "[GH-200]") + + minus_ullong_max = -LIMITS["ULLONG_MAX"] + assert_equal(BigDecimal(minus_ullong_max.to_s), BigDecimal(minus_ullong_max), "[GH-200]") + end + def assert_no_memory_leak(code, *rest, **opt) code = "8.times {20_000.times {begin #{code}; rescue NoMemoryError; end}; GC.start}" super(["-rbigdecimal"], diff --git a/test/bigdecimal/test_bigdecimal_util.rb b/test/bigdecimal/test_bigdecimal_util.rb index ffd4c5f679..2f27163ebf 100644 --- a/test/bigdecimal/test_bigdecimal_util.rb +++ b/test/bigdecimal/test_bigdecimal_util.rb @@ -25,6 +25,8 @@ class TestBigDecimalUtil < Test::Unit::TestCase assert_equal(9.05, 9.05.to_d.to_f) assert_equal("9.05", 9.05.to_d.to_s('F')) + assert_equal("65.6", 65.6.to_d.to_s("F")) + assert_equal(Math::PI, Math::PI.to_d.to_f) bug9214 = '[ruby-core:58858]' @@ -60,6 +62,19 @@ class TestBigDecimalUtil < Test::Unit::TestCase "[ruby-core:80234] [Bug #13331]") end + def test_Float_to_d_issue_192 + # https://github.com/ruby/bigdecimal/issues/192 + # https://github.com/rails/rails/pull/42125 + if BASE_FIG == 9 + flo = 1_000_000_000.12345 + big = BigDecimal("0.100000000012345e10") + else # BASE_FIG == 4 + flo = 1_0000.12 + big = BigDecimal("0.1000012e5") + end + assert_equal(flo.to_d, big, "[ruby/bigdecimal#192]") + end + def test_Rational_to_d digits = 100 delta = 1.0/10**(digits) diff --git a/test/cgi/test_cgi_util.rb b/test/cgi/test_cgi_util.rb index 6ce8b42c20..5a2d07b328 100644 --- a/test/cgi/test_cgi_util.rb +++ b/test/cgi/test_cgi_util.rb @@ -104,6 +104,23 @@ class CGIUtilTest < Test::Unit::TestCase assert_not_predicate CGI.escapeHTML("Ruby".freeze), :frozen? end + def test_cgi_escape_html_large + ulong_max, size_max = RbConfig::LIMITS.values_at("ULONG_MAX", "SIZE_MAX") + return unless ulong_max < size_max # Platforms not concerned + + size = (ulong_max / 6 + 1) + begin + str = '"' * size + escaped = CGI.escapeHTML(str) + rescue NoMemoryError + omit "Not enough memory" + rescue => e + end + assert_raise_with_message(ArgumentError, /overflow/, ->{"length = #{escaped.length}"}) do + raise e if e + end + end + def test_cgi_unescapeHTML assert_equal("'&\"><", CGI.unescapeHTML("'&"><")) end diff --git a/test/csv/parse/test_convert.rb b/test/csv/parse/test_convert.rb index bfe6ddd527..21d9f20b28 100644 --- a/test/csv/parse/test_convert.rb +++ b/test/csv/parse/test_convert.rb @@ -43,7 +43,7 @@ class TestCSVParseConvert < Test::Unit::TestCase @parser.shift) end - def test_numberic + def test_numeric @parser.convert(:numeric) assert_equal(["Numbers", ":integer", 1, ":float", 3.015], @parser.shift) diff --git a/test/csv/parse/test_general.rb b/test/csv/parse/test_general.rb index 14903d462c..d2b74008eb 100644 --- a/test/csv/parse/test_general.rb +++ b/test/csv/parse/test_general.rb @@ -14,7 +14,7 @@ require_relative "../helper" class TestCSVParseGeneral < Test::Unit::TestCase extend DifferentOFS - BIG_DATA = "123456789\n" * 1024 + BIG_DATA = "123456789\n" * 512 def test_mastering_regex_example ex = %Q{Ten Thousand,10000, 2710 ,,"10,000","It's ""10 Grand"", baby",10K} @@ -247,7 +247,7 @@ line,5,jkl def assert_parse_errors_out(data, **options) assert_raise(CSV::MalformedCSVError) do timeout = 0.2 - if defined?(RubyVM::JIT.enabled?) and RubyVM::JIT.enabled? + if defined?(RubyVM::MJIT.enabled?) and RubyVM::MJIT.enabled? timeout = 5 # for --jit-wait end Timeout.timeout(timeout) do diff --git a/test/csv/parse/test_strip.rb b/test/csv/parse/test_strip.rb index 3564fcb3ba..c5e35209cc 100644 --- a/test/csv/parse/test_strip.rb +++ b/test/csv/parse/test_strip.rb @@ -80,4 +80,33 @@ class TestCSVParseStrip < Test::Unit::TestCase %Q{"a" ,"b " \r\n}, strip: true)) end + + def test_col_sep_incompatible_true + message = "The provided strip (true) and " \ + "col_sep (\\t) options are incompatible." + assert_raise_with_message(ArgumentError, message) do + CSV.parse_line(%Q{"a"\t"b"\n}, + col_sep: "\t", + strip: true) + end + end + + def test_col_sep_incompatible_string + message = "The provided strip (\\t) and " \ + "col_sep (\\t) options are incompatible." + assert_raise_with_message(ArgumentError, message) do + CSV.parse_line(%Q{"a"\t"b"\n}, + col_sep: "\t", + strip: "\t") + end + end + + def test_col_sep_compatible_string + assert_equal( + ["a", "b"], + CSV.parse_line(%Q{\va\tb\v\n}, + col_sep: "\t", + strip: "\v") + ) + end end diff --git a/test/csv/test_table.rb b/test/csv/test_table.rb index 3202963a67..968e64eae7 100644 --- a/test/csv/test_table.rb +++ b/test/csv/test_table.rb @@ -20,7 +20,7 @@ class TestCSVTable < Test::Unit::TestCase @header_only_table = CSV::Table.new([], headers: %w{A B C}) end - def test_initialze + def test_initialize assert_not_nil(@table) assert_instance_of(CSV::Table, @table) end diff --git a/test/date/test_date_parse.rb b/test/date/test_date_parse.rb index 34a672b069..d8dcf6e05e 100644 --- a/test/date/test_date_parse.rb +++ b/test/date/test_date_parse.rb @@ -1,7 +1,7 @@ # frozen_string_literal: true require 'test/unit' require 'date' -require 'timeout' +require 'envutil' class TestDateParse < Test::Unit::TestCase @@ -585,6 +585,18 @@ class TestDateParse < Test::Unit::TestCase assert_equal(5025, h[:offset]) end + def test__parse_too_long_year + str = "Jan 1" + "0" * 100_000 + h = EnvUtil.timeout(3) {Date._parse(str, limit: 100_010)} + assert_equal(100_000, Math.log10(h[:year])) + assert_equal(1, h[:mon]) + + str = "Jan - 1" + "0" * 100_000 + h = EnvUtil.timeout(3) {Date._parse(str, limit: 100_010)} + assert_equal(1, h[:mon]) + assert_not_include(h, :year) + end + require 'time' def test_parse__time @@ -852,7 +864,7 @@ class TestDateParse < Test::Unit::TestCase h = Date._iso8601(nil) assert_equal({}, h) - h = Date._iso8601('01-02-03T04:05:06Z'.to_sym) + h = assert_deprecated_warn {Date._iso8601('01-02-03T04:05:06Z'.to_sym)} assert_equal([2001, 2, 3, 4, 5, 6, 0], h.values_at(:year, :mon, :mday, :hour, :min, :sec, :offset)) end @@ -874,7 +886,7 @@ class TestDateParse < Test::Unit::TestCase h = Date._rfc3339(nil) assert_equal({}, h) - h = Date._rfc3339('2001-02-03T04:05:06Z'.to_sym) + h = assert_deprecated_warn {Date._rfc3339('2001-02-03T04:05:06Z'.to_sym)} assert_equal([2001, 2, 3, 4, 5, 6, 0], h.values_at(:year, :mon, :mday, :hour, :min, :sec, :offset)) end @@ -963,7 +975,7 @@ class TestDateParse < Test::Unit::TestCase h = Date._xmlschema(nil) assert_equal({}, h) - h = Date._xmlschema('2001-02-03'.to_sym) + h = assert_deprecated_warn {Date._xmlschema('2001-02-03'.to_sym)} assert_equal([2001, 2, 3, nil, nil, nil, nil], h.values_at(:year, :mon, :mday, :hour, :min, :sec, :offset)) end @@ -1002,7 +1014,7 @@ class TestDateParse < Test::Unit::TestCase h = Date._rfc2822(nil) assert_equal({}, h) - h = Date._rfc2822('Sat, 3 Feb 2001 04:05:06 UT'.to_sym) + h = assert_deprecated_warn {Date._rfc2822('Sat, 3 Feb 2001 04:05:06 UT'.to_sym)} assert_equal([2001, 2, 3, 4, 5, 6, 0], h.values_at(:year, :mon, :mday, :hour, :min, :sec, :offset)) end @@ -1029,7 +1041,7 @@ class TestDateParse < Test::Unit::TestCase h = Date._httpdate(nil) assert_equal({}, h) - h = Date._httpdate('Sat, 03 Feb 2001 04:05:06 GMT'.to_sym) + h = assert_deprecated_warn {Date._httpdate('Sat, 03 Feb 2001 04:05:06 GMT'.to_sym)} assert_equal([2001, 2, 3, 4, 5, 6, 0], h.values_at(:year, :mon, :mday, :hour, :min, :sec, :offset)) end @@ -1112,7 +1124,7 @@ class TestDateParse < Test::Unit::TestCase h = Date._jisx0301(nil) assert_equal({}, h) - h = Date._jisx0301('H13.02.03T04:05:06.07+0100'.to_sym) + h = assert_deprecated_warn {Date._jisx0301('H13.02.03T04:05:06.07+0100'.to_sym)} assert_equal([2001, 2, 3, 4, 5, 6, 3600], h.values_at(:year, :mon, :mday, :hour, :min, :sec, :offset)) end @@ -1297,6 +1309,5 @@ class TestDateParse < Test::Unit::TestCase assert_raise(ArgumentError) { DateTime.jisx0301("1" * 1000) } assert_raise(ArgumentError) { Date._parse("Jan " + "9" * 1000000) } - assert_raise(Timeout::Error) { Timeout.timeout(1) { Date._parse("Jan " + "9" * 1000000, limit: nil) } } end end diff --git a/test/date/test_date_ractor.rb b/test/date/test_date_ractor.rb index 7b0c3f4911..7ec953d87a 100644 --- a/test/date/test_date_ractor.rb +++ b/test/date/test_date_ractor.rb @@ -2,7 +2,7 @@ require 'test/unit' require 'date' -class TestDateParse < Test::Unit::TestCase +class TestDateParseRactor < Test::Unit::TestCase def code(klass = Date, share: false) <<~RUBY.gsub('Date', klass.name) share = #{share} diff --git a/test/date/test_date_strftime.rb b/test/date/test_date_strftime.rb index be9354504a..dd04c0d9a4 100644 --- a/test/date/test_date_strftime.rb +++ b/test/date/test_date_strftime.rb @@ -125,7 +125,7 @@ class TestDateStrftime < Test::Unit::TestCase def test_strftime__3_2 s = Time.now.strftime('%G') - skip if s.empty? || s == '%G' + omit if s.empty? || s == '%G' (Date.new(1970,1,1)..Date.new(2037,12,31)).each do |d| t = Time.utc(d.year,d.mon,d.mday) assert_equal(t.strftime('%G'), d.strftime('%G')) diff --git a/test/did_you_mean/core_ext/test_name_error_extension.rb b/test/did_you_mean/core_ext/test_name_error_extension.rb index 9dc08dbde3..91871cda9a 100644 --- a/test/did_you_mean/core_ext/test_name_error_extension.rb +++ b/test/did_you_mean/core_ext/test_name_error_extension.rb @@ -1,7 +1,7 @@ require_relative '../helper' class NameErrorExtensionTest < Test::Unit::TestCase - SPELL_CHECKERS = DidYouMean::SPELL_CHECKERS + SPELL_CHECKERS = DidYouMean.spell_checkers class TestSpellChecker def initialize(*); end @@ -9,13 +9,14 @@ class NameErrorExtensionTest < Test::Unit::TestCase end def setup - @org, SPELL_CHECKERS['NameError'] = SPELL_CHECKERS['NameError'], TestSpellChecker + @original_spell_checker = DidYouMean.spell_checkers['NameError'] + DidYouMean.correct_error(NameError, TestSpellChecker) @error = assert_raise(NameError){ doesnt_exist } end def teardown - SPELL_CHECKERS['NameError'] = @org + DidYouMean.correct_error(NameError, @original_spell_checker) end def test_message diff --git a/test/did_you_mean/helper.rb b/test/did_you_mean/helper.rb index d8aa41c3d1..7cb7b10282 100644 --- a/test/did_you_mean/helper.rb +++ b/test/did_you_mean/helper.rb @@ -4,6 +4,10 @@ module DidYouMean module TestHelper class << self attr_reader :root + + def ractor_compatible? + defined?(Ractor) && RUBY_VERSION >= "3.1.0" + end end if File.file?(File.expand_path('../lib/did_you_mean.rb', __dir__)) diff --git a/test/did_you_mean/test_ractor_compatibility.rb b/test/did_you_mean/test_ractor_compatibility.rb new file mode 100644 index 0000000000..f66a1a9d62 --- /dev/null +++ b/test/did_you_mean/test_ractor_compatibility.rb @@ -0,0 +1,117 @@ +require_relative './helper' + +return if not DidYouMean::TestHelper.ractor_compatible? + +class RactorCompatibilityTest < Test::Unit::TestCase + def test_class_name_suggestion_works_in_ractor + assert_ractor(<<~CODE, require_relative: "helper") + class ::Book; end + include DidYouMean::TestHelper + error = Ractor.new { + begin + Boook + rescue NameError => e + e.corrections # It is important to call the #corrections method within Ractor. + e + end + }.take + + assert_correction "Book", error.corrections + CODE + end + + def test_key_name_suggestion_works_in_ractor + assert_ractor(<<~CODE, require_relative: "helper") + include DidYouMean::TestHelper + error = Ractor.new { + begin + hash = { "foo" => 1, bar: 2 } + + hash.fetch(:bax) + rescue KeyError => e + e.corrections # It is important to call the #corrections method within Ractor. + e + end + }.take + + assert_correction ":bar", error.corrections + assert_match "Did you mean? :bar", error.to_s + CODE + end + + def test_method_name_suggestion_works_in_ractor + assert_ractor(<<~CODE, require_relative: "helper") + include DidYouMean::TestHelper + error = Ractor.new { + begin + self.to__s + rescue NoMethodError => e + e.corrections # It is important to call the #corrections method within Ractor. + e + end + }.take + + assert_correction :to_s, error.corrections + assert_match "Did you mean? to_s", error.to_s + CODE + end + + if defined?(::NoMatchingPatternKeyError) + def test_pattern_key_name_suggestion_works_in_ractor + assert_ractor(<<~CODE, require_relative: "helper") + include DidYouMean::TestHelper + error = Ractor.new { + begin + eval(<<~RUBY, binding, __FILE__, __LINE__) + hash = {foo: 1, bar: 2, baz: 3} + hash => {fooo:} + fooo = 1 # suppress "unused variable: fooo" warning + RUBY + rescue NoMatchingPatternKeyError => e + e.corrections # It is important to call the #corrections method within Ractor. + e + end + }.take + + assert_correction ":foo", error.corrections + assert_match "Did you mean? :foo", error.to_s + CODE + end + end + + def test_can_raise_other_name_error_in_ractor + assert_ractor(<<~CODE, require_relative: "helper") + class FirstNameError < NameError; end + include DidYouMean::TestHelper + error = Ractor.new { + begin + raise FirstNameError, "Other name error" + rescue FirstNameError => e + e.corrections # It is important to call the #corrections method within Ractor. + e + end + }.take + + assert_not_match(/Did you mean\?/, error.message) + CODE + end + + def test_variable_name_suggestion_works_in_ractor + assert_ractor(<<~CODE, require_relative: "helper") + include DidYouMean::TestHelper + error = Ractor.new { + in_ractor = in_ractor = 1 + + begin + in_reactor + rescue NameError => e + e.corrections # It is important to call the #corrections method within Ractor. + e + end + }.take + + assert_correction :in_ractor, error.corrections + assert_match "Did you mean? in_ractor", error.to_s + CODE + end +end diff --git a/test/drb/drbtest.rb b/test/drb/drbtest.rb index f3d20201bc..3c33aedb6f 100644 --- a/test/drb/drbtest.rb +++ b/test/drb/drbtest.rb @@ -216,7 +216,7 @@ module DRbCore def test_06_timeout omit if RUBY_PLATFORM.include?("armv7l-linux") omit if RUBY_PLATFORM.include?("sparc-solaris2.10") - omit if defined?(RubyVM::JIT) && RubyVM::JIT.enabled? # expecting a certain delay is difficult for --jit-wait CI + omit if defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? # expecting a certain delay is difficult for --jit-wait CI Timeout.timeout(60) do ten = Onecky.new(10) assert_raise(Timeout::Error) do diff --git a/test/dtrace/helper.rb b/test/dtrace/helper.rb index ce730800b4..7fa16965f1 100644 --- a/test/dtrace/helper.rb +++ b/test/dtrace/helper.rb @@ -122,7 +122,7 @@ module DTrace def trap_probe d_program, ruby_program if Hash === d_program d_program = d_program[IMPL] or - skip "#{d_program} not implemented for #{IMPL}" + omit "#{d_program} not implemented for #{IMPL}" elsif String === d_program && IMPL == :stap d_program = dtrace2systemtap(d_program) end diff --git a/test/error_highlight/test_error_highlight.rb b/test/error_highlight/test_error_highlight.rb index 08036bca54..a3cc7aa149 100644 --- a/test/error_highlight/test_error_highlight.rb +++ b/test/error_highlight/test_error_highlight.rb @@ -1194,4 +1194,34 @@ undefined method `time' for 1:Integer end end end + + def test_simulate_funcallv_from_embedded_ruby + assert_error_message(NoMethodError, <<~END) do +undefined method `foo' for nil:NilClass + END + + nil.foo + 1 + rescue NoMethodError => exc + def exc.backtrace_locations = [] + raise + end + end + + def test_spoofed_filename + Tempfile.create(["error_highlight_test", ".rb"], binmode: true) do |tmp| + tmp << "module Dummy\nend\n" + tmp.close + + assert_error_message(NameError, <<~END) do + undefined local variable or method `foo' for "dummy":String + END + + "dummy".instance_eval do + eval <<-END, nil, tmp.path + foo + END + end + end + end + end end diff --git a/test/excludes/TestGem.rb b/test/excludes/TestGem.rb new file mode 100644 index 0000000000..042af26eff --- /dev/null +++ b/test/excludes/TestGem.rb @@ -0,0 +1,4 @@ +if RbConfig::CONFIG["LIBRUBY_RELATIVE"] == "yes" + exclude(/test_looks_for_gemdeps_files_automatically_from_binstubs/, + "can't test before installation") +end diff --git a/test/excludes/TestThread.rb b/test/excludes/TestThread.rb index ea73a4c010..cf7e88427e 100644 --- a/test/excludes/TestThread.rb +++ b/test/excludes/TestThread.rb @@ -1,2 +1,14 @@ # frozen_string_literal: false exclude(/_stack_size$/, 'often too expensive') +if /freebsd13/ =~ RUBY_PLATFORM + # http://rubyci.s3.amazonaws.com/freebsd13/ruby-master/log/20220216T143001Z.fail.html.gz + # + # 1) Error: + # TestThread#test_signal_at_join: + # Timeout::Error: execution of assert_separately expired timeout (120 sec) + # pid 30743 killed by SIGABRT (signal 6) (core dumped) + # | + # + # /usr/home/chkbuild/chkbuild/tmp/build/20220216T143001Z/ruby/test/ruby/test_thread.rb:1390:in `test_signal_at_join' + exclude(:test_signal_at_join, 'gets stuck somewhere') +end diff --git a/test/excludes/TestThreadQueue.rb b/test/excludes/TestThreadQueue.rb new file mode 100644 index 0000000000..c8231e372a --- /dev/null +++ b/test/excludes/TestThreadQueue.rb @@ -0,0 +1,9 @@ +# frozen_string_literal: false +if /freebsd13/ =~ RUBY_PLATFORM + # http://rubyci.s3.amazonaws.com/freebsd13/ruby-master/log/20220308T023001Z.fail.html.gz + # + # 1) Failure: + # TestThreadQueue#test_thr_kill [/usr/home/chkbuild/chkbuild/tmp/build/20220308T023001Z/ruby/test/ruby/test_thread_queue.rb:175]: + # only 169/250 done in 60 seconds. + exclude(:test_thr_kill, 'gets stuck somewhere') +end diff --git a/test/fiber/autoload.rb b/test/fiber/autoload.rb new file mode 100644 index 0000000000..dcb27164a7 --- /dev/null +++ b/test/fiber/autoload.rb @@ -0,0 +1,3 @@ +sleep 0.01 +module TestFiberSchedulerAutoload +end diff --git a/test/fiber/scheduler.rb b/test/fiber/scheduler.rb index a6e1325259..96b22856d1 100644 --- a/test/fiber/scheduler.rb +++ b/test/fiber/scheduler.rb @@ -30,7 +30,7 @@ class Scheduler @closed = false @lock = Thread::Mutex.new - @blocking = 0 + @blocking = Hash.new.compare_by_identity @ready = [] @urgent = IO.pipe @@ -57,7 +57,7 @@ class Scheduler def run # $stderr.puts [__method__, Fiber.current].inspect - while @readable.any? or @writable.any? or @waiting.any? or @blocking.positive? + while @readable.any? or @writable.any? or @waiting.any? or @blocking.any? # Can only handle file descriptors up to 1024... readable, writable = IO.select(@readable.keys + [@urgent.first], @writable.keys, [], next_timeout) @@ -192,6 +192,9 @@ class Scheduler end Fiber.yield + ensure + @readable.delete(io) + @writable.delete(io) end # Used for Kernel#sleep and Thread::Mutex#sleep @@ -208,20 +211,22 @@ class Scheduler def block(blocker, timeout = nil) # $stderr.puts [__method__, blocker, timeout].inspect + fiber = Fiber.current + if timeout - @waiting[Fiber.current] = current_time + timeout + @waiting[fiber] = current_time + timeout begin Fiber.yield ensure # Remove from @waiting in the case #unblock was called before the timeout expired: - @waiting.delete(Fiber.current) + @waiting.delete(fiber) end else - @blocking += 1 + @blocking[fiber] = true begin Fiber.yield ensure - @blocking -= 1 + @blocking.delete(fiber) end end end @@ -257,6 +262,85 @@ class Scheduler end end +class IOBufferScheduler < Scheduler + EAGAIN = Errno::EAGAIN::Errno + + def io_read(io, buffer, length) + offset = 0 + + while true + maximum_size = buffer.size - offset + result = blocking{io.read_nonblock(maximum_size, exception: false)} + + # blocking{pp read: maximum_size, result: result, length: length} + + case result + when :wait_readable + if length > 0 + self.io_wait(io, IO::READABLE, nil) + else + return -EAGAIN + end + when :wait_writable + if length > 0 + self.io_wait(io, IO::WRITABLE, nil) + else + return -EAGAIN + end + else + break unless result + + buffer.set_string(result, offset) + + size = result.bytesize + offset += size + break if size >= length + length -= size + end + end + + return offset + end + + def io_write(io, buffer, length) + offset = 0 + + while true + maximum_size = buffer.size - offset + + chunk = buffer.get_string(offset, maximum_size) + result = blocking{io.write_nonblock(chunk, exception: false)} + + # blocking{pp write: maximum_size, result: result, length: length} + + case result + when :wait_readable + if length > 0 + self.io_wait(io, IO::READABLE, nil) + else + return -EAGAIN + end + when :wait_writable + if length > 0 + self.io_wait(io, IO::WRITABLE, nil) + else + return -EAGAIN + end + else + offset += result + break if result >= length + length -= result + end + end + + return offset + end + + def blocking(&block) + Fiber.new(blocking: true, &block).resume + end +end + class BrokenUnblockScheduler < Scheduler def unblock(blocker, fiber) super diff --git a/test/fiber/test_enumerator.rb b/test/fiber/test_enumerator.rb index cd4ccd1de5..c635f474db 100644 --- a/test/fiber/test_enumerator.rb +++ b/test/fiber/test_enumerator.rb @@ -6,14 +6,14 @@ class TestFiberEnumerator < Test::Unit::TestCase MESSAGE = "Hello World" def test_read_characters - skip "UNIXSocket is not defined!" unless defined?(UNIXSocket) + omit "UNIXSocket is not defined!" unless defined?(UNIXSocket) i, o = UNIXSocket.pair unless i.nonblock? && o.nonblock? i.close o.close - skip "I/O is not non-blocking!" + omit "I/O is not non-blocking!" end message = String.new diff --git a/test/fiber/test_io.rb b/test/fiber/test_io.rb index ce65a55f78..4252641cde 100644 --- a/test/fiber/test_io.rb +++ b/test/fiber/test_io.rb @@ -6,14 +6,14 @@ class TestFiberIO < Test::Unit::TestCase MESSAGE = "Hello World" def test_read - skip "UNIXSocket is not defined!" unless defined?(UNIXSocket) + omit "UNIXSocket is not defined!" unless defined?(UNIXSocket) i, o = UNIXSocket.pair unless i.nonblock? && o.nonblock? i.close o.close - skip "I/O is not non-blocking!" + omit "I/O is not non-blocking!" end message = nil @@ -41,7 +41,7 @@ class TestFiberIO < Test::Unit::TestCase end def test_heavy_read - skip unless defined?(UNIXSocket) + omit unless defined?(UNIXSocket) 16.times.map do Thread.new do @@ -64,14 +64,14 @@ class TestFiberIO < Test::Unit::TestCase end def test_epipe_on_read - skip "UNIXSocket is not defined!" unless defined?(UNIXSocket) + omit "UNIXSocket is not defined!" unless defined?(UNIXSocket) i, o = UNIXSocket.pair unless i.nonblock? && o.nonblock? i.close o.close - skip "I/O is not non-blocking!" + omit "I/O is not non-blocking!" end error = nil @@ -140,4 +140,36 @@ class TestFiberIO < Test::Unit::TestCase server.close th.join end + + def test_read_write_blocking + omit "UNIXSocket is not defined!" unless defined?(UNIXSocket) + + i, o = UNIXSocket.pair + i.nonblock = false + o.nonblock = false + + message = nil + + thread = Thread.new do + # This scheduler provides non-blocking `io_read`/`io_write`: + scheduler = IOBufferScheduler.new + Fiber.set_scheduler scheduler + + Fiber.schedule do + message = i.read(20) + i.close + end + + Fiber.schedule do + o.write("Hello World") + o.close + end + end + + thread.join + + assert_equal MESSAGE, message + assert_predicate(i, :closed?) + assert_predicate(o, :closed?) + end end diff --git a/test/fiber/test_io_buffer.rb b/test/fiber/test_io_buffer.rb new file mode 100644 index 0000000000..48a34c31b6 --- /dev/null +++ b/test/fiber/test_io_buffer.rb @@ -0,0 +1,125 @@ +# frozen_string_literal: true +require 'test/unit' +require_relative 'scheduler' + +require 'timeout' + +class TestFiberIOBuffer < Test::Unit::TestCase + MESSAGE = "Hello World" + + def test_read_write_blocking + omit "UNIXSocket is not defined!" unless defined?(UNIXSocket) + + i, o = UNIXSocket.pair + i.nonblock = false + o.nonblock = false + + message = nil + + thread = Thread.new do + scheduler = IOBufferScheduler.new + Fiber.set_scheduler scheduler + + Fiber.schedule do + message = i.read(20) + i.close + end + + Fiber.schedule do + o.write(MESSAGE) + o.close + end + end + + thread.join + + assert_equal MESSAGE, message + assert_predicate(i, :closed?) + assert_predicate(o, :closed?) + ensure + i&.close + o&.close + end + + def test_timeout_after + omit "UNIXSocket is not defined!" unless defined?(UNIXSocket) + + i, o = UNIXSocket.pair + i.nonblock = false + o.nonblock = false + + message = nil + error = nil + + thread = Thread.new do + scheduler = IOBufferScheduler.new + Fiber.set_scheduler scheduler + + Fiber.schedule do + Timeout.timeout(0.1) do + message = i.read(20) + end + rescue Timeout::Error => error + # Assertions below. + ensure + i.close + end + end + + thread.join + + assert_nil message + assert_kind_of Timeout::Error, error + ensure + i&.close + o&.close + end + + def test_read_nonblock + omit "UNIXSocket is not defined!" unless defined?(UNIXSocket) + + i, o = UNIXSocket.pair + + message = nil + + thread = Thread.new do + scheduler = IOBufferScheduler.new + Fiber.set_scheduler scheduler + + Fiber.schedule do + message = i.read_nonblock(20, exception: false) + i.close + end + end + + thread.join + + assert_equal :wait_readable, message + ensure + i&.close + o&.close + end + + def test_write_nonblock + omit "UNIXSocket is not defined!" unless defined?(UNIXSocket) + + i, o = UNIXSocket.pair + + thread = Thread.new do + scheduler = IOBufferScheduler.new + Fiber.set_scheduler scheduler + + Fiber.schedule do + o.write_nonblock(MESSAGE, exception: false) + o.close + end + end + + thread.join + + assert_equal MESSAGE, i.read + ensure + i&.close + o&.close + end +end diff --git a/test/fiber/test_process.rb b/test/fiber/test_process.rb index c6583cac9b..a5990be204 100644 --- a/test/fiber/test_process.rb +++ b/test/fiber/test_process.rb @@ -33,4 +33,19 @@ class TestFiberProcess < Test::Unit::TestCase end end.join end + + def test_fork + omit 'fork not supported' unless Process.respond_to?(:fork) + Thread.new do + scheduler = Scheduler.new + Fiber.set_scheduler scheduler + + Fiber.schedule do + pid = Process.fork {} + Process.wait(pid) + + assert_predicate $?, :success? + end + end.join + end end diff --git a/test/fiber/test_ractor.rb b/test/fiber/test_ractor.rb index d03455a9f7..3c4ccbd8e5 100644 --- a/test/fiber/test_ractor.rb +++ b/test/fiber/test_ractor.rb @@ -4,7 +4,7 @@ require "fiber" class TestFiberCurrentRactor < Test::Unit::TestCase def setup - skip unless defined? Ractor + omit unless defined? Ractor end def test_ractor_shareable diff --git a/test/fiber/test_scheduler.rb b/test/fiber/test_scheduler.rb index 1870ab1c33..4b1310f0a6 100644 --- a/test/fiber/test_scheduler.rb +++ b/test/fiber/test_scheduler.rb @@ -104,4 +104,26 @@ class TestFiberScheduler < Test::Unit::TestCase thread.join end + + def test_autoload + 100.times do + Object.autoload(:TestFiberSchedulerAutoload, File.expand_path("autoload.rb", __dir__)) + + thread = Thread.new do + scheduler = Scheduler.new + Fiber.set_scheduler scheduler + + 10.times do + Fiber.schedule do + Object.const_get(:TestFiberSchedulerAutoload) + end + end + end + + thread.join + ensure + $LOADED_FEATURES.delete(File.expand_path("autoload.rb", __dir__)) + Object.send(:remove_const, :TestFiberSchedulerAutoload) + end + end end diff --git a/test/fileutils/clobber.rb b/test/fileutils/clobber.rb index fdcecd5e08..ac5c8c79c0 100644 --- a/test/fileutils/clobber.rb +++ b/test/fileutils/clobber.rb @@ -4,10 +4,7 @@ require 'test/unit' require 'tmpdir' require_relative 'fileasserts' -class TestFileUtils < Test::Unit::TestCase -end - -module TestFileUtils::Clobber +module TestFileUtilsClobber include Test::Unit::FileAssertions def my_rm_rf(path) diff --git a/test/fileutils/test_dryrun.rb b/test/fileutils/test_dryrun.rb index fd8a7805ec..a3efbb4bdf 100644 --- a/test/fileutils/test_dryrun.rb +++ b/test/fileutils/test_dryrun.rb @@ -8,7 +8,7 @@ require_relative 'visibility_tests' class TestFileUtilsDryRun < Test::Unit::TestCase include FileUtils::DryRun - include TestFileUtilsInc::Visibility + include TestFileUtilsIncVisibility def setup super diff --git a/test/fileutils/test_nowrite.rb b/test/fileutils/test_nowrite.rb index 543fa39f5a..659fa20886 100644 --- a/test/fileutils/test_nowrite.rb +++ b/test/fileutils/test_nowrite.rb @@ -8,7 +8,7 @@ require_relative 'visibility_tests' class TestFileUtilsNoWrite < Test::Unit::TestCase include FileUtils::NoWrite - include TestFileUtilsInc::Visibility + include TestFileUtilsIncVisibility def setup super diff --git a/test/fileutils/test_verbose.rb b/test/fileutils/test_verbose.rb index cf65be8e03..7987af2395 100644 --- a/test/fileutils/test_verbose.rb +++ b/test/fileutils/test_verbose.rb @@ -8,7 +8,7 @@ require_relative 'visibility_tests' class TestFileUtilsVerbose < Test::Unit::TestCase include FileUtils::Verbose - include TestFileUtilsInc::Visibility + include TestFileUtilsIncVisibility def setup super diff --git a/test/fileutils/visibility_tests.rb b/test/fileutils/visibility_tests.rb index 4c02c9d207..9f8f8dc9e1 100644 --- a/test/fileutils/visibility_tests.rb +++ b/test/fileutils/visibility_tests.rb @@ -2,14 +2,11 @@ require 'test/unit' require 'fileutils' -class TestFileUtilsInc < Test::Unit::TestCase -end - ## # These tests are reused in the FileUtils::Verbose, FileUtils::NoWrite and # FileUtils::DryRun tests -module TestFileUtilsInc::Visibility +module TestFileUtilsIncVisibility FileUtils::METHODS.each do |m| define_method "test_singleton_visibility_#{m}" do diff --git a/test/io/console/test_io_console.rb b/test/io/console/test_io_console.rb index 33b98990a1..f6e46fe112 100644 --- a/test/io/console/test_io_console.rb +++ b/test/io/console/test_io_console.rb @@ -383,7 +383,14 @@ defined?(PTY) and defined?(IO.console) and TestIO_Console.class_eval do assert_ctrl("#{cc.ord}", cc, r, w) assert_ctrl("Interrupt", cc, r, w) unless /linux|solaris/ =~ RUBY_PLATFORM end - if cc = ctrl["dsusp"] + # This test fails randomly on FreeBSD 13 + # http://rubyci.s3.amazonaws.com/freebsd13/ruby-master/log/20220304T163001Z.fail.html.gz + # + # 1) Failure: + # TestIO_Console#test_intr [/usr/home/chkbuild/chkbuild/tmp/build/20220304T163001Z/ruby/test/io/console/test_io_console.rb:387]: + # <"25"> expected but was + # <"-e:12:in `p': \e[1mexecution expired (\e[1;4mTimeout::Error\e[m\e[1m)\e[m">. + if (cc = ctrl["dsusp"]) && /freebsd/ !~ RUBY_PLATFORM assert_ctrl("#{cc.ord}", cc, r, w) assert_ctrl("#{cc.ord}", cc, r, w) assert_ctrl("#{cc.ord}", cc, r, w) @@ -407,6 +414,10 @@ defined?(PTY) and defined?(IO.console) and TestIO_Console.class_eval do assert_equal(["true"], run_pty("IO.console(:close); p IO.console(:tty?)")) end + def test_console_kw + assert_equal(["File"], run_pty("IO.console.close; p IO.console(:clone, freeze: true).class")) + end + def test_sync assert_equal(["true"], run_pty("p IO.console.sync")) end @@ -483,6 +494,12 @@ defined?(IO.console) and TestIO_Console.class_eval do IO.console(:close) end + def test_console_kw + io = IO.console(:clone, freeze: true) + io.close + assert_kind_of(IO, io) + end + def test_sync assert(IO.console.sync, "console should be unbuffered") ensure diff --git a/test/io/nonblock/test_flush.rb b/test/io/nonblock/test_flush.rb index 08d129de3f..447d761f18 100644 --- a/test/io/nonblock/test_flush.rb +++ b/test/io/nonblock/test_flush.rb @@ -15,7 +15,7 @@ class TestIONonblock < Test::Unit::TestCase Socket.pair(:INET, :STREAM) {|s1, s2| return if flush_test(s1, s2) } - skip "nonblocking IO did not work" + omit "nonblocking IO did not work" end def flush_test(r, w) diff --git a/test/io/wait/test_io_wait_uncommon.rb b/test/io/wait/test_io_wait_uncommon.rb index 75cd335802..7b92e4c758 100644 --- a/test/io/wait/test_io_wait_uncommon.rb +++ b/test/io/wait/test_io_wait_uncommon.rb @@ -13,7 +13,7 @@ class TestIOWaitUncommon < Test::Unit::TestCase end def test_fifo_wait - skip 'no mkfifo' unless File.respond_to?(:mkfifo) && IO.const_defined?(:NONBLOCK) + omit 'no mkfifo' unless File.respond_to?(:mkfifo) && IO.const_defined?(:NONBLOCK) require 'tmpdir' Dir.mktmpdir('rubytest-fifo') do |dir| fifo = "#{dir}/fifo" diff --git a/test/irb/test_cmd.rb b/test/irb/test_cmd.rb index 8eee36badc..7b7ab55a64 100644 --- a/test/irb/test_cmd.rb +++ b/test/irb/test_cmd.rb @@ -81,6 +81,7 @@ module TestIRB InputMethod:\sAbstract\sInputMethod\n \.irbrc\spath:\s.+\n RUBY_PLATFORM:\s.+\n + East\sAsian\sAmbiguous\sWidth:\s\d\n #{@is_win ? 'Code\spage:\s\d+\n' : ''} }x assert_match expected, irb.context.main.irb_info.to_s @@ -107,6 +108,7 @@ module TestIRB InputMethod:\sAbstract\sInputMethod\n \.irbrc\spath:\s.+\n RUBY_PLATFORM:\s.+\n + East\sAsian\sAmbiguous\sWidth:\s\d\n #{@is_win ? 'Code\spage:\s\d+\n' : ''} }x assert_match expected, irb.context.main.irb_info.to_s @@ -135,6 +137,7 @@ module TestIRB IRB\sversion:\sirb\s.+\n InputMethod:\sAbstract\sInputMethod\n RUBY_PLATFORM:\s.+\n + East\sAsian\sAmbiguous\sWidth:\s\d\n #{@is_win ? 'Code\spage:\s\d+\n' : ''} \z }x @@ -167,6 +170,7 @@ module TestIRB IRB\sversion:\sirb\s.+\n InputMethod:\sAbstract\sInputMethod\n RUBY_PLATFORM:\s.+\n + East\sAsian\sAmbiguous\sWidth:\s\d\n #{@is_win ? 'Code\spage:\s\d+\n' : ''} \z }x @@ -200,7 +204,8 @@ module TestIRB \.irbrc\spath: .+\n RUBY_PLATFORM: .+\n LANG\senv:\sja_JP\.UTF-8\n - LC_ALL\s env:\sen_US\.UTF-8\n + LC_ALL\senv:\sen_US\.UTF-8\n + East\sAsian\sAmbiguous\sWidth:\s\d\n }x assert_match expected, irb.context.main.irb_info.to_s ensure diff --git a/test/irb/test_context.rb b/test/irb/test_context.rb index d908195e6a..42f82fc37e 100644 --- a/test/irb/test_context.rb +++ b/test/irb/test_context.rb @@ -259,6 +259,7 @@ module TestIRB end def test_omit_on_assignment + IRB.conf[:USE_COLORIZE] = false input = TestInputMethod.new([ "a = [1] * 100\n", "a\n", @@ -322,6 +323,7 @@ module TestIRB end def test_omit_multiline_on_assignment + IRB.conf[:USE_COLORIZE] = false input = TestInputMethod.new([ "class A; def inspect; ([?* * 1000] * 3).join(%{\\n}); end; end; a = A.new\n", "a\n" @@ -347,7 +349,7 @@ module TestIRB irb.eval_input end assert_empty err - assert_equal("=> #{value_first_line[0..(input.winsize.last - 9)]}...\e[0m\n=> \n#{value}\n", out) + assert_equal("=> #{value_first_line[0..(input.winsize.last - 9)]}...\n=> \n#{value}\n", out) irb.context.evaluate('A.remove_method(:inspect)', 0) input.reset @@ -395,6 +397,7 @@ module TestIRB # Default IRB.conf[:ECHO] = nil IRB.conf[:ECHO_ON_ASSIGNMENT] = nil + IRB.conf[:USE_COLORIZE] = false input = TestInputMethod.new() irb = IRB::Irb.new(IRB::WorkSpace.new(Object.new), input) @@ -422,6 +425,7 @@ module TestIRB def main.inspect "abc\ndef" end + IRB.conf[:USE_COLORIZE] = false input = TestInputMethod.new([ "self" ]) diff --git a/test/irb/test_ruby_lex.rb b/test/irb/test_ruby_lex.rb index e02370d3f7..47435d675e 100644 --- a/test/irb/test_ruby_lex.rb +++ b/test/irb/test_ruby_lex.rb @@ -399,6 +399,23 @@ module TestIRB end end + def test_corresponding_syntax_to_keyword_in + input_with_correct_indents = [ + Row.new(%q(module E), nil, 2, 1), + Row.new(%q(end), 0, 0, 0), + Row.new(%q(class A), nil, 2, 1), + Row.new(%q( in), nil, 4, 1) + ] + + lines = [] + input_with_correct_indents.each do |row| + lines << row.content + assert_indenting(lines, row.current_line_spaces, false) + assert_indenting(lines, row.new_line_spaces, true) + assert_nesting_level(lines, row.nesting_level) + end + end + def test_bracket_corresponding_to_times input_with_correct_indents = [ Row.new(%q(3.times { |i|), nil, 2, 1), @@ -581,8 +598,8 @@ module TestIRB tokens = RubyLex.ripper_lex_without_warning('%wwww') pos_to_index = {} tokens.each_with_index { |t, i| - assert_nil(pos_to_index[t[0]], "There is already another token in the position of #{t.inspect}.") - pos_to_index[t[0]] = i + assert_nil(pos_to_index[t.pos], "There is already another token in the position of #{t.inspect}.") + pos_to_index[t.pos] = i } end @@ -598,8 +615,8 @@ module TestIRB EOC pos_to_index = {} tokens.each_with_index { |t, i| - assert_nil(pos_to_index[t[0]], "There is already another token in the position of #{t.inspect}.") - pos_to_index[t[0]] = i + assert_nil(pos_to_index[t.pos], "There is already another token in the position of #{t.inspect}.") + pos_to_index[t.pos] = i } end end diff --git a/test/json/json_addition_test.rb b/test/json/json_addition_test.rb index e95ace8375..614c735567 100644 --- a/test/json/json_addition_test.rb +++ b/test/json/json_addition_test.rb @@ -165,7 +165,7 @@ class JSONAdditionTest < Test::Unit::TestCase def test_utc_datetime now = Time.now - d = DateTime.parse(now.to_s, :create_additions => true) # usual case + d = DateTime.parse(now.to_s) # usual case assert_equal d, parse(d.to_json, :create_additions => true) d = DateTime.parse(now.utc.to_s) # of = 0 assert_equal d, parse(d.to_json, :create_additions => true) diff --git a/test/json/json_parser_test.rb b/test/json/json_parser_test.rb index dce693e548..00b254fc6a 100644 --- a/test/json/json_parser_test.rb +++ b/test/json/json_parser_test.rb @@ -84,6 +84,7 @@ class JSONParserTest < Test::Unit::TestCase assert_equal({ "a" => 23 }, parse(' { "a" : 23 } ')) assert_equal({ "a" => 0.23 }, parse(' { "a" : 0.23 } ')) assert_equal({ "a" => 0.23 }, parse(' { "a" : 0.23 } ')) + assert_equal({ "" => 123 }, parse('{"":123}')) end def test_parse_numbers diff --git a/test/lib/jit_support.rb b/test/lib/jit_support.rb index 779aa8567e..c7618e03a0 100644 --- a/test/lib/jit_support.rb +++ b/test/lib/jit_support.rb @@ -21,7 +21,7 @@ module JITSupport ] module_function - # Run Ruby script with --jit-wait (Synchronous JIT compilation). + # Run Ruby script with --mjit-wait (Synchronous JIT compilation). # Returns [stdout, stderr] def eval_with_jit(env = nil, script, **opts) stdout, stderr = nil, nil @@ -36,13 +36,13 @@ module JITSupport def eval_with_jit_without_retry(env = nil, script, verbose: 0, min_calls: 5, save_temps: false, max_cache: 1000, wait: true, timeout: JIT_TIMEOUT) args = [ - '--disable-gems', "--jit-verbose=#{verbose}", - "--jit-min-calls=#{min_calls}", "--jit-max-cache=#{max_cache}", + '--disable-gems', "--mjit-verbose=#{verbose}", + "--mjit-min-calls=#{min_calls}", "--mjit-max-cache=#{max_cache}", ] args << '--disable-yjit' - args << '--jit-wait' if wait - args << '--jit-save-temps' if save_temps - args << '--jit-debug' if defined?(@jit_debug) && @jit_debug + args << '--mjit-wait' if wait + args << '--mjit-save-temps' if save_temps + args << '--mjit-debug' if defined?(@mjit_debug) && @mjit_debug args << '-e' << script base_env = { 'MJIT_SEARCH_BUILD_DIR' => 'true' } # workaround to skip requiring `make install` for `make test-all` if preloadenv = RbConfig::CONFIG['PRELOADENV'] and !preloadenv.empty? @@ -62,6 +62,11 @@ module JITSupport end && !appveyor_pdb_corrupted? && !PENDING_RUBYCI_NICKNAMES.include?(ENV['RUBYCI_NICKNAME']) end + def yjit_supported? + # e.g. x86_64-linux, x64-mswin64_140, x64-mingw32, x64-mingw-ucrt + RUBY_PLATFORM.match?(/^(x86_64|x64)-/) + end + # AppVeyor's Visual Studio 2013 / 2015 are known to spuriously generate broken pch / pdb, like: # error C2859: c:\projects\ruby\x64-mswin_120\include\ruby-2.8.0\x64-mswin64_120\rb_mjit_header-2.8.0.pdb # is not the pdb file that was used when this precompiled header was created, recreate the precompiled header. @@ -75,7 +80,7 @@ module JITSupport end def remove_mjit_logs(stderr) - if defined?(RubyVM::JIT) && RubyVM::JIT.enabled? # utility for -DFORCE_MJIT_ENABLE + if defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? # utility for -DFORCE_MJIT_ENABLE stderr.gsub(/^MJIT warning: Skipped to compile unsupported instruction: \w+\n/m, '') else stderr diff --git a/test/logger/test_formatter.rb b/test/logger/test_formatter.rb new file mode 100644 index 0000000000..9465722991 --- /dev/null +++ b/test/logger/test_formatter.rb @@ -0,0 +1,35 @@ +# coding: US-ASCII +# frozen_string_literal: false +require 'logger' + +class TestFormatter < Test::Unit::TestCase + def test_call + severity = 'INFO' + time = Time.now + progname = 'ruby' + msg = 'This is a test' + formatter = Logger::Formatter.new + + result = formatter.call(severity, time, progname, msg) + time_matcher = /\d{4}\-\d{2}\-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6}/ + matcher = /#{severity[0..0]}, \[#{time_matcher} #\d+\] #{severity} -- #{progname}: #{msg}\n/ + + assert_match(matcher, result) + end + + class CustomFormatter < Logger::Formatter + def call(time) + format_datetime(time) + end + end + + def test_format_datetime + time = Time.now + formatter = CustomFormatter.new + + result = formatter.call(time) + matcher = /^\d{4}\-\d{2}\-\d{2}T\d{2}:\d{2}:\d{2}\.\d{6}$/ + + assert_match(matcher, result) + end +end diff --git a/test/logger/test_logdevice.rb b/test/logger/test_logdevice.rb index d360fa2107..8f1c15542a 100644 --- a/test/logger/test_logdevice.rb +++ b/test/logger/test_logdevice.rb @@ -435,6 +435,7 @@ class TestLogDevice < Test::Unit::TestCase logdev1.write(message) assert_file.identical?(log, logdev1.dev) + # NOTE: below assertion fails in JRuby 9.3 and TruffleRuby assert_file.identical?(log + ".0", logdev2.dev) logdev2.write(message) @@ -451,7 +452,7 @@ class TestLogDevice < Test::Unit::TestCase end ensure logdev0.close - end unless /mswin|mingw|cygwin/ =~ RUBY_PLATFORM + end unless /mswin|mingw|cygwin/ =~ RbConfig::CONFIG['host_os'] def test_shifting_midnight Dir.mktmpdir do |tmpdir| diff --git a/test/logger/test_logger.rb b/test/logger/test_logger.rb index 3281d17c7b..37d0f5862a 100644 --- a/test/logger/test_logger.rb +++ b/test/logger/test_logger.rb @@ -13,7 +13,7 @@ class TestLogger < Test::Unit::TestCase class Log attr_reader :label, :datetime, :pid, :severity, :progname, :msg def initialize(line) - /\A(\w+), \[([^#]*)#(\d+)\]\s+(\w+) -- (\w*): ([\x0-\xff]*)/ =~ line + /\A(\w+), \[([^#]*) #(\d+)\]\s+(\w+) -- (\w*): ([\x0-\xff]*)/ =~ line @label, @datetime, @pid, @severity, @progname, @msg = $1, $2, $3, $4, $5, $6 end end @@ -124,7 +124,7 @@ class TestLogger < Test::Unit::TestCase dummy = STDERR logger = Logger.new(dummy) log = log_add(logger, INFO, "foo") - assert_match(/^\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\d.\s*\d+ $/, log.datetime) + assert_match(/^\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\d.\s*\d+$/, log.datetime) logger.datetime_format = "%d%b%Y@%H:%M:%S" log = log_add(logger, INFO, "foo") assert_match(/^\d\d\w\w\w\d\d\d\d@\d\d:\d\d:\d\d$/, log.datetime) @@ -203,7 +203,7 @@ class TestLogger < Test::Unit::TestCase # default logger = Logger.new(STDERR) log = log_add(logger, INFO, "foo") - assert_match(/^\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\d.\s*\d+ $/, log.datetime) + assert_match(/^\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\d.\s*\d+$/, log.datetime) # config logger = Logger.new(STDERR, datetime_format: "%d%b%Y@%H:%M:%S") log = log_add(logger, INFO, "foo") diff --git a/test/mkmf/base.rb b/test/mkmf/base.rb index 4f67478a56..e097c396d6 100644 --- a/test/mkmf/base.rb +++ b/test/mkmf/base.rb @@ -20,134 +20,131 @@ $INCFLAGS << " -I." $extout_prefix = "$(extout)$(target_prefix)/" class TestMkmf < Test::Unit::TestCase -end - -module TestMkmf::Base - MKMFLOG = proc {File.read("mkmf.log") rescue ""} + module Base + MKMFLOG = proc {File.read("mkmf.log") rescue ""} - class Capture - attr_accessor :origin - def initialize - @buffer = "" - @filter = nil - @out = true - @origin = nil - end - def clear - @buffer.clear - end - def flush - STDOUT.print @filter ? @filter.call(@buffer) : @buffer - clear - end - def reopen(io) - case io - when Capture - initialize_copy(io) - when File - @out = false - @origin.reopen(io) if @origin - when IO + class Capture + attr_accessor :origin + def initialize + @buffer = "" + @filter = nil @out = true - @origin.reopen(io) if @origin - else - @out = false + @origin = nil end - end - def filter(&block) - @filter = block - end - def write(*s) - if @out - @buffer.concat(*s) - elsif @origin - @origin.write(*s) + def clear + @buffer.clear + end + def flush + STDOUT.print @filter ? @filter.call(@buffer) : @buffer + clear + end + def reopen(io) + case io + when Capture + initialize_copy(io) + when File + @out = false + @origin.reopen(io) if @origin + when IO + @out = true + @origin.reopen(io) if @origin + else + @out = false + end + end + def filter(&block) + @filter = block + end + def write(*s) + if @out + @buffer.concat(*s) + elsif @origin + @origin.write(*s) + end end end - end - attr_reader :stdout + attr_reader :stdout - def mkmflog(msg) - proc {MKMFLOG[] << msg} - end + def mkmflog(msg) + proc {MKMFLOG[] << msg} + end - def setup - @rbconfig = rbconfig0 = RbConfig::CONFIG - @mkconfig = mkconfig0 = RbConfig::MAKEFILE_CONFIG - rbconfig = { - "hdrdir" => $hdrdir, - "srcdir" => $srcdir, - "topdir" => $topdir, - } - mkconfig = { - "hdrdir" => "$(top_srcdir)/include", - "srcdir" => "$(top_srcdir)", - "topdir" => $topdir, - } - rbconfig0.each_pair {|key, val| rbconfig[key] ||= val.dup} - mkconfig0.each_pair {|key, val| mkconfig[key] ||= val.dup} - RbConfig.module_eval { - remove_const(:CONFIG) - const_set(:CONFIG, rbconfig) - remove_const(:MAKEFILE_CONFIG) - const_set(:MAKEFILE_CONFIG, mkconfig) - } - MakeMakefile.class_eval { - remove_const(:CONFIG) - const_set(:CONFIG, mkconfig) - } - @tmpdir = Dir.mktmpdir - @curdir = Dir.pwd - @mkmfobj = Object.new - @stdout = Capture.new - Dir.chdir(@tmpdir) - @quiet, Logging.quiet = Logging.quiet, true - init_mkmf - $INCFLAGS[0, 0] = "-I. " - end + def setup + @rbconfig = rbconfig0 = RbConfig::CONFIG + @mkconfig = mkconfig0 = RbConfig::MAKEFILE_CONFIG + rbconfig = { + "hdrdir" => $hdrdir, + "srcdir" => $srcdir, + "topdir" => $topdir, + } + mkconfig = { + "hdrdir" => "$(top_srcdir)/include", + "srcdir" => "$(top_srcdir)", + "topdir" => $topdir, + } + rbconfig0.each_pair {|key, val| rbconfig[key] ||= val.dup} + mkconfig0.each_pair {|key, val| mkconfig[key] ||= val.dup} + RbConfig.module_eval { + remove_const(:CONFIG) + const_set(:CONFIG, rbconfig) + remove_const(:MAKEFILE_CONFIG) + const_set(:MAKEFILE_CONFIG, mkconfig) + } + MakeMakefile.class_eval { + remove_const(:CONFIG) + const_set(:CONFIG, mkconfig) + } + @tmpdir = Dir.mktmpdir + @curdir = Dir.pwd + @mkmfobj = Object.new + @stdout = Capture.new + Dir.chdir(@tmpdir) + @quiet, Logging.quiet = Logging.quiet, true + init_mkmf + $INCFLAGS[0, 0] = "-I. " + end - def teardown - rbconfig0 = @rbconfig - mkconfig0 = @mkconfig - RbConfig.module_eval { - remove_const(:CONFIG) - const_set(:CONFIG, rbconfig0) - remove_const(:MAKEFILE_CONFIG) - const_set(:MAKEFILE_CONFIG, mkconfig0) - } - MakeMakefile.class_eval { - remove_const(:CONFIG) - const_set(:CONFIG, mkconfig0) - } - Logging.quiet = @quiet - Logging.log_close - FileUtils.rm_f("mkmf.log") - Dir.chdir(@curdir) - FileUtils.rm_rf(@tmpdir) - end + def teardown + rbconfig0 = @rbconfig + mkconfig0 = @mkconfig + RbConfig.module_eval { + remove_const(:CONFIG) + const_set(:CONFIG, rbconfig0) + remove_const(:MAKEFILE_CONFIG) + const_set(:MAKEFILE_CONFIG, mkconfig0) + } + MakeMakefile.class_eval { + remove_const(:CONFIG) + const_set(:CONFIG, mkconfig0) + } + Logging.quiet = @quiet + Logging.log_close + FileUtils.rm_f("mkmf.log") + Dir.chdir(@curdir) + FileUtils.rm_rf(@tmpdir) + end - def mkmf(*args, &block) - @stdout.clear - stdout, @stdout.origin, $stdout = @stdout.origin, $stdout, @stdout - verbose, $VERBOSE = $VERBOSE, false - @mkmfobj.instance_eval(*args, &block) - ensure - $VERBOSE = verbose - $stdout, @stdout.origin = @stdout.origin, stdout - end + def mkmf(*args, &block) + @stdout.clear + stdout, @stdout.origin, $stdout = @stdout.origin, $stdout, @stdout + verbose, $VERBOSE = $VERBOSE, false + @mkmfobj.instance_eval(*args, &block) + ensure + $VERBOSE = verbose + $stdout, @stdout.origin = @stdout.origin, stdout + end - def config_value(name) - create_tmpsrc("---config-value=#{name}") - xpopen(cpp_command('')) do |f| - f.grep(/^---config-value=(.*)/) {return $1} + def config_value(name) + create_tmpsrc("---config-value=#{name}") + xpopen(cpp_command('')) do |f| + f.grep(/^---config-value=(.*)/) {return $1} + end + nil end - nil end -end -class TestMkmf - include TestMkmf::Base + include Base def assert_separately(args, src, *rest, **options) super(args + ["-r#{__FILE__}"], "extend TestMkmf::Base; setup\nEND{teardown}\n#{src}", *rest, **options) diff --git a/test/mkmf/test_config.rb b/test/mkmf/test_config.rb index 07ed641415..3878db1964 100644 --- a/test/mkmf/test_config.rb +++ b/test/mkmf/test_config.rb @@ -4,14 +4,12 @@ $extmk = true require 'test/unit' require 'mkmf' -class TestMkmf < Test::Unit::TestCase - class TestConfig < Test::Unit::TestCase - def test_dir_config - bug8074 = '[Bug #8074]' - lib = RbConfig.expand(RbConfig::MAKEFILE_CONFIG["libdir"], "exec_prefix"=>"") - assert_separately %w[-rmkmf - -- --with-foo-dir=/test/foo], %{ - assert_equal(%w[/test/foo/include /test/foo#{lib}], dir_config("foo"), #{bug8074.dump}) - } - end +class TestMkmfConfig < Test::Unit::TestCase + def test_dir_config + bug8074 = '[Bug #8074]' + lib = RbConfig.expand(RbConfig::MAKEFILE_CONFIG["libdir"], "exec_prefix"=>"") + assert_separately %w[-rmkmf - -- --with-foo-dir=/test/foo], %{ + assert_equal(%w[/test/foo/include /test/foo#{lib}], dir_config("foo"), #{bug8074.dump}) + } end end diff --git a/test/mkmf/test_constant.rb b/test/mkmf/test_constant.rb index f5a87a1caa..f6834c7f28 100644 --- a/test/mkmf/test_constant.rb +++ b/test/mkmf/test_constant.rb @@ -1,38 +1,36 @@ # frozen_string_literal: false require_relative 'base' -class TestMkmf - class TestTryConstant < TestMkmf - def test_simple - assert_equal( 0, mkmf {try_constant("0")}, MKMFLOG) - assert_equal( 1, mkmf {try_constant("1")}, MKMFLOG) - assert_equal(-1, mkmf {try_constant("-1")}, MKMFLOG) - end - - def test_sizeof - assert_equal(config_value("SIZEOF_INT").to_i, mkmf {try_constant("sizeof(int)")}, MKMFLOG) - assert_equal(config_value("SIZEOF_LONG").to_i, mkmf {try_constant("sizeof(long)")}, MKMFLOG) - assert_equal(config_value("SIZEOF_VOIDP").to_i, mkmf {try_constant("sizeof(void*)")}, MKMFLOG) - assert_equal(config_value("SIZEOF_VALUE").to_i, mkmf {try_constant("sizeof(Qnil)")}, MKMFLOG) - end +class TestMkmfTryConstant < TestMkmf + def test_simple + assert_equal( 0, mkmf {try_constant("0")}, MKMFLOG) + assert_equal( 1, mkmf {try_constant("1")}, MKMFLOG) + assert_equal(-1, mkmf {try_constant("-1")}, MKMFLOG) + end - def test_long - sizeof_int = config_value("SIZEOF_INT").to_i - sizeof_long = config_value("SIZEOF_LONG").to_i - if sizeof_long > sizeof_int - type = 'long' - else - sizeof_long_long = config_value("SIZEOF_LONG_LONG").to_i - return if !sizeof_long_long or sizeof_long_long <= sizeof_int - type = 'LONG_LONG' - end + def test_sizeof + assert_equal(config_value("SIZEOF_INT").to_i, mkmf {try_constant("sizeof(int)")}, MKMFLOG) + assert_equal(config_value("SIZEOF_LONG").to_i, mkmf {try_constant("sizeof(long)")}, MKMFLOG) + assert_equal(config_value("SIZEOF_VOIDP").to_i, mkmf {try_constant("sizeof(void*)")}, MKMFLOG) + assert_equal(config_value("SIZEOF_VALUE").to_i, mkmf {try_constant("sizeof(Qnil)")}, MKMFLOG) + end - decl = "#define CONFTEST_VALUE (unsigned #{type})(((unsigned #{type})1)<<(CHAR_BIT*sizeof(int)))" - assert_operator(mkmf {try_constant("CONFTEST_VALUE", [[decl]])}, :>, 0, MKMFLOG) + def test_long + sizeof_int = config_value("SIZEOF_INT").to_i + sizeof_long = config_value("SIZEOF_LONG").to_i + if sizeof_long > sizeof_int + type = 'long' + else + sizeof_long_long = config_value("SIZEOF_LONG_LONG").to_i + return if !sizeof_long_long or sizeof_long_long <= sizeof_int + type = 'LONG_LONG' end - def test_large_unsigned - assert_operator(mkmf {try_constant("1U<<(CHAR_BIT*sizeof(int)-1)")}, :>, 0, MKMFLOG) - end + decl = "#define CONFTEST_VALUE (unsigned #{type})(((unsigned #{type})1)<<(CHAR_BIT*sizeof(int)))" + assert_operator(mkmf {try_constant("CONFTEST_VALUE", [[decl]])}, :>, 0, MKMFLOG) + end + + def test_large_unsigned + assert_operator(mkmf {try_constant("1U<<(CHAR_BIT*sizeof(int)-1)")}, :>, 0, MKMFLOG) end end diff --git a/test/mkmf/test_convertible.rb b/test/mkmf/test_convertible.rb index 1baf892842..d65db4265b 100644 --- a/test/mkmf/test_convertible.rb +++ b/test/mkmf/test_convertible.rb @@ -1,35 +1,33 @@ # frozen_string_literal: false require_relative 'base' -class TestMkmf - class TestConvertible < TestMkmf - def test_typeof_builtin - ["", ["signed ", ""], "unsigned "].each do |signed, prefix| - %w[short int long].each do |type| - assert_equal((prefix || signed)+type, - mkmf {convertible_int(signed+type)}, MKMFLOG) - end +class TestMkmfConvertible < TestMkmf + def test_typeof_builtin + ["", ["signed ", ""], "unsigned "].each do |signed, prefix| + %w[short int long].each do |type| + assert_equal((prefix || signed)+type, + mkmf {convertible_int(signed+type)}, MKMFLOG) end end + end - def test_typeof_typedef - ["", ["signed ", ""], "unsigned "].each do |signed, prefix| - %w[short int long].each do |type| - open("confdefs.h", "w") {|f| - f.puts "typedef #{signed}#{type} test1_t;" - } - $defs.clear - assert_equal((prefix || signed)+type, - mkmf {convertible_int("test1_t", "confdefs.h")}, MKMFLOG) - (u = signed[/^u/]) and u.upcase! - assert_include($defs, "-DTYPEOF_TEST1_T="+"#{prefix||signed}#{type}".quote) - assert_include($defs, "-DPRI_TEST1T_PREFIX=PRI_#{type.upcase}_PREFIX") - assert_include($defs, "-DTEST1T2NUM=#{u}#{type.upcase}2NUM") - assert_include($defs, "-DNUM2TEST1T=NUM2#{u}#{type.upcase}") - end + def test_typeof_typedef + ["", ["signed ", ""], "unsigned "].each do |signed, prefix| + %w[short int long].each do |type| + open("confdefs.h", "w") {|f| + f.puts "typedef #{signed}#{type} test1_t;" + } + $defs.clear + assert_equal((prefix || signed)+type, + mkmf {convertible_int("test1_t", "confdefs.h")}, MKMFLOG) + (u = signed[/^u/]) and u.upcase! + assert_include($defs, "-DTYPEOF_TEST1_T="+"#{prefix||signed}#{type}".quote) + assert_include($defs, "-DPRI_TEST1T_PREFIX=PRI_#{type.upcase}_PREFIX") + assert_include($defs, "-DTEST1T2NUM=#{u}#{type.upcase}2NUM") + assert_include($defs, "-DNUM2TEST1T=NUM2#{u}#{type.upcase}") end - ensure - File.unlink("confdefs.h") end + ensure + File.unlink("confdefs.h") end end diff --git a/test/mkmf/test_egrep_cpp.rb b/test/mkmf/test_egrep_cpp.rb index ce276bef20..7ac0e60010 100644 --- a/test/mkmf/test_egrep_cpp.rb +++ b/test/mkmf/test_egrep_cpp.rb @@ -2,14 +2,12 @@ require_relative 'base' require 'tempfile' -class TestMkmf - class TestEgrepCpp < TestMkmf - def test_egrep_cpp - assert_equal(true, egrep_cpp(/ruby_init/, ""), MKMFLOG) - end +class TestMkmfEgrepCpp < TestMkmf + def test_egrep_cpp + assert_equal(true, egrep_cpp(/ruby_init/, ""), MKMFLOG) + end - def test_not_have_func - assert_equal(false, egrep_cpp(/never match/, ""), MKMFLOG) - end + def test_not_have_func + assert_equal(false, egrep_cpp(/never match/, ""), MKMFLOG) end end diff --git a/test/mkmf/test_find_executable.rb b/test/mkmf/test_find_executable.rb index 7ffc28ecc8..88b70c21c0 100644 --- a/test/mkmf/test_find_executable.rb +++ b/test/mkmf/test_find_executable.rb @@ -1,58 +1,56 @@ # frozen_string_literal: false require_relative 'base' -class TestMkmf - class TestFindExecutable < TestMkmf - def setup - super - @path, ENV["PATH"] = ENV["PATH"], @tmpdir - end +class TestMkmfFindExecutable < TestMkmf + def setup + super + @path, ENV["PATH"] = ENV["PATH"], @tmpdir + end - def each_exts(&block) - name = "foobar#{$$}#{rand(1000)}" - stdout.filter {|s| s.sub(name, "<executable>")} - exts = mkmf {self.class::CONFIG['EXECUTABLE_EXTS']}.split - exts[0] ||= "" - exts.each do |ext| - yield name+ext, name - end + def each_exts(&block) + name = "foobar#{$$}#{rand(1000)}" + stdout.filter {|s| s.sub(name, "<executable>")} + exts = mkmf {self.class::CONFIG['EXECUTABLE_EXTS']}.split + exts[0] ||= "" + exts.each do |ext| + yield name+ext, name end + end - def teardown - ENV["PATH"] = @path - super - end + def teardown + ENV["PATH"] = @path + super + end - def test_find_executable - bug2669 = '[ruby-core:27912]' - each_exts do |full, name| - begin - open(full, "w") {|ff| ff.chmod(0755)} - result = mkmf {find_executable(name)} - ensure - File.unlink(full) - end - assert_equal("#{@tmpdir}/#{full}", result, bug2669) + def test_find_executable + bug2669 = '[ruby-core:27912]' + each_exts do |full, name| + begin + open(full, "w") {|ff| ff.chmod(0755)} + result = mkmf {find_executable(name)} + ensure + File.unlink(full) end + assert_equal("#{@tmpdir}/#{full}", result, bug2669) end + end - def test_find_executable_dir - each_exts do |full, name| - begin - Dir.mkdir(full) - result = mkmf {find_executable(name)} - ensure - Dir.rmdir(full) - end - assert_nil(result) + def test_find_executable_dir + each_exts do |full, name| + begin + Dir.mkdir(full) + result = mkmf {find_executable(name)} + ensure + Dir.rmdir(full) end + assert_nil(result) end + end - if /mingw|mswin/ =~ RUBY_PLATFORM - def test_quoted_path_on_windows - ENV["PATH"] = %["#{@tmpdir}"] - test_find_executable - end + if /mingw|mswin/ =~ RUBY_PLATFORM + def test_quoted_path_on_windows + ENV["PATH"] = %["#{@tmpdir}"] + test_find_executable end end end diff --git a/test/mkmf/test_flags.rb b/test/mkmf/test_flags.rb index a3596d8e55..aedf06b610 100644 --- a/test/mkmf/test_flags.rb +++ b/test/mkmf/test_flags.rb @@ -1,57 +1,55 @@ # frozen_string_literal: false require_relative 'base' -class TestMkmf - class TestFlags < TestMkmf - def test_valid_warnflags - val = $extmk - warnflags = $warnflags - makefile = mkmf do - $extmk = false - self.class::CONFIG['warnflags'] = %w"-Wextra - -Wno-unused-parameter -Wno-parentheses -Wno-long-long - -Wno-missing-field-initializers -Werror=pointer-arith - -Werror=write-strings -Werror=declaration-after-statement - -Werror=shorten-64-to-32 - -Werror-implicit-function-declaration - ".join(' ') - self.class::CONFIG['GCC'] = 'yes' - init_mkmf(self.class::CONFIG) - configuration '.' - end - generated_flags = makefile.grep(/warnflags/).first[/^warnflags = (.*)$/, 1].split +class TestMkmfFlags < TestMkmf + def test_valid_warnflags + val = $extmk + warnflags = $warnflags + makefile = mkmf do + $extmk = false + self.class::CONFIG['warnflags'] = %w"-Wextra + -Wno-unused-parameter -Wno-parentheses -Wno-long-long + -Wno-missing-field-initializers -Werror=pointer-arith + -Werror=write-strings -Werror=declaration-after-statement + -Werror=shorten-64-to-32 + -Werror-implicit-function-declaration + ".join(' ') + self.class::CONFIG['GCC'] = 'yes' + init_mkmf(self.class::CONFIG) + configuration '.' + end + generated_flags = makefile.grep(/warnflags/).first[/^warnflags = (.*)$/, 1].split - assert_equal %w" - -Wextra -Wno-unused-parameter -Wno-parentheses - -Wno-long-long -Wno-missing-field-initializers -Wpointer-arith - -Wwrite-strings -Wdeclaration-after-statement - -Wshorten-64-to-32 -Wimplicit-function-declaration - ", generated_flags + assert_equal %w" + -Wextra -Wno-unused-parameter -Wno-parentheses + -Wno-long-long -Wno-missing-field-initializers -Wpointer-arith + -Wwrite-strings -Wdeclaration-after-statement + -Wshorten-64-to-32 -Werror-implicit-function-declaration + ", generated_flags - ensure - $warnflags = warnflags - $extmk = val - end + ensure + $warnflags = warnflags + $extmk = val + end - def test_try_ldflag_invalid_opt - assert_separately([], <<-'end;') #do - assert(!try_ldflags("nosuch.c"), TestMkmf::MKMFLOG) - assert(have_devel?, TestMkmf::MKMFLOG) - end; - end + def test_try_ldflag_invalid_opt + assert_separately([], <<-'end;') #do + assert(!try_ldflags("nosuch.c"), TestMkmf::MKMFLOG) + assert(have_devel?, TestMkmf::MKMFLOG) + end; + end - def test_try_cflag_invalid_opt - assert_separately([], <<-'end;', timeout: 30) #do - assert(!try_cflags("nosuch.c"), TestMkmf::MKMFLOG) - assert(have_devel?, TestMkmf::MKMFLOG) - end; - end + def test_try_cflag_invalid_opt + assert_separately([], <<-'end;', timeout: 30) #do + assert(!try_cflags("nosuch.c"), TestMkmf::MKMFLOG) + assert(have_devel?, TestMkmf::MKMFLOG) + end; + end - def test_try_cppflag_invalid_opt - assert_separately([], <<-'end;') #do - assert(!try_cppflags("nosuch.c"), TestMkmf::MKMFLOG) - assert(have_devel?, TestMkmf::MKMFLOG) - end; - end + def test_try_cppflag_invalid_opt + assert_separately([], <<-'end;') #do + assert(!try_cppflags("nosuch.c"), TestMkmf::MKMFLOG) + assert(have_devel?, TestMkmf::MKMFLOG) + end; end end diff --git a/test/mkmf/test_framework.rb b/test/mkmf/test_framework.rb index ba15299ae0..3245e43c75 100644 --- a/test/mkmf/test_framework.rb +++ b/test/mkmf/test_framework.rb @@ -1,49 +1,47 @@ # frozen_string_literal: false require_relative 'base' -class TestMkmf - class TestHaveFramework < TestMkmf - def create_framework(fw, hdrname = "#{fw}.h") - Dir.mktmpdir("frameworks") do |dir| - fwdir = "#{dir}/#{fw}.framework" - hdrdir = "#{fwdir}/Headers" - FileUtils.mkdir_p(hdrdir) - File.write("#{hdrdir}/#{hdrname}", "") - src = "#{fwdir}/main.c" - File.write(src, "void #{fw}(void) {}\n") - cmd = LINK_SO.dup - RbConfig.expand(cmd, RbConfig::CONFIG.merge("OBJS"=>src)) - cmd.gsub!("$@", "#{fwdir}/#{fw}") - cmd.gsub!(/ -bundle /, ' -dynamiclib ') - assert(xsystem(cmd), MKMFLOG) - $INCFLAGS << " " << "-F#{dir}".quote - yield fw, hdrname - end +class TestMkmfHaveFramework < TestMkmf + def create_framework(fw, hdrname = "#{fw}.h") + Dir.mktmpdir("frameworks") do |dir| + fwdir = "#{dir}/#{fw}.framework" + hdrdir = "#{fwdir}/Headers" + FileUtils.mkdir_p(hdrdir) + File.write("#{hdrdir}/#{hdrname}", "") + src = "#{fwdir}/main.c" + File.write(src, "void #{fw}(void) {}\n") + cmd = LINK_SO.dup + RbConfig.expand(cmd, RbConfig::CONFIG.merge("OBJS"=>src)) + cmd.gsub!("$@", "#{fwdir}/#{fw}") + cmd.gsub!(/ -bundle /, ' -dynamiclib ') + assert(xsystem(cmd), MKMFLOG) + $INCFLAGS << " " << "-F#{dir}".quote + yield fw, hdrname end + end - def test_single_framework - assert(have_framework(%w"Ruby ruby.h"), mkmflog("try as Objective-C")) - end + def test_single_framework + assert(have_framework(%w"Ruby ruby.h"), mkmflog("try as Objective-C")) + end - def test_multi_frameworks - assert(have_framework(%w"Ruby ruby.h"), mkmflog("try as Objective-C")) - create_framework("MkmfTest") do |fw| - assert(have_framework(fw), MKMFLOG) - end + def test_multi_frameworks + assert(have_framework(%w"Ruby ruby.h"), mkmflog("try as Objective-C")) + create_framework("MkmfTest") do |fw| + assert(have_framework(fw), MKMFLOG) end + end - def test_empty_framework - create_framework("MkmfTest") do |fw| - assert(have_framework(fw), MKMFLOG) - end + def test_empty_framework + create_framework("MkmfTest") do |fw| + assert(have_framework(fw), MKMFLOG) end + end - def test_different_name_header - _bug8593 = '[ruby-core:55745] [Bug #8593]' - create_framework("MkmfTest", "test_mkmf.h") do |fw, hdrname| - assert(!have_framework(fw), MKMFLOG) - assert(have_framework([fw, hdrname]), MKMFLOG) - end + def test_different_name_header + _bug8593 = '[ruby-core:55745] [Bug #8593]' + create_framework("MkmfTest", "test_mkmf.h") do |fw, hdrname| + assert(!have_framework(fw), MKMFLOG) + assert(have_framework([fw, hdrname]), MKMFLOG) end end end if /darwin/ =~ RUBY_PLATFORM diff --git a/test/mkmf/test_have_func.rb b/test/mkmf/test_have_func.rb index 6204ab24f0..521a0bb435 100644 --- a/test/mkmf/test_have_func.rb +++ b/test/mkmf/test_have_func.rb @@ -2,16 +2,14 @@ require_relative 'base' require 'tempfile' -class TestMkmf - class TestHaveFunc < TestMkmf - def test_have_func - assert_equal(true, have_func("ruby_init"), MKMFLOG) - assert_include($defs, '-DHAVE_RUBY_INIT') - end +class TestMkmfHaveFunc < TestMkmf + def test_have_func + assert_equal(true, have_func("ruby_init"), MKMFLOG) + assert_include($defs, '-DHAVE_RUBY_INIT') + end - def test_not_have_func - assert_equal(false, have_func("no_ruby_init"), MKMFLOG) - assert_not_include($defs, '-DHAVE_RUBY_INIT') - end + def test_not_have_func + assert_equal(false, have_func("no_ruby_init"), MKMFLOG) + assert_not_include($defs, '-DHAVE_RUBY_INIT') end end diff --git a/test/mkmf/test_have_library.rb b/test/mkmf/test_have_library.rb index bb9ce6972d..e34a9b06da 100644 --- a/test/mkmf/test_have_library.rb +++ b/test/mkmf/test_have_library.rb @@ -2,55 +2,53 @@ require_relative 'base' require 'tempfile' -class TestMkmf - class TestHaveLibrary < TestMkmf - LIBRARY_NAME = 'mkmftest' - HEADER_NAME = "#{LIBRARY_NAME}.h" - FUNC_NAME = 'ruby_mkmftest_foo' - ARPREFIX = config_string('LIBRUBY_A') {|lib| lib[/\A\w+/]} - - def create_library(libname = LIBRARY_NAME) - lib = "#{ARPREFIX}#{libname}.#{$LIBEXT}" - open(HEADER_NAME, "w") do |hdr| - hdr.puts "void #{FUNC_NAME}(void);" - hdr.puts "void #{FUNC_NAME}_fake(void);" - end - create_tmpsrc("#include \"#{HEADER_NAME}\"\n""void #{FUNC_NAME}(void) {}") - assert(xsystem(cc_command), "compile failed: #{cc_command}") - command = "#{CONFIG['AR']} #{config_string('ARFLAGS') || 'cru '}#{lib} #{CONFTEST}.#{$OBJEXT}" - assert(xsystem(command), "making library failed: #{command}") - File.unlink("#{CONFTEST}.#{$OBJEXT}") - config_string('RANLIB') do |ranlib| - command = "#{ranlib} #{lib}" - assert(xsystem(command), "ranlib failed: #{command}") - end +class TestMkmfHaveLibrary < TestMkmf + LIBRARY_NAME = 'mkmftest' + HEADER_NAME = "#{LIBRARY_NAME}.h" + FUNC_NAME = 'ruby_mkmftest_foo' + ARPREFIX = config_string('LIBRUBY_A') {|lib| lib[/\A\w+/]} + + def create_library(libname = LIBRARY_NAME) + lib = "#{ARPREFIX}#{libname}.#{$LIBEXT}" + open(HEADER_NAME, "w") do |hdr| + hdr.puts "void #{FUNC_NAME}(void);" + hdr.puts "void #{FUNC_NAME}_fake(void);" end - - def assert_have_library(*args) - assert_equal(true, have_library(LIBRARY_NAME, *args), MKMFLOG) + create_tmpsrc("#include \"#{HEADER_NAME}\"\n""void #{FUNC_NAME}(void) {}") + assert(xsystem(cc_command), "compile failed: #{cc_command}") + command = "#{CONFIG['AR']} #{config_string('ARFLAGS') || 'cru '}#{lib} #{CONFTEST}.#{$OBJEXT}" + assert(xsystem(command), "making library failed: #{command}") + File.unlink("#{CONFTEST}.#{$OBJEXT}") + config_string('RANLIB') do |ranlib| + command = "#{ranlib} #{lib}" + assert(xsystem(command), "ranlib failed: #{command}") end + end - def assert_not_have_library(*args) - assert_equal(false, have_library(LIBRARY_NAME, *args), MKMFLOG) - end + def assert_have_library(*args) + assert_equal(true, have_library(LIBRARY_NAME, *args), MKMFLOG) + end - def test_have_library - create_library - assert_have_library - end + def assert_not_have_library(*args) + assert_equal(false, have_library(LIBRARY_NAME, *args), MKMFLOG) + end - def test_have_library_with_name - create_library - assert_have_library(FUNC_NAME, HEADER_NAME) - end + def test_have_library + create_library + assert_have_library + end - def test_not_have_library - assert_not_have_library - end + def test_have_library_with_name + create_library + assert_have_library(FUNC_NAME, HEADER_NAME) + end - def test_not_have_library_with_name - create_library - assert_not_have_library("#{FUNC_NAME}_fake", HEADER_NAME) - end + def test_not_have_library + assert_not_have_library + end + + def test_not_have_library_with_name + create_library + assert_not_have_library("#{FUNC_NAME}_fake", HEADER_NAME) end end diff --git a/test/mkmf/test_have_macro.rb b/test/mkmf/test_have_macro.rb index ebc5648097..3178bfea0b 100644 --- a/test/mkmf/test_have_macro.rb +++ b/test/mkmf/test_have_macro.rb @@ -2,35 +2,33 @@ require_relative 'base' require 'tempfile' -class TestMkmf - class TestHaveMacro < TestMkmf - MACRO_NAME = "RUBY_MKMFTEST_FOOBAR" +class TestMkmfHaveMacro < TestMkmf + MACRO_NAME = "RUBY_MKMFTEST_FOOBAR" - def test_have_macro_opt - assert_equal(true, have_macro(MACRO_NAME, nil, "-D#{MACRO_NAME}"), MKMFLOG) - end + def test_have_macro_opt + assert_equal(true, have_macro(MACRO_NAME, nil, "-D#{MACRO_NAME}"), MKMFLOG) + end - def test_have_macro_header - Tempfile.create(%w"test_mkmf .h", ".") do |tmp| - tmp.puts("#undef #{MACRO_NAME}") - tmp.puts("#define #{MACRO_NAME} 1") - tmp.close - base = File.basename(tmp.path) - assert_equal(true, have_macro(MACRO_NAME, base, "-I."), MKMFLOG) - end + def test_have_macro_header + Tempfile.create(%w"test_mkmf .h", ".") do |tmp| + tmp.puts("#undef #{MACRO_NAME}") + tmp.puts("#define #{MACRO_NAME} 1") + tmp.close + base = File.basename(tmp.path) + assert_equal(true, have_macro(MACRO_NAME, base, "-I."), MKMFLOG) end + end - def test_not_have_macro_opt - assert_equal(false, have_macro(MACRO_NAME, nil, "-U#{MACRO_NAME}"), MKMFLOG) - end + def test_not_have_macro_opt + assert_equal(false, have_macro(MACRO_NAME, nil, "-U#{MACRO_NAME}"), MKMFLOG) + end - def test_not_have_macro_header - Tempfile.create(%w"test_mkmf .h", ".") do |tmp| - tmp.puts("#undef #{MACRO_NAME}") - tmp.close - base = File.basename(tmp.path) - assert_equal(false, have_macro(MACRO_NAME, base, "-I."), MKMFLOG) - end + def test_not_have_macro_header + Tempfile.create(%w"test_mkmf .h", ".") do |tmp| + tmp.puts("#undef #{MACRO_NAME}") + tmp.close + base = File.basename(tmp.path) + assert_equal(false, have_macro(MACRO_NAME, base, "-I."), MKMFLOG) end end end diff --git a/test/mkmf/test_install.rb b/test/mkmf/test_install.rb index 7f8c603d42..009d55f72d 100644 --- a/test/mkmf/test_install.rb +++ b/test/mkmf/test_install.rb @@ -1,27 +1,25 @@ # frozen_string_literal: false require_relative 'base' -class TestMkmf - class TestInstall < TestMkmf - def test_install_dirs - Dir.mktmpdir do |dir| - File.write(dir+"/extconf.rb", "require 'mkmf'; create_makefile('test')") - all_assertions do |a| +class TestMkmfInstall < TestMkmf + def test_install_dirs + Dir.mktmpdir do |dir| + File.write(dir+"/extconf.rb", "require 'mkmf'; create_makefile('test')") + all_assertions do |a| + a.foreach( + ["site"], + ["vendor", "--vendor"], + ) do |dest, *options| + assert_ruby_status(["-C", dir, "extconf.rb", *options]) + mf = File.read(dir+"/Makefile") a.foreach( - ["site"], - ["vendor", "--vendor"], - ) do |dest, *options| - assert_ruby_status(["-C", dir, "extconf.rb", *options]) - mf = File.read(dir+"/Makefile") - a.foreach( - ["RUBYCOMMONDIR", "$(#{dest}dir)$(target_prefix)"], - ["RUBYLIBDIR", "$(#{dest}libdir)$(target_prefix)"], - ["RUBYARCHDIR", "$(#{dest}archdir)$(target_prefix)"], - ["HDRDIR", "$(#{dest}hdrdir)$(target_prefix)"], - ["ARCHHDRDIR", "$(#{dest}archhdrdir)$(target_prefix)"], - ) do |(var, path)| - assert_equal path, mf[/^#{var}\s*=\s*(.*)$/, 1] - end + ["RUBYCOMMONDIR", "$(#{dest}dir)$(target_prefix)"], + ["RUBYLIBDIR", "$(#{dest}libdir)$(target_prefix)"], + ["RUBYARCHDIR", "$(#{dest}archdir)$(target_prefix)"], + ["HDRDIR", "$(#{dest}hdrdir)$(target_prefix)"], + ["ARCHHDRDIR", "$(#{dest}archhdrdir)$(target_prefix)"], + ) do |(var, path)| + assert_equal path, mf[/^#{var}\s*=\s*(.*)$/, 1] end end end diff --git a/test/mkmf/test_libs.rb b/test/mkmf/test_libs.rb index 9c5e1d29fb..2f84d024e2 100644 --- a/test/mkmf/test_libs.rb +++ b/test/mkmf/test_libs.rb @@ -1,94 +1,92 @@ # frozen_string_literal: false require_relative 'base' -class TestMkmf - class TestLibs < TestMkmf - def test_split_libs - assert_equal(%w[-lfoo -lbar], split_libs("-lfoo -lbar")) - end +class TestMkmfLibs < TestMkmf + def test_split_libs + assert_equal(%w[-lfoo -lbar], split_libs("-lfoo -lbar")) + end - def test_split_libs_macos - assert_equal(%w[-ObjC -framework\ Ruby], split_libs("-ObjC -framework Ruby"), 'Bug #6987') - end if /darwin/ =~ RUBY_PLATFORM + def test_split_libs_macos + assert_equal(%w[-ObjC -framework\ Ruby], split_libs("-ObjC -framework Ruby"), 'Bug #6987') + end if /darwin/ =~ RUBY_PLATFORM - def test_split_libs_windows - assert_equal(%w[zdll.lib libffi.lib], split_libs("zdll.lib libffi.lib")) - end if /mswin/ =~ RUBY_PLATFORM + def test_split_libs_windows + assert_equal(%w[zdll.lib libffi.lib], split_libs("zdll.lib libffi.lib")) + end if /mswin/ =~ RUBY_PLATFORM - def assert_in_order(array, x, y, mesg = nil) - mesg = "#{x} must proceed to #{y}#{': ' if mesg}#{mesg}" - assert_operator(array.index(x), :<, array.rindex(y), mesg) - end + def assert_in_order(array, x, y, mesg = nil) + mesg = "#{x} must proceed to #{y}#{': ' if mesg}#{mesg}" + assert_operator(array.index(x), :<, array.rindex(y), mesg) + end - def test_merge_simple - bug = '[ruby-dev:21765]' - assert_equal([], merge_libs(%w[])) - assert_equal(%w[a b], merge_libs(%w[a], %w[b])) - array = merge_libs(%w[a c], %w[b]) - assert_in_order(array, "a", "c", bug) - end + def test_merge_simple + bug = '[ruby-dev:21765]' + assert_equal([], merge_libs(%w[])) + assert_equal(%w[a b], merge_libs(%w[a], %w[b])) + array = merge_libs(%w[a c], %w[b]) + assert_in_order(array, "a", "c", bug) + end - def test_merge_seq - bug = '[ruby-dev:21765]' - array = merge_libs(%w[a c d], %w[c b e]) - assert_in_order(array, "a", "c", bug) - assert_in_order(array, "c", "d", bug) - assert_in_order(array, "c", "b", bug) - assert_in_order(array, "b", "e", bug) - end + def test_merge_seq + bug = '[ruby-dev:21765]' + array = merge_libs(%w[a c d], %w[c b e]) + assert_in_order(array, "a", "c", bug) + assert_in_order(array, "c", "d", bug) + assert_in_order(array, "c", "b", bug) + assert_in_order(array, "b", "e", bug) + end - def test_merge_seq_pre - bug = '[ruby-dev:21765]' - array = merge_libs(%w[a c d], %w[b c d e]) - assert_in_order(array, "a", "c", bug) - assert_in_order(array, "c", "d", bug) - assert_in_order(array, "b", "c", bug) - assert_in_order(array, "d", "e", bug) - end + def test_merge_seq_pre + bug = '[ruby-dev:21765]' + array = merge_libs(%w[a c d], %w[b c d e]) + assert_in_order(array, "a", "c", bug) + assert_in_order(array, "c", "d", bug) + assert_in_order(array, "b", "c", bug) + assert_in_order(array, "d", "e", bug) + end - def test_merge_cyclic - bug = '[ruby-dev:21765]' - array = merge_libs(%w[a c d], %w[b c b]) - assert_in_order(array, "a", "c", bug) - assert_in_order(array, "c", "d", bug) - assert_in_order(array, "b", "c", bug) - assert_in_order(array, "c", "b", bug) - end + def test_merge_cyclic + bug = '[ruby-dev:21765]' + array = merge_libs(%w[a c d], %w[b c b]) + assert_in_order(array, "a", "c", bug) + assert_in_order(array, "c", "d", bug) + assert_in_order(array, "b", "c", bug) + assert_in_order(array, "c", "b", bug) + end - def test_merge_cyclic_2 - bug = '[ruby-dev:21765]' - array = merge_libs(%w[a c a d], %w[b c b]) - assert_in_order(array, "a", "c", bug) - assert_in_order(array, "c", "a", bug) - assert_in_order(array, "c", "d", bug) - assert_in_order(array, "a", "d", bug) - assert_in_order(array, "b", "c", bug) - assert_in_order(array, "c", "b", bug) - end + def test_merge_cyclic_2 + bug = '[ruby-dev:21765]' + array = merge_libs(%w[a c a d], %w[b c b]) + assert_in_order(array, "a", "c", bug) + assert_in_order(array, "c", "a", bug) + assert_in_order(array, "c", "d", bug) + assert_in_order(array, "a", "d", bug) + assert_in_order(array, "b", "c", bug) + assert_in_order(array, "c", "b", bug) + end - def test_merge_reversal - bug = '[ruby-dev:22440]' - array = merge_libs(%w[a b c], %w[c d a]) - assert_in_order(array, "a", "b" , bug) - assert_in_order(array, "c", "d" , bug) - ## assume that a and c have no dependency - end + def test_merge_reversal + bug = '[ruby-dev:22440]' + array = merge_libs(%w[a b c], %w[c d a]) + assert_in_order(array, "a", "b" , bug) + assert_in_order(array, "c", "d" , bug) + ## assume that a and c have no dependency + end - def test_merge_reversal_followed - bug7467 = '[ruby-core:50314] [Bug #7467]' - array = nil - assert_nothing_raised(bug7467) { - array = merge_libs(%w[a b c d e f g h], %w[d c d e], []) - } - assert_in_order(array, "a", "b", bug7467) - assert_in_order(array, "b", "c", bug7467) - assert_in_order(array, "c", "d", bug7467) - assert_in_order(array, "d", "e", bug7467) - assert_in_order(array, "e", "f", bug7467) - assert_in_order(array, "f", "g", bug7467) - assert_in_order(array, "g", "h", bug7467) - assert_in_order(array, "d", "c", bug7467) - assert_in_order(array, "c", "e", bug7467) - end + def test_merge_reversal_followed + bug7467 = '[ruby-core:50314] [Bug #7467]' + array = nil + assert_nothing_raised(bug7467) { + array = merge_libs(%w[a b c d e f g h], %w[d c d e], []) + } + assert_in_order(array, "a", "b", bug7467) + assert_in_order(array, "b", "c", bug7467) + assert_in_order(array, "c", "d", bug7467) + assert_in_order(array, "d", "e", bug7467) + assert_in_order(array, "e", "f", bug7467) + assert_in_order(array, "f", "g", bug7467) + assert_in_order(array, "g", "h", bug7467) + assert_in_order(array, "d", "c", bug7467) + assert_in_order(array, "c", "e", bug7467) end end if RUBY_ENGINE == "ruby" diff --git a/test/mkmf/test_mkmf.rb b/test/mkmf/test_mkmf.rb index adb86eca8d..55f9aa3b88 100644 --- a/test/mkmf/test_mkmf.rb +++ b/test/mkmf/test_mkmf.rb @@ -2,14 +2,12 @@ require 'test/unit' require 'mkmf' -class TestMkmf < Test::Unit::TestCase - class TestGlobal < TestMkmf - main = TOPLEVEL_BINDING.receiver - MakeMakefile.public_instance_methods(false).each do |m| - define_method(:"test_global_#{m}") do - assert_respond_to(main, [m, true]) - assert_not_respond_to(main, [m, false]) - end +class TestMkmfGlobal < Test::Unit::TestCase + main = TOPLEVEL_BINDING.receiver + MakeMakefile.public_instance_methods(false).each do |m| + define_method(:"test_global_#{m}") do + assert_respond_to(main, [m, true]) + assert_not_respond_to(main, [m, false]) end end end diff --git a/test/mkmf/test_pkg_config.rb b/test/mkmf/test_pkg_config.rb new file mode 100644 index 0000000000..72efb4ba81 --- /dev/null +++ b/test/mkmf/test_pkg_config.rb @@ -0,0 +1,66 @@ +# frozen_string_literal: false +require_relative 'base' +require 'shellwords' + +class TestMkmfPkgConfig < TestMkmf + PKG_CONFIG = find_executable0("pkg-config") + + def setup + super + + if PKG_CONFIG + @fixtures_dir = File.join(Dir.pwd, "fixtures") + @fixtures_lib_dir = File.join(@fixtures_dir, "lib") + @fixtures_inc_dir = File.join(@fixtures_dir, "include") + + FileUtils.mkdir(@fixtures_dir) + File.write("fixtures/test1.pc", <<~EOF) + libdir=#{@fixtures_lib_dir} + includedir=#{@fixtures_inc_dir} + + Name: test1 + Description: Test for mkmf pkg-config method + Version: 1.2.3 + Libs: -L${libdir} -ltest1-public + Libs.private: -ltest1-private + Cflags: -I${includedir}/cflags-I --cflags-other + EOF + + @pkg_config_path, ENV["PKG_CONFIG_PATH"] = ENV["PKG_CONFIG_PATH"], File.join(Dir.pwd, "fixtures") + end + end + + def teardown + if PKG_CONFIG + ENV["PKG_CONFIG_PATH"] = @pkg_config_path + end + + super + end + + def test_pkgconfig_with_option_returns_nil_on_error + pend("skipping because pkg-config is not installed") unless PKG_CONFIG + assert_nil(pkg_config("package-does-not-exist", "exists"), MKMFLOG) + end + + def test_pkgconfig_with_libs_option_returns_output + pend("skipping because pkg-config is not installed") unless PKG_CONFIG + expected = ["-L#{@fixtures_lib_dir}", "-ltest1-public"].sort + actual = pkg_config("test1", "libs").shellsplit.sort + assert_equal(expected, actual, MKMFLOG) + end + + def test_pkgconfig_with_cflags_option_returns_output + pend("skipping because pkg-config is not installed") unless PKG_CONFIG + expected = ["--cflags-other", "-I#{@fixtures_inc_dir}/cflags-I"].sort + actual = pkg_config("test1", "cflags").shellsplit.sort + assert_equal(expected, actual, MKMFLOG) + end + + def test_pkgconfig_with_multiple_options + pend("skipping because pkg-config is not installed") unless PKG_CONFIG + expected = ["-L#{@fixtures_lib_dir}", "-ltest1-public", "-ltest1-private"].sort + actual = pkg_config("test1", "libs", "static").shellsplit.sort + assert_equal(expected, actual, MKMFLOG) + end +end diff --git a/test/mkmf/test_signedness.rb b/test/mkmf/test_signedness.rb index 589dcb56e8..a59e3548a2 100644 --- a/test/mkmf/test_signedness.rb +++ b/test/mkmf/test_signedness.rb @@ -1,30 +1,28 @@ # frozen_string_literal: false require_relative 'base' -class TestMkmf - class TestSignedness < TestMkmf - def test_typeof_builtin - bug4144 = '[ruby-dev:42731]' - [["", "-1"], ["signed ", "-1"], ["unsigned ", "+1"]].each do |signed, expect| - %w[short int long].each do |type| - assert_equal(expect.to_i, mkmf {check_signedness(signed+type)}, mkmflog(bug4144)) - end +class TestMkmfSignedness < TestMkmf + def test_typeof_builtin + bug4144 = '[ruby-dev:42731]' + [["", "-1"], ["signed ", "-1"], ["unsigned ", "+1"]].each do |signed, expect| + %w[short int long].each do |type| + assert_equal(expect.to_i, mkmf {check_signedness(signed+type)}, mkmflog(bug4144)) end end + end - def test_typeof_typedef - [["", "-1"], ["signed ", "-1"], ["unsigned ", "+1"]].each do |signed, expect| - %w[short int long].each do |type| - open("confdefs.h", "w") {|f| - f.puts "typedef #{signed}#{type} test1_t;" - } - $defs.clear - assert_equal(expect.to_i, mkmf {check_signedness("test1_t", "confdefs.h")}, MKMFLOG) - assert_include($defs, "-DSIGNEDNESS_OF_TEST1_T=#{expect}") - end + def test_typeof_typedef + [["", "-1"], ["signed ", "-1"], ["unsigned ", "+1"]].each do |signed, expect| + %w[short int long].each do |type| + open("confdefs.h", "w") {|f| + f.puts "typedef #{signed}#{type} test1_t;" + } + $defs.clear + assert_equal(expect.to_i, mkmf {check_signedness("test1_t", "confdefs.h")}, MKMFLOG) + assert_include($defs, "-DSIGNEDNESS_OF_TEST1_T=#{expect}") end - ensure - File.unlink("confdefs.h") end + ensure + File.unlink("confdefs.h") end end diff --git a/test/mkmf/test_sizeof.rb b/test/mkmf/test_sizeof.rb index 742c3d6454..6fb0a6a8f6 100644 --- a/test/mkmf/test_sizeof.rb +++ b/test/mkmf/test_sizeof.rb @@ -1,48 +1,46 @@ # frozen_string_literal: false require_relative 'base' -class TestMkmf - class TestSizeof < TestMkmf - def setup - super - @sizeof_short = config_value("SIZEOF_SHORT").to_i - @sizeof_int = config_value("SIZEOF_INT").to_i - @sizeof_long = config_value("SIZEOF_LONG").to_i - @sizeof_long_long = config_value("SIZEOF_LONG_LONG").to_i - @sizeof___int64 = config_value("SIZEOF___INT64").to_i - end +class TestMkmfSizeof < TestMkmf + def setup + super + @sizeof_short = config_value("SIZEOF_SHORT").to_i + @sizeof_int = config_value("SIZEOF_INT").to_i + @sizeof_long = config_value("SIZEOF_LONG").to_i + @sizeof_long_long = config_value("SIZEOF_LONG_LONG").to_i + @sizeof___int64 = config_value("SIZEOF___INT64").to_i + end - def test_sizeof_builtin - %w[char short int long float double void*].each do |type| - assert_kind_of(Integer, mkmf {check_sizeof(type)}, MKMFLOG) - end - assert_operator(@sizeof_short, :<=, @sizeof_int) - assert_operator(@sizeof_int, :<=, @sizeof_long) - assert_operator(@sizeof_long, :<=, @sizeof_long_long) unless @sizeof_long_long.zero? - assert_equal(8, @sizeof___int64) unless @sizeof___int64.zero? + def test_sizeof_builtin + %w[char short int long float double void*].each do |type| + assert_kind_of(Integer, mkmf {check_sizeof(type)}, MKMFLOG) end + assert_operator(@sizeof_short, :<=, @sizeof_int) + assert_operator(@sizeof_int, :<=, @sizeof_long) + assert_operator(@sizeof_long, :<=, @sizeof_long_long) unless @sizeof_long_long.zero? + assert_equal(8, @sizeof___int64) unless @sizeof___int64.zero? + end - def test_sizeof_struct - open("confdefs.h", "w") {|f| - f.puts "typedef struct {char x;} test1_t;" - } - assert_equal(1, mkmf {check_sizeof("test1_t", "confdefs.h")}, MKMFLOG) + def test_sizeof_struct + open("confdefs.h", "w") {|f| + f.puts "typedef struct {char x;} test1_t;" + } + assert_equal(1, mkmf {check_sizeof("test1_t", "confdefs.h")}, MKMFLOG) - open("confdefs.h", "w") {|f| - f.puts "typedef struct {char x, y;} test1_t;" - } - assert_equal(2, mkmf {check_sizeof("test1_t", "confdefs.h")}, MKMFLOG) + open("confdefs.h", "w") {|f| + f.puts "typedef struct {char x, y;} test1_t;" + } + assert_equal(2, mkmf {check_sizeof("test1_t", "confdefs.h")}, MKMFLOG) - open("confdefs.h", "w") {|f| - f.puts "typedef struct {int x;} test1_t;" - } - assert_equal(@sizeof_int, mkmf {check_sizeof("test1_t", "confdefs.h")}, MKMFLOG) - open("confdefs.h", "w") {|f| - f.puts "typedef struct {int x, y;} test1_t;" - } - assert_equal(2 * @sizeof_int, mkmf {check_sizeof("test1_t", "confdefs.h")}, MKMFLOG) - ensure - File.unlink("confdefs.h") - end + open("confdefs.h", "w") {|f| + f.puts "typedef struct {int x;} test1_t;" + } + assert_equal(@sizeof_int, mkmf {check_sizeof("test1_t", "confdefs.h")}, MKMFLOG) + open("confdefs.h", "w") {|f| + f.puts "typedef struct {int x, y;} test1_t;" + } + assert_equal(2 * @sizeof_int, mkmf {check_sizeof("test1_t", "confdefs.h")}, MKMFLOG) + ensure + File.unlink("confdefs.h") end end diff --git a/test/net/http/test_http.rb b/test/net/http/test_http.rb index b5156078a4..e9471273f4 100644 --- a/test/net/http/test_http.rb +++ b/test/net/http/test_http.rb @@ -1294,3 +1294,87 @@ class TestNetHTTPLocalBind < Test::Unit::TestCase end end +class TestNetHTTPForceEncoding < Test::Unit::TestCase + CONFIG = { + 'host' => 'localhost', + 'proxy_host' => nil, + 'proxy_port' => nil, + } + + include TestNetHTTPUtils + + def fe_request(force_enc, content_type=nil) + @server.mount_proc('/fe') do |req, res| + res['Content-Type'] = content_type if content_type + res.body = "hello\u1234" + end + + http = Net::HTTP.new(config('host'), config('port')) + http.local_host = Addrinfo.tcp(config('host'), config('port')).ip_address + assert_not_nil(http.local_host) + assert_nil(http.local_port) + + http.response_body_encoding = force_enc + http.get('/fe') + end + + def test_response_body_encoding_false + res = fe_request(false) + assert_equal("hello\u1234".b, res.body) + assert_equal(Encoding::ASCII_8BIT, res.body.encoding) + end + + def test_response_body_encoding_true_without_content_type + res = fe_request(true) + assert_equal("hello\u1234".b, res.body) + assert_equal(Encoding::ASCII_8BIT, res.body.encoding) + end + + def test_response_body_encoding_true_with_content_type + res = fe_request(true, 'text/html; charset=utf-8') + assert_equal("hello\u1234", res.body) + assert_equal(Encoding::UTF_8, res.body.encoding) + end + + def test_response_body_encoding_string_without_content_type + res = fe_request('utf-8') + assert_equal("hello\u1234", res.body) + assert_equal(Encoding::UTF_8, res.body.encoding) + end + + def test_response_body_encoding_encoding_without_content_type + res = fe_request(Encoding::UTF_8) + assert_equal("hello\u1234", res.body) + assert_equal(Encoding::UTF_8, res.body.encoding) + end +end + +class TestNetHTTPPartialResponse < Test::Unit::TestCase + CONFIG = { + 'host' => '127.0.0.1', + 'proxy_host' => nil, + 'proxy_port' => nil, + } + + include TestNetHTTPUtils + + def test_partial_response + str = "0123456789" + @server.mount_proc('/') do |req, res| + res.status = 200 + res['Content-Type'] = 'text/plain' + + res.body = str + res['Content-Length'] = str.length + 1 + end + @server.mount_proc('/show_ip') { |req, res| res.body = req.remote_ip } + + http = Net::HTTP.new(config('host'), config('port')) + res = http.get('/') + assert_equal(str, res.body) + + http = Net::HTTP.new(config('host'), config('port')) + http.ignore_eof = false + assert_raise(EOFError) {http.get('/')} + end +end diff --git a/test/net/http/test_httpresponse.rb b/test/net/http/test_httpresponse.rb index 00b0072e70..394b4c5bfa 100644 --- a/test/net/http/test_httpresponse.rb +++ b/test/net/http/test_httpresponse.rb @@ -54,6 +54,241 @@ EOS assert_equal 'hello', body end + def test_read_body_body_encoding_false + body = "hello\u1234" + io = dummy_io(<<EOS) +HTTP/1.1 200 OK +Connection: close +Content-Length: #{body.bytesize} + +#{body} +EOS + + res = Net::HTTPResponse.read_new(io) + + body = nil + + res.reading_body io, true do + body = res.read_body + end + + assert_equal "hello\u1234".b, body + assert_equal Encoding::ASCII_8BIT, body.encoding + end + + def test_read_body_body_encoding_encoding + body = "hello\u1234" + io = dummy_io(<<EOS) +HTTP/1.1 200 OK +Connection: close +Content-Length: #{body.bytesize} + +#{body} +EOS + + res = Net::HTTPResponse.read_new(io) + res.body_encoding = Encoding.find('utf-8') + + body = nil + + res.reading_body io, true do + body = res.read_body + end + + assert_equal "hello\u1234", body + assert_equal Encoding::UTF_8, body.encoding + end + + def test_read_body_body_encoding_string + body = "hello\u1234" + io = dummy_io(<<EOS) +HTTP/1.1 200 OK +Connection: close +Content-Length: #{body.bytesize} + +#{body} +EOS + + res = Net::HTTPResponse.read_new(io) + res.body_encoding = 'utf-8' + + body = nil + + res.reading_body io, true do + body = res.read_body + end + + assert_equal "hello\u1234", body + assert_equal Encoding::UTF_8, body.encoding + end + + def test_read_body_body_encoding_true_without_content_type_header + body = "hello\u1234" + io = dummy_io(<<EOS) +HTTP/1.1 200 OK +Connection: close +Content-Length: #{body.bytesize} + +#{body} +EOS + + res = Net::HTTPResponse.read_new(io) + res.body_encoding = true + + body = nil + + res.reading_body io, true do + body = res.read_body + end + + assert_equal "hello\u1234".b, body + assert_equal Encoding::ASCII_8BIT, body.encoding + end + + def test_read_body_body_encoding_true_with_utf8_content_type_header + body = "hello\u1234" + io = dummy_io(<<EOS) +HTTP/1.1 200 OK +Connection: close +Content-Length: #{body.bytesize} +Content-Type: text/plain; charset=utf-8 + +#{body} +EOS + + res = Net::HTTPResponse.read_new(io) + res.body_encoding = true + + body = nil + + res.reading_body io, true do + body = res.read_body + end + + assert_equal "hello\u1234", body + assert_equal Encoding::UTF_8, body.encoding + end + + def test_read_body_body_encoding_true_with_iso_8859_1_content_type_header + body = "hello\u1234" + io = dummy_io(<<EOS) +HTTP/1.1 200 OK +Connection: close +Content-Length: #{body.bytesize} +Content-Type: text/plain; charset=iso-8859-1 + +#{body} +EOS + + res = Net::HTTPResponse.read_new(io) + res.body_encoding = true + + body = nil + + res.reading_body io, true do + body = res.read_body + end + + assert_equal "hello\u1234".force_encoding("ISO-8859-1"), body + assert_equal Encoding::ISO_8859_1, body.encoding + end + + def test_read_body_body_encoding_true_with_utf8_meta_charset + res_body = "<html><meta charset=\"utf-8\">hello\u1234</html>" + io = dummy_io(<<EOS) +HTTP/1.1 200 OK +Connection: close +Content-Length: #{res_body.bytesize} +Content-Type: text/html + +#{res_body} +EOS + + res = Net::HTTPResponse.read_new(io) + res.body_encoding = true + + body = nil + + res.reading_body io, true do + body = res.read_body + end + + assert_equal res_body, body + assert_equal Encoding::UTF_8, body.encoding + end + + def test_read_body_body_encoding_true_with_iso8859_1_meta_charset + res_body = "<html><meta charset=\"iso-8859-1\">hello\u1234</html>" + io = dummy_io(<<EOS) +HTTP/1.1 200 OK +Connection: close +Content-Length: #{res_body.bytesize} +Content-Type: text/html + +#{res_body} +EOS + + res = Net::HTTPResponse.read_new(io) + res.body_encoding = true + + body = nil + + res.reading_body io, true do + body = res.read_body + end + + assert_equal res_body.force_encoding("ISO-8859-1"), body + assert_equal Encoding::ISO_8859_1, body.encoding + end + + def test_read_body_body_encoding_true_with_utf8_meta_content_charset + res_body = "<meta http-equiv='content-type' content='text/html; charset=UTF-8'>hello\u1234</html>" + io = dummy_io(<<EOS) +HTTP/1.1 200 OK +Connection: close +Content-Length: #{res_body.bytesize} +Content-Type: text/html + +#{res_body} +EOS + + res = Net::HTTPResponse.read_new(io) + res.body_encoding = true + + body = nil + + res.reading_body io, true do + body = res.read_body + end + + assert_equal res_body, body + assert_equal Encoding::UTF_8, body.encoding + end + + def test_read_body_body_encoding_true_with_iso8859_1_meta_content_charset + res_body = "<meta http-equiv='content-type' content='text/html; charset=ISO-8859-1'>hello\u1234</html>" + io = dummy_io(<<EOS) +HTTP/1.1 200 OK +Connection: close +Content-Length: #{res_body.bytesize} +Content-Type: text/html + +#{res_body} +EOS + + res = Net::HTTPResponse.read_new(io) + res.body_encoding = true + + body = nil + + res.reading_body io, true do + body = res.read_body + end + + assert_equal res_body.force_encoding("ISO-8859-1"), body + assert_equal Encoding::ISO_8859_1, body.encoding + end + def test_read_body_block io = dummy_io(<<EOS) HTTP/1.1 200 OK @@ -78,7 +313,7 @@ EOS def test_read_body_block_mod # http://ci.rvm.jp/results/trunk-mjit-wait@silicon-docker/3019353 - if defined?(RubyVM::JIT) ? RubyVM::JIT.enabled? : defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? + if defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? omit 'too unstable with --jit-wait, and extending read_timeout did not help it' end IO.pipe do |r, w| @@ -127,9 +362,11 @@ EOS if Net::HTTP::HAVE_ZLIB assert_equal nil, res['content-encoding'] + assert_equal '5', res['content-length'] assert_equal 'hello', body else assert_equal 'deflate', res['content-encoding'] + assert_equal '13', res['content-length'] assert_equal "x\x9C\xCBH\xCD\xC9\xC9\a\x00\x06,\x02\x15", body end end @@ -155,9 +392,11 @@ EOS if Net::HTTP::HAVE_ZLIB assert_equal nil, res['content-encoding'] + assert_equal '5', res['content-length'] assert_equal 'hello', body else assert_equal 'DEFLATE', res['content-encoding'] + assert_equal '13', res['content-length'] assert_equal "x\x9C\xCBH\xCD\xC9\xC9\a\x00\x06,\x02\x15", body end end @@ -188,9 +427,11 @@ EOS if Net::HTTP::HAVE_ZLIB assert_equal nil, res['content-encoding'] + assert_equal nil, res['content-length'] assert_equal 'hello', body else assert_equal 'deflate', res['content-encoding'] + assert_equal nil, res['content-length'] assert_equal "x\x9C\xCBH\xCD\xC9\xC9\a\x00\x06,\x02\x15", body end end @@ -215,6 +456,7 @@ EOS end assert_equal 'deflate', res['content-encoding'], 'Bug #7831' + assert_equal '13', res['content-length'] assert_equal "x\x9C\xCBH\xCD\xC9\xC9\a\x00\x06,\x02\x15", body, 'Bug #7381' end @@ -238,9 +480,11 @@ EOS if Net::HTTP::HAVE_ZLIB assert_equal nil, res['content-encoding'] + assert_equal nil, res['content-length'] assert_equal 'hello', body else assert_equal 'deflate', res['content-encoding'] + assert_equal nil, res['content-length'] assert_equal "x\x9C\xCBH\xCD\xC9\xC9\a\x00\x06,\x02\x15\r\n", body end end @@ -288,9 +532,11 @@ EOS if Net::HTTP::HAVE_ZLIB assert_equal nil, res['content-encoding'] + assert_equal '0', res['content-length'] assert_equal '', body else assert_equal 'deflate', res['content-encoding'] + assert_equal '0', res['content-length'] assert_equal '', body end end @@ -314,9 +560,11 @@ EOS if Net::HTTP::HAVE_ZLIB assert_equal nil, res['content-encoding'] + assert_equal nil, res['content-length'] assert_equal '', body else assert_equal 'deflate', res['content-encoding'] + assert_equal nil, res['content-length'] assert_equal '', body end end diff --git a/test/net/http/test_https.rb b/test/net/http/test_https.rb index 4dc9f1b026..72a69af1a5 100644 --- a/test/net/http/test_https.rb +++ b/test/net/http/test_https.rb @@ -137,7 +137,7 @@ class TestNetHTTPS < Test::Unit::TestCase def test_session_reuse # FIXME: The new_session_cb is known broken for clients in OpenSSL 1.1.0h. # See https://github.com/openssl/openssl/pull/5967 for details. - skip if OpenSSL::OPENSSL_LIBRARY_VERSION =~ /OpenSSL 1.1.0h/ + omit if OpenSSL::OPENSSL_LIBRARY_VERSION.include?('OpenSSL 1.1.0h') http = Net::HTTP.new(HOST, config("port")) http.use_ssl = true @@ -152,19 +152,21 @@ class TestNetHTTPS < Test::Unit::TestCase end http.start - assert_equal false, http.instance_variable_get(:@socket).io.session_reused? + session_reused = http.instance_variable_get(:@socket).io.session_reused? + assert_false session_reused unless session_reused.nil? # can not detect re-use under JRuby http.get("/") http.finish http.start - assert_equal true, http.instance_variable_get(:@socket).io.session_reused? + session_reused = http.instance_variable_get(:@socket).io.session_reused? + assert_true session_reused unless session_reused.nil? # can not detect re-use under JRuby assert_equal $test_net_http_data, http.get("/").body http.finish end def test_session_reuse_but_expire # FIXME: The new_session_cb is known broken for clients in OpenSSL 1.1.0h. - skip if OpenSSL::OPENSSL_LIBRARY_VERSION =~ /OpenSSL 1.1.0h/ + omit if OpenSSL::OPENSSL_LIBRARY_VERSION.include?('OpenSSL 1.1.0h') http = Net::HTTP.new(HOST, config("port")) http.use_ssl = true @@ -301,7 +303,7 @@ class TestNetHTTPS < Test::Unit::TestCase ex = assert_raise(OpenSSL::SSL::SSLError){ http.request_get("/") {|res| } } - re_msg = /\ASSL_connect returned=1 errno=0 |SSL_CTX_set_max_proto_version/ + re_msg = /\ASSL_connect returned=1 errno=0 |SSL_CTX_set_max_proto_version|No appropriate protocol/ assert_match(re_msg, ex.message) end diff --git a/test/net/http/test_https_proxy.rb b/test/net/http/test_https_proxy.rb index f833f1a1e3..4c2a92ccd6 100644 --- a/test/net/http/test_https_proxy.rb +++ b/test/net/http/test_https_proxy.rb @@ -10,7 +10,7 @@ class HTTPSProxyTest < Test::Unit::TestCase begin OpenSSL rescue LoadError - skip 'autoload problem. see [ruby-dev:45021][Bug #5786]' + omit 'autoload problem. see [ruby-dev:45021][Bug #5786]' end TCPServer.open("127.0.0.1", 0) {|serv| diff --git a/test/objspace/test_objspace.rb b/test/objspace/test_objspace.rb index a1954d56a9..ed9c998597 100644 --- a/test/objspace/test_objspace.rb +++ b/test/objspace/test_objspace.rb @@ -33,7 +33,7 @@ class TestObjSpace < Test::Unit::TestCase b = a.dup c = nil ObjectSpace.each_object(String) {|x| break c = x if x == a and x.frozen?} - rv_size = GC::INTERNAL_CONSTANTS[:RVALUE_SIZE] + rv_size = GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE] assert_equal([rv_size, rv_size, a.length + 1 + rv_size], [a, b, c].map {|x| ObjectSpace.memsize_of(x)}) end @@ -140,6 +140,18 @@ class TestObjSpace < Test::Unit::TestCase end; end + def test_reachable_objects_during_iteration + opts = %w[--disable-gem --disable=frozen-string-literal -robjspace] + assert_separately opts, "#{<<-"begin;"}\n#{<<-'end;'}" + begin; + ObjectSpace.each_object{|o| + o.inspect + ObjectSpace.reachable_objects_from(Class) + } + end; + end + + def test_reachable_objects_from_root root_objects = ObjectSpace.reachable_objects_from_root @@ -295,6 +307,28 @@ class TestObjSpace < Test::Unit::TestCase JSON.parse(info) if defined?(JSON) end + def test_dump_array + # Empty array + info = ObjectSpace.dump([]) + assert_include(info, '"length":0, "embedded":true') + assert_not_include(info, '"shared":true') + + # Non-embed array + arr = (1..10).to_a + info = ObjectSpace.dump(arr) + assert_include(info, '"length":10') + assert_not_include(info, '"embedded":true') + assert_not_include(info, '"shared":true') + + # Shared array + arr1 = (1..10).to_a + arr = [] + arr.replace(arr1) + info = ObjectSpace.dump(arr) + assert_include(info, '"length":10, "shared":true') + assert_not_include(info, '"embedded":true') + end + def test_dump_control_char assert_include(ObjectSpace.dump("\x0f"), '"value":"\u000f"') assert_include(ObjectSpace.dump("\C-?"), '"value":"\u007f"') @@ -431,6 +465,27 @@ class TestObjSpace < Test::Unit::TestCase end end + def test_dump_objects_dumps_page_slot_sizes + assert_in_out_err(%w[-robjspace], "#{<<-"begin;"}\n#{<<-'end;'}") do |output, error| + begin; + def dump_my_heap_please + ObjectSpace.dump_all(output: $stdout) + end + + p $stdout == dump_my_heap_please + end; + assert_equal 'true', output.pop + assert(output.count > 1) + output.each { |l| + obj = JSON.parse(l) + next if obj["type"] == "ROOT" + + assert(obj["slot_size"] != nil) + assert(obj["slot_size"] % GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE] == 0) + } + end + end + def test_dump_escapes_method_name method_name = "foo\"bar" klass = Class.new do @@ -449,6 +504,13 @@ class TestObjSpace < Test::Unit::TestCase ObjectSpace.trace_object_allocations_stop end + def test_dump_includes_slot_size + str = "TEST" + dump = ObjectSpace.dump(str) + + assert_includes dump, "\"slot_size\":#{GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE]}" + end + def test_dump_reference_addresses_match_dump_all_addresses assert_in_out_err(%w[-robjspace], "#{<<-"begin;"}\n#{<<-'end;'}") do |output, error| begin; @@ -470,8 +532,28 @@ class TestObjSpace < Test::Unit::TestCase end end + def assert_test_string_entry_correct_in_dump_all(output) + # `TEST STRING` appears twice in the output of `ObjectSpace.dump_all` + # 1. To create the T_STRING object for the literal string "TEST STRING" + # 2. When it is assigned to the `str` variable with a new encoding + # + # This test makes assertions on the assignment to `str`, so we look for + # the second appearance of /TEST STRING/ in the output + test_string_in_dump_all = output.grep(/TEST STRING/) + assert_equal(test_string_in_dump_all.size, 2) + + entry_hash = JSON.parse(test_string_in_dump_all[1]) + + assert_equal(entry_hash["bytesize"], 11) + assert_equal(entry_hash["value"], "TEST STRING") + assert_equal(entry_hash["encoding"], "UTF-8") + assert_equal(entry_hash["file"], "-") + assert_equal(entry_hash["line"], 4) + assert_equal(entry_hash["method"], "dump_my_heap_please") + assert_not_nil(entry_hash["generation"]) + end + def test_dump_all - entry = /"bytesize":11, "value":"TEST STRING", "encoding":"UTF-8", "file":"-", "line":4, "method":"dump_my_heap_please", "generation":/ opts = %w[--disable-gem --disable=frozen-string-literal -robjspace] assert_in_out_err(opts, "#{<<-"begin;"}#{<<-'end;'}") do |output, error| @@ -485,8 +567,8 @@ class TestObjSpace < Test::Unit::TestCase p dump_my_heap_please end; - assert_equal 'nil', output.pop - assert_match(entry, output.grep(/TEST STRING/).join("\n")) + + assert_test_string_entry_correct_in_dump_all(output) end assert_in_out_err(%w[-robjspace], "#{<<-"begin;"}#{<<-'end;'}") do |(output), (error)| @@ -503,7 +585,8 @@ class TestObjSpace < Test::Unit::TestCase assert_nil(error) dump = File.readlines(output) File.unlink(output) - assert_match(entry, dump.grep(/TEST STRING/).join("\n")) + + assert_test_string_entry_correct_in_dump_all(dump) end if defined?(JSON) diff --git a/test/openssl/test_bn.rb b/test/openssl/test_bn.rb index 3f0622f94f..346602dada 100644 --- a/test/openssl/test_bn.rb +++ b/test/openssl/test_bn.rb @@ -334,6 +334,31 @@ class OpenSSL::TestBN < OpenSSL::TestCase e.set_flags(0) assert_equal(4, e.get_flags(OpenSSL::BN::CONSTTIME)) end + + if respond_to?(:ractor) + ractor + def test_ractor + assert_equal(@e1, Ractor.new { OpenSSL::BN.new("999") }.take) + assert_equal(@e3, Ractor.new { OpenSSL::BN.new("\a\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF\xFF", 2) }.take) + assert_equal("999", Ractor.new(@e1) { |e1| e1.to_s }.take) + assert_equal("07FFFFFFFFFFFFFFFFFFFFFFFFFF", Ractor.new(@e3) { |e3| e3.to_s(16) }.take) + assert_equal(2**107-1, Ractor.new(@e3) { _1.to_i }.take) + assert_equal([1000, -999], Ractor.new(@e2) { _1.coerce(1000) }.take) + assert_equal(false, Ractor.new { 1.to_bn.zero? }.take) + assert_equal(true, Ractor.new { 1.to_bn.one? }.take) + assert_equal(true, Ractor.new(@e2) { _1.negative? }.take) + assert_equal("-03E7", Ractor.new(@e2) { _1.to_s(16) }.take) + assert_equal(2**107-1, Ractor.new(@e3) { _1.to_i }.take) + assert_equal([1000, -999], Ractor.new(@e2) { _1.coerce(1000) }.take) + assert_equal(true, Ractor.new { 0.to_bn.zero? }.take) + assert_equal(true, Ractor.new { 1.to_bn.one? }.take ) + assert_equal(false,Ractor.new { 2.to_bn.odd? }.take) + assert_equal(true, Ractor.new(@e2) { _1.negative? }.take) + assert_include(128..255, Ractor.new { OpenSSL::BN.rand(8)}.take) + assert_include(0...2**32, Ractor.new { OpenSSL::BN.generate_prime(32) }.take) + assert_equal(0, Ractor.new { OpenSSL::BN.new(999).get_flags(OpenSSL::BN::CONSTTIME) }.take) + end + end end end diff --git a/test/openssl/test_cipher.rb b/test/openssl/test_cipher.rb index 6d18c0c85c..b5fdf0b3d1 100644 --- a/test/openssl/test_cipher.rb +++ b/test/openssl/test_cipher.rb @@ -135,14 +135,11 @@ class OpenSSL::TestCipher < OpenSSL::TestCase end def test_ciphers - OpenSSL::Cipher.ciphers.each{|name| - next if /netbsd/ =~ RUBY_PLATFORM && /idea|rc5/i =~ name - begin - assert_kind_of(OpenSSL::Cipher, OpenSSL::Cipher.new(name)) - rescue OpenSSL::Cipher::CipherError => e - raise unless /wrap/ =~ name and /wrap mode not allowed/ =~ e.message - end - } + ciphers = OpenSSL::Cipher.ciphers + assert_kind_of Array, ciphers + assert_include ciphers, "aes-128-cbc" + assert_include ciphers, "aes128" # alias of aes-128-cbc + assert_include ciphers, "aes-128-gcm" end def test_AES diff --git a/test/openssl/test_hmac.rb b/test/openssl/test_hmac.rb index 2f53a813e1..47cb3718df 100644 --- a/test/openssl/test_hmac.rb +++ b/test/openssl/test_hmac.rb @@ -21,6 +21,7 @@ class OpenSSL::TestHMAC < OpenSSL::TestCase end def test_dup + pend "HMAC#initialize_copy is currently broken on OpenSSL 3.0.0" if openssl?(3, 0, 0) h1 = OpenSSL::HMAC.new("KEY", "MD5") h1.update("DATA") h = h1.dup diff --git a/test/openssl/test_pkey_dh.rb b/test/openssl/test_pkey_dh.rb index 757704caf6..161af1897b 100644 --- a/test/openssl/test_pkey_dh.rb +++ b/test/openssl/test_pkey_dh.rb @@ -26,14 +26,19 @@ class OpenSSL::TestPKeyDH < OpenSSL::PKeyTestCase end def test_derive_key - dh1 = Fixtures.pkey("dh1024").generate_key! - dh2 = Fixtures.pkey("dh1024").generate_key! + params = Fixtures.pkey("dh1024") + dh1 = OpenSSL::PKey.generate_key(params) + dh2 = OpenSSL::PKey.generate_key(params) dh1_pub = OpenSSL::PKey.read(dh1.public_to_der) dh2_pub = OpenSSL::PKey.read(dh2.public_to_der) + z = dh1.g.mod_exp(dh1.priv_key, dh1.p).mod_exp(dh2.priv_key, dh1.p).to_s(2) assert_equal z, dh1.derive(dh2_pub) assert_equal z, dh2.derive(dh1_pub) + assert_raise(OpenSSL::PKey::PKeyError) { params.derive(dh1_pub) } + assert_raise(OpenSSL::PKey::PKeyError) { dh1_pub.derive(params) } + assert_equal z, dh1.compute_key(dh2.pub_key) assert_equal z, dh2.compute_key(dh1.pub_key) end @@ -74,19 +79,16 @@ class OpenSSL::TestPKeyDH < OpenSSL::PKeyTestCase end def test_generate_key - dh = Fixtures.pkey("dh1024").public_key # creates a copy + # Deprecated in v3.0.0; incompatible with OpenSSL 3.0 + dh = Fixtures.pkey("dh1024").public_key # creates a copy with params only assert_no_key(dh) dh.generate_key! assert_key(dh) - end - def test_key_exchange - dh = Fixtures.pkey("dh1024") dh2 = dh.public_key - dh.generate_key! dh2.generate_key! assert_equal(dh.compute_key(dh2.pub_key), dh2.compute_key(dh.pub_key)) - end + end if !openssl?(3, 0, 0) def test_params_ok? dh0 = Fixtures.pkey("dh1024") @@ -105,13 +107,32 @@ class OpenSSL::TestPKeyDH < OpenSSL::PKeyTestCase end def test_dup - dh = Fixtures.pkey("dh1024") - dh2 = dh.dup - assert_equal dh.to_der, dh2.to_der # params - assert_equal_params dh, dh2 # keys - dh2.set_pqg(dh2.p + 1, nil, dh2.g) - assert_not_equal dh2.p, dh.p - assert_equal dh2.g, dh.g + # Parameters only + dh1 = Fixtures.pkey("dh1024") + dh2 = dh1.dup + assert_equal dh1.to_der, dh2.to_der + assert_not_equal nil, dh1.p + assert_not_equal nil, dh1.g + assert_equal [dh1.p, dh1.g], [dh2.p, dh2.g] + assert_equal nil, dh1.pub_key + assert_equal nil, dh1.priv_key + assert_equal [dh1.pub_key, dh1.priv_key], [dh2.pub_key, dh2.priv_key] + + # PKey is immutable in OpenSSL >= 3.0 + if !openssl?(3, 0, 0) + dh2.set_pqg(dh2.p + 1, nil, dh2.g) + assert_not_equal dh2.p, dh1.p + end + + # With a key pair + dh3 = OpenSSL::PKey.generate_key(Fixtures.pkey("dh1024")) + dh4 = dh3.dup + assert_equal dh3.to_der, dh4.to_der + assert_equal dh1.to_der, dh4.to_der # encodes parameters only + assert_equal [dh1.p, dh1.g], [dh4.p, dh4.g] + assert_not_equal nil, dh3.pub_key + assert_not_equal nil, dh3.priv_key + assert_equal [dh3.pub_key, dh3.priv_key], [dh4.pub_key, dh4.priv_key] end def test_marshal @@ -123,11 +144,6 @@ class OpenSSL::TestPKeyDH < OpenSSL::PKeyTestCase private - def assert_equal_params(dh1, dh2) - assert_equal(dh1.g, dh2.g) - assert_equal(dh1.p, dh2.p) - end - def assert_no_key(dh) assert_equal(false, dh.public?) assert_equal(false, dh.private?) diff --git a/test/openssl/test_pkey_dsa.rb b/test/openssl/test_pkey_dsa.rb index 0994607f21..726b7dbf7e 100644 --- a/test/openssl/test_pkey_dsa.rb +++ b/test/openssl/test_pkey_dsa.rb @@ -208,8 +208,12 @@ fWLOqqkzFeRrYMDzUpl36XktY6Yq8EJYlW9pCMmBVNy/dQ== key = Fixtures.pkey("dsa1024") key2 = key.dup assert_equal key.params, key2.params - key2.set_pqg(key2.p + 1, key2.q, key2.g) - assert_not_equal key.params, key2.params + + # PKey is immutable in OpenSSL >= 3.0 + if !openssl?(3, 0, 0) + key2.set_pqg(key2.p + 1, key2.q, key2.g) + assert_not_equal key.params, key2.params + end end def test_marshal diff --git a/test/openssl/test_pkey_ec.rb b/test/openssl/test_pkey_ec.rb index 3f5958af50..ffe5a94e5b 100644 --- a/test/openssl/test_pkey_ec.rb +++ b/test/openssl/test_pkey_ec.rb @@ -13,21 +13,23 @@ class OpenSSL::TestEC < OpenSSL::PKeyTestCase # FIPS-selftest failure on some environment, so skip for now. next if ["Oakley", "X25519"].any? { |n| curve_name.start_with?(n) } - key = OpenSSL::PKey::EC.new(curve_name) - key.generate_key! - + key = OpenSSL::PKey::EC.generate(curve_name) assert_predicate key, :private? assert_predicate key, :public? assert_nothing_raised { key.check_key } end - key1 = OpenSSL::PKey::EC.new("prime256v1").generate_key! + key1 = OpenSSL::PKey::EC.generate("prime256v1") - key2 = OpenSSL::PKey::EC.new - key2.group = key1.group - key2.private_key = key1.private_key - key2.public_key = key1.public_key - assert_equal key1.to_der, key2.to_der + # PKey is immutable in OpenSSL >= 3.0; constructing an empty EC object is + # deprecated + if !openssl?(3, 0, 0) + key2 = OpenSSL::PKey::EC.new + key2.group = key1.group + key2.private_key = key1.private_key + key2.public_key = key1.public_key + assert_equal key1.to_der, key2.to_der + end key3 = OpenSSL::PKey::EC.new(key1) assert_equal key1.to_der, key3.to_der @@ -37,10 +39,14 @@ class OpenSSL::TestEC < OpenSSL::PKeyTestCase key5 = key1.dup assert_equal key1.to_der, key5.to_der - key_tmp = OpenSSL::PKey::EC.new("prime256v1").generate_key! - key5.private_key = key_tmp.private_key - key5.public_key = key_tmp.public_key - assert_not_equal key1.to_der, key5.to_der + + # PKey is immutable in OpenSSL >= 3.0; EC object should not be modified + if !openssl?(3, 0, 0) + key_tmp = OpenSSL::PKey::EC.generate("prime256v1") + key5.private_key = key_tmp.private_key + key5.public_key = key_tmp.public_key + assert_not_equal key1.to_der, key5.to_der + end end def test_generate @@ -52,6 +58,13 @@ class OpenSSL::TestEC < OpenSSL::PKeyTestCase assert_equal(true, ec.private?) end + def test_generate_key + ec = OpenSSL::PKey::EC.new("prime256v1") + assert_equal false, ec.private? + ec.generate_key! + assert_equal true, ec.private? + end if !openssl?(3, 0, 0) + def test_marshal key = Fixtures.pkey("p256") deserialized = Marshal.load(Marshal.dump(key)) @@ -60,22 +73,26 @@ class OpenSSL::TestEC < OpenSSL::PKeyTestCase end def test_check_key - key = OpenSSL::PKey::EC.new("prime256v1").generate_key! - assert_equal(true, key.check_key) - assert_equal(true, key.private?) - assert_equal(true, key.public?) - key2 = OpenSSL::PKey::EC.new(key.group) - assert_equal(false, key2.private?) - assert_equal(false, key2.public?) - key2.public_key = key.public_key - assert_equal(false, key2.private?) - assert_equal(true, key2.public?) - key2.private_key = key.private_key + key0 = Fixtures.pkey("p256") + assert_equal(true, key0.check_key) + assert_equal(true, key0.private?) + assert_equal(true, key0.public?) + + key1 = OpenSSL::PKey.read(key0.public_to_der) + assert_equal(true, key1.check_key) + assert_equal(false, key1.private?) + assert_equal(true, key1.public?) + + key2 = OpenSSL::PKey.read(key0.private_to_der) assert_equal(true, key2.private?) assert_equal(true, key2.public?) assert_equal(true, key2.check_key) - key2.private_key += 1 - assert_raise(OpenSSL::PKey::ECError) { key2.check_key } + + # EC#private_key= is deprecated in 3.0 and won't work on OpenSSL 3.0 + if !openssl?(3, 0, 0) + key2.private_key += 1 + assert_raise(OpenSSL::PKey::ECError) { key2.check_key } + end end def test_sign_verify @@ -107,7 +124,7 @@ class OpenSSL::TestEC < OpenSSL::PKeyTestCase assert_equal [zIUT].pack("H*"), a.derive(b) assert_equal a.derive(b), a.dh_compute_key(b.public_key) - end + end if !openssl?(3, 0, 0) # TODO: Test it without using #private_key= def test_sign_verify_raw key = Fixtures.pkey("p256") @@ -136,7 +153,7 @@ class OpenSSL::TestEC < OpenSSL::PKeyTestCase end def test_dsa_sign_asn1_FIPS186_3 - key = OpenSSL::PKey::EC.new("prime256v1").generate_key! + key = OpenSSL::PKey::EC.generate("prime256v1") size = key.group.order.num_bits / 8 + 1 dgst = (1..size).to_a.pack('C*') sig = key.dsa_sign_asn1(dgst) @@ -145,8 +162,8 @@ class OpenSSL::TestEC < OpenSSL::PKeyTestCase end def test_dh_compute_key - key_a = OpenSSL::PKey::EC.new("prime256v1").generate_key! - key_b = OpenSSL::PKey::EC.new(key_a.group).generate_key! + key_a = OpenSSL::PKey::EC.generate("prime256v1") + key_b = OpenSSL::PKey::EC.generate(key_a.group) pub_a = key_a.public_key pub_b = key_b.public_key @@ -276,7 +293,7 @@ class OpenSSL::TestEC < OpenSSL::PKeyTestCase def test_ec_point group = OpenSSL::PKey::EC::Group.new("prime256v1") - key = OpenSSL::PKey::EC.new(group).generate_key! + key = OpenSSL::PKey::EC.generate(group) point = key.public_key point2 = OpenSSL::PKey::EC::Point.new(group, point.to_bn) diff --git a/test/openssl/test_pkey_rsa.rb b/test/openssl/test_pkey_rsa.rb index dbe87ba4c1..4bb39ed4a6 100644 --- a/test/openssl/test_pkey_rsa.rb +++ b/test/openssl/test_pkey_rsa.rb @@ -31,15 +31,18 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase assert(!key4.private?) rsa1024 = Fixtures.pkey("rsa1024") - # Generated by RSA#set_key - key5 = OpenSSL::PKey::RSA.new - key5.set_key(rsa1024.n, rsa1024.e, rsa1024.d) - assert(key5.private?) - - # Generated by RSA#set_key, without d - key6 = OpenSSL::PKey::RSA.new - key6.set_key(rsa1024.n, rsa1024.e, nil) - assert(!key6.private?) + if !openssl?(3, 0, 0) + key = OpenSSL::PKey::RSA.new + # Generated by RSA#set_key + key5 = OpenSSL::PKey::RSA.new + key5.set_key(rsa1024.n, rsa1024.e, rsa1024.d) + assert(key5.private?) + + # Generated by RSA#set_key, without d + key6 = OpenSSL::PKey::RSA.new + key6.set_key(rsa1024.n, rsa1024.e, nil) + assert(!key6.private?) + end end def test_new @@ -235,36 +238,52 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase def test_export rsa1024 = Fixtures.pkey("rsa1024") - key = OpenSSL::PKey::RSA.new - # key has only n, e and d - key.set_key(rsa1024.n, rsa1024.e, rsa1024.d) - assert_equal rsa1024.public_key.export, key.export + pub = OpenSSL::PKey.read(rsa1024.public_to_der) + assert_not_equal rsa1024.export, pub.export + assert_equal rsa1024.public_to_pem, pub.export + + # PKey is immutable in OpenSSL >= 3.0 + if !openssl?(3, 0, 0) + key = OpenSSL::PKey::RSA.new + + # key has only n, e and d + key.set_key(rsa1024.n, rsa1024.e, rsa1024.d) + assert_equal rsa1024.public_key.export, key.export - # key has only n, e, d, p and q - key.set_factors(rsa1024.p, rsa1024.q) - assert_equal rsa1024.public_key.export, key.export + # key has only n, e, d, p and q + key.set_factors(rsa1024.p, rsa1024.q) + assert_equal rsa1024.public_key.export, key.export - # key has n, e, d, p, q, dmp1, dmq1 and iqmp - key.set_crt_params(rsa1024.dmp1, rsa1024.dmq1, rsa1024.iqmp) - assert_equal rsa1024.export, key.export + # key has n, e, d, p, q, dmp1, dmq1 and iqmp + key.set_crt_params(rsa1024.dmp1, rsa1024.dmq1, rsa1024.iqmp) + assert_equal rsa1024.export, key.export + end end def test_to_der rsa1024 = Fixtures.pkey("rsa1024") - key = OpenSSL::PKey::RSA.new - # key has only n, e and d - key.set_key(rsa1024.n, rsa1024.e, rsa1024.d) - assert_equal rsa1024.public_key.to_der, key.to_der + pub = OpenSSL::PKey.read(rsa1024.public_to_der) + assert_not_equal rsa1024.to_der, pub.to_der + assert_equal rsa1024.public_to_der, pub.to_der + + # PKey is immutable in OpenSSL >= 3.0 + if !openssl?(3, 0, 0) + key = OpenSSL::PKey::RSA.new - # key has only n, e, d, p and q - key.set_factors(rsa1024.p, rsa1024.q) - assert_equal rsa1024.public_key.to_der, key.to_der + # key has only n, e and d + key.set_key(rsa1024.n, rsa1024.e, rsa1024.d) + assert_equal rsa1024.public_key.to_der, key.to_der - # key has n, e, d, p, q, dmp1, dmq1 and iqmp - key.set_crt_params(rsa1024.dmp1, rsa1024.dmq1, rsa1024.iqmp) - assert_equal rsa1024.to_der, key.to_der + # key has only n, e, d, p and q + key.set_factors(rsa1024.p, rsa1024.q) + assert_equal rsa1024.public_key.to_der, key.to_der + + # key has n, e, d, p, q, dmp1, dmq1 and iqmp + key.set_crt_params(rsa1024.dmp1, rsa1024.dmq1, rsa1024.iqmp) + assert_equal rsa1024.to_der, key.to_der + end end def test_RSAPrivateKey @@ -306,6 +325,12 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase assert_equal asn1.to_der, rsa1024.to_der assert_equal pem, rsa1024.export + + # Unknown PEM prepended + cert = issue_cert(OpenSSL::X509::Name.new([["CN", "nobody"]]), rsa1024, 1, [], nil, nil) + str = cert.to_text + cert.to_pem + rsa1024.to_pem + key = OpenSSL::PKey::RSA.new(str) + assert_same_rsa rsa1024, key end def test_RSAPrivateKey_encrypted @@ -495,8 +520,12 @@ class OpenSSL::TestPKeyRSA < OpenSSL::PKeyTestCase key = Fixtures.pkey("rsa1024") key2 = key.dup assert_equal key.params, key2.params - key2.set_key(key2.n, 3, key2.d) - assert_not_equal key.params, key2.params + + # PKey is immutable in OpenSSL >= 3.0 + if !openssl?(3, 0, 0) + key2.set_key(key2.n, 3, key2.d) + assert_not_equal key.params, key2.params + end end def test_marshal diff --git a/test/openssl/test_ssl.rb b/test/openssl/test_ssl.rb index ef9958aee5..a7607da073 100644 --- a/test/openssl/test_ssl.rb +++ b/test/openssl/test_ssl.rb @@ -893,14 +893,12 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end end - begin - sock = TCPSocket.new("127.0.0.1", port) - sock.puts "abc" - ensure - sock&.close - end + sock = TCPSocket.new("127.0.0.1", port) + sock << "\x00" * 1024 assert t.join + ensure + sock&.close server.close end @@ -1211,46 +1209,51 @@ class OpenSSL::TestSSL < OpenSSL::SSLTestCase end def test_options_disable_versions - # Note: Use of these OP_* flags has been deprecated since OpenSSL 1.1.0. + # It's recommended to use SSLContext#{min,max}_version= instead in real + # applications. The purpose of this test case is to check that SSL options + # are properly propagated to OpenSSL library. supported = check_supported_protocol_versions + if !defined?(OpenSSL::SSL::TLS1_3_VERSION) || + !supported.include?(OpenSSL::SSL::TLS1_2_VERSION) || + !supported.include?(OpenSSL::SSL::TLS1_3_VERSION) || + !defined?(OpenSSL::SSL::OP_NO_TLSv1_3) # LibreSSL < 3.4 + pend "this test case requires both TLS 1.2 and TLS 1.3 to be supported " \ + "and enabled by default" + end - if supported.include?(OpenSSL::SSL::TLS1_1_VERSION) && - supported.include?(OpenSSL::SSL::TLS1_2_VERSION) - # Server disables ~ TLS 1.1 - ctx_proc = proc { |ctx| - ctx.options |= OpenSSL::SSL::OP_NO_SSLv2 | OpenSSL::SSL::OP_NO_SSLv3 | - OpenSSL::SSL::OP_NO_TLSv1 | OpenSSL::SSL::OP_NO_TLSv1_1 - } - start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port| - # Client only supports TLS 1.1 - ctx1 = OpenSSL::SSL::SSLContext.new - ctx1.min_version = ctx1.max_version = OpenSSL::SSL::TLS1_1_VERSION - assert_handshake_error { server_connect(port, ctx1) { } } + # Server disables TLS 1.2 and earlier + ctx_proc = proc { |ctx| + ctx.options |= OpenSSL::SSL::OP_NO_SSLv2 | OpenSSL::SSL::OP_NO_SSLv3 | + OpenSSL::SSL::OP_NO_TLSv1 | OpenSSL::SSL::OP_NO_TLSv1_1 | + OpenSSL::SSL::OP_NO_TLSv1_2 + } + start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port| + # Client only supports TLS 1.2 + ctx1 = OpenSSL::SSL::SSLContext.new + ctx1.min_version = ctx1.max_version = OpenSSL::SSL::TLS1_2_VERSION + assert_handshake_error { server_connect(port, ctx1) { } } - # Client only supports TLS 1.2 - ctx2 = OpenSSL::SSL::SSLContext.new - ctx2.min_version = ctx2.max_version = OpenSSL::SSL::TLS1_2_VERSION - assert_nothing_raised { server_connect(port, ctx2) { } } - } + # Client only supports TLS 1.3 + ctx2 = OpenSSL::SSL::SSLContext.new + ctx2.min_version = ctx2.max_version = OpenSSL::SSL::TLS1_3_VERSION + assert_nothing_raised { server_connect(port, ctx2) { } } + } - # Server only supports TLS 1.1 - ctx_proc = proc { |ctx| - ctx.min_version = ctx.max_version = OpenSSL::SSL::TLS1_1_VERSION - } - start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port| - # Client disables TLS 1.1 - ctx1 = OpenSSL::SSL::SSLContext.new - ctx1.options |= OpenSSL::SSL::OP_NO_TLSv1_1 - assert_handshake_error { server_connect(port, ctx1) { } } + # Server only supports TLS 1.2 + ctx_proc = proc { |ctx| + ctx.min_version = ctx.max_version = OpenSSL::SSL::TLS1_2_VERSION + } + start_server(ctx_proc: ctx_proc, ignore_listener_error: true) { |port| + # Client doesn't support TLS 1.2 + ctx1 = OpenSSL::SSL::SSLContext.new + ctx1.options |= OpenSSL::SSL::OP_NO_TLSv1_2 + assert_handshake_error { server_connect(port, ctx1) { } } - # Client disables TLS 1.2 - ctx2 = OpenSSL::SSL::SSLContext.new - ctx2.options |= OpenSSL::SSL::OP_NO_TLSv1_2 - assert_nothing_raised { server_connect(port, ctx2) { } } - } - else - pend "TLS 1.1 and TLS 1.2 must be supported; skipping" - end + # Client supports TLS 1.2 by default + ctx2 = OpenSSL::SSL::SSLContext.new + ctx2.options |= OpenSSL::SSL::OP_NO_TLSv1_3 + assert_nothing_raised { server_connect(port, ctx2) { } } + } end def test_ssl_methods_constant diff --git a/test/optparse/test_acceptable.rb b/test/optparse/test_acceptable.rb index 12f7886538..12f5322726 100644 --- a/test/optparse/test_acceptable.rb +++ b/test/optparse/test_acceptable.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false require_relative 'test_optparse' -class TestOptionParser::Acceptable < TestOptionParser +class TestOptionParserAcceptable < TestOptionParser def setup super diff --git a/test/optparse/test_autoconf.rb b/test/optparse/test_autoconf.rb index 45f2ba09b2..ec87744633 100644 --- a/test/optparse/test_autoconf.rb +++ b/test/optparse/test_autoconf.rb @@ -2,9 +2,7 @@ require 'test/unit' require 'optparse/ac' -class TestOptionParser < Test::Unit::TestCase; end - -class TestOptionParser::AutoConf < Test::Unit::TestCase +class TestOptionParserAutoConf < Test::Unit::TestCase def setup @opt = OptionParser::AC.new @foo = @bar = self.class diff --git a/test/optparse/test_bash_completion.rb b/test/optparse/test_bash_completion.rb index 513e986f66..60c82f7136 100644 --- a/test/optparse/test_bash_completion.rb +++ b/test/optparse/test_bash_completion.rb @@ -2,9 +2,7 @@ require 'test/unit' require 'optparse' -class TestOptionParser < Test::Unit::TestCase -end -class TestOptionParser::BashCompletion < Test::Unit::TestCase +class TestOptionParserBashCompletion < Test::Unit::TestCase def setup @opt = OptionParser.new @opt.define("-z", "zzz") {} diff --git a/test/optparse/test_cclass.rb b/test/optparse/test_cclass.rb index ac46f46bb2..0ded61f60e 100644 --- a/test/optparse/test_cclass.rb +++ b/test/optparse/test_cclass.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false require_relative 'test_optparse' -class TestOptionParser::CClass < TestOptionParser +class TestOptionParserCClass < TestOptionParser def test_no_argument flags = [] @opt.def_option("-[a-z]") {|x| flags << x} diff --git a/test/optparse/test_did_you_mean.rb b/test/optparse/test_did_you_mean.rb index aa866f4072..3c923922ec 100644 --- a/test/optparse/test_did_you_mean.rb +++ b/test/optparse/test_did_you_mean.rb @@ -6,17 +6,21 @@ rescue LoadError return end -class TestOptionParser::DidYouMean < TestOptionParser +class TestOptionParserDidYouMean < TestOptionParser def setup super @opt.def_option("--foo", Integer) { |v| @foo = v } @opt.def_option("--bar", Integer) { |v| @bar = v } @opt.def_option("--baz", Integer) { |v| @baz = v } @formatter = ::DidYouMean.formatter - case @formatter - when ::DidYouMean::PlainFormatter + if ::DidYouMean.const_defined?(:Formatter) + ::DidYouMean.formatter = ::DidYouMean::Formatter else - ::DidYouMean.formatter = ::DidYouMean::PlainFormatter.new + case @formatter + when ::DidYouMean::PlainFormatter + else + ::DidYouMean.formatter = ::DidYouMean::PlainFormatter.new + end end end diff --git a/test/optparse/test_getopts.rb b/test/optparse/test_getopts.rb index 3711e6f269..7d9160f7af 100644 --- a/test/optparse/test_getopts.rb +++ b/test/optparse/test_getopts.rb @@ -2,9 +2,7 @@ require 'test/unit' require 'optparse' -class TestOptionParser < Test::Unit::TestCase -end -class TestOptionParser::Getopts < Test::Unit::TestCase +class TestOptionParserGetopts < Test::Unit::TestCase def setup @opt = OptionParser.new end diff --git a/test/optparse/test_kwargs.rb b/test/optparse/test_kwargs.rb index 78d7e2ee9c..2e826bfd12 100644 --- a/test/optparse/test_kwargs.rb +++ b/test/optparse/test_kwargs.rb @@ -3,9 +3,7 @@ require 'test/unit' require 'optparse' require 'optparse/kwargs' -class TestOptionParser < Test::Unit::TestCase -end -class TestOptionParser::KwArg < Test::Unit::TestCase +class TestOptionParserKwArg < Test::Unit::TestCase class K def initialize(host:, port: 8080) @host = host diff --git a/test/optparse/test_noarg.rb b/test/optparse/test_noarg.rb index 8f20519408..a53399afc2 100644 --- a/test/optparse/test_noarg.rb +++ b/test/optparse/test_noarg.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false require_relative 'test_optparse' -module TestOptionParser::NoArg +module TestOptionParserNoArg def setup super @opt.def_option "--with_underscore" do |x| @flag = x end @@ -9,7 +9,7 @@ module TestOptionParser::NoArg end class Def1 < TestOptionParser - include NoArg + include TestOptionParserNoArg def setup super @opt.def_option("-x") {|x| @flag = x} @@ -17,7 +17,7 @@ module TestOptionParser::NoArg end end class Def2 < TestOptionParser - include NoArg + include TestOptionParserNoArg def setup super @opt.def_option("-x", "--option") {|x| @flag = x} diff --git a/test/optparse/test_optarg.rb b/test/optparse/test_optarg.rb index 14584f7e89..81127a8a37 100644 --- a/test/optparse/test_optarg.rb +++ b/test/optparse/test_optarg.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false require_relative 'test_optparse' -class TestOptionParser::OptArg < TestOptionParser +class TestOptionParserOptArg < TestOptionParser def setup super @opt.def_option("-x[VAL]") {|x| @flag = x} diff --git a/test/optparse/test_placearg.rb b/test/optparse/test_placearg.rb index 8acfdb2161..94cfb0e819 100644 --- a/test/optparse/test_placearg.rb +++ b/test/optparse/test_placearg.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false require_relative 'test_optparse' -class TestOptionParser::PlaceArg < TestOptionParser +class TestOptionParserPlaceArg < TestOptionParser def setup super @opt.def_option("-x [VAL]") {|x| @flag = x} diff --git a/test/optparse/test_reqarg.rb b/test/optparse/test_reqarg.rb index b2e4755f80..d5686d13aa 100644 --- a/test/optparse/test_reqarg.rb +++ b/test/optparse/test_reqarg.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false require_relative 'test_optparse' -module TestOptionParser::ReqArg +module TestOptionParserReqArg def setup super @opt.def_option "--with_underscore=VAL" do |x| @flag = x end @@ -9,7 +9,7 @@ module TestOptionParser::ReqArg end class Def1 < TestOptionParser - include ReqArg + include TestOptionParserReqArg def setup super @opt.def_option("-xVAL") {|x| @flag = x} @@ -19,21 +19,21 @@ module TestOptionParser::ReqArg end end class Def2 < TestOptionParser - include ReqArg + include TestOptionParserReqArg def setup super @opt.def_option("-x", "--option=VAL") {|x| @flag = x} end end class Def3 < TestOptionParser - include ReqArg + include TestOptionParserReqArg def setup super @opt.def_option("--option=VAL", "-x") {|x| @flag = x} end end class Def4 < TestOptionParser - include ReqArg + include TestOptionParserReqArg def setup super @opt.def_option("-xVAL", "--option=VAL") {|x| @flag = x} diff --git a/test/optparse/test_summary.rb b/test/optparse/test_summary.rb index 67b05672d4..6b36ce3c76 100644 --- a/test/optparse/test_summary.rb +++ b/test/optparse/test_summary.rb @@ -1,7 +1,7 @@ # frozen_string_literal: false require_relative 'test_optparse' -class TestOptionParser::SummaryTest < TestOptionParser +class TestOptionParserSummaryTest < TestOptionParser def test_short_clash r = nil o = OptionParser.new do |opts| diff --git a/test/optparse/test_zsh_completion.rb b/test/optparse/test_zsh_completion.rb index c548d4af8a..76f0a73f32 100644 --- a/test/optparse/test_zsh_completion.rb +++ b/test/optparse/test_zsh_completion.rb @@ -2,9 +2,7 @@ require 'test/unit' require 'optparse' -class TestOptionParser < Test::Unit::TestCase -end -class TestOptionParser::ZshCompletion < Test::Unit::TestCase +class TestOptionParserZshCompletion < Test::Unit::TestCase def setup @opt = OptionParser.new @opt.define("-z", "zzz") {} diff --git a/test/ostruct/test_ostruct.rb b/test/ostruct/test_ostruct.rb index 4ec4d43084..256db7a0c7 100644 --- a/test/ostruct/test_ostruct.rb +++ b/test/ostruct/test_ostruct.rb @@ -280,6 +280,7 @@ class TC_OpenStruct < Test::Unit::TestCase os = OpenStruct.new(method: :foo, hash: 42) assert_equal(os.object_id, os.method!(:object_id).call) assert_not_equal(42, os.hash!) + refute os.methods.include?(:"!~!") end def test_override_subclass @@ -405,4 +406,10 @@ class TC_OpenStruct < Test::Unit::TestCase o2 = Marshal.load(Marshal.dump(o)) assert_equal o, o2 end + + def test_class + os = OpenStruct.new(class: 'my-class', method: 'post') + assert_equal('my-class', os.class) + assert_equal(OpenStruct, os.class!) + end end diff --git a/test/pathname/test_pathname.rb b/test/pathname/test_pathname.rb index 9e14668c99..a23dc21ae3 100644 --- a/test/pathname/test_pathname.rb +++ b/test/pathname/test_pathname.rb @@ -1043,6 +1043,25 @@ class TestPathname < Test::Unit::TestCase } end + def test_lutime + return if !has_symlink? + with_tmpchdir('rubytest-pathname') {|dir| + open("a", "w") {|f| f.write "abc" } + atime = File.atime("a") + mtime = File.mtime("a") + latime = Time.utc(2000) + lmtime = Time.utc(1999) + File.symlink("a", "l") + Pathname("l").utime(latime, lmtime) + s = File.lstat("a") + ls = File.lstat("l") + assert_equal(atime, s.atime) + assert_equal(mtime, s.mtime) + assert_equal(latime, ls.atime) + assert_equal(lmtime, ls.mtime) + } + end + def test_basename assert_equal(Pathname("basename"), Pathname("dirname/basename").basename) assert_equal(Pathname("bar"), Pathname("foo/bar.x").basename(".x")) @@ -1355,6 +1374,18 @@ class TestPathname < Test::Unit::TestCase } end + def test_each_entry_enumerator + with_tmpchdir('rubytest-pathname') {|dir| + open("a", "w") {} + open("b", "w") {} + a = [] + e = Pathname(".").each_entry + assert_kind_of(Enumerator, e) + e.each {|v| a << v } + assert_equal([Pathname("."), Pathname(".."), Pathname("a"), Pathname("b")], a.sort) + } + end + def test_mkdir with_tmpchdir('rubytest-pathname') {|dir| Pathname("d").mkdir diff --git a/test/psych/test_numeric.rb b/test/psych/test_numeric.rb index 8c3dcd173c..9c75c016cd 100644 --- a/test/psych/test_numeric.rb +++ b/test/psych/test_numeric.rb @@ -43,5 +43,16 @@ module Psych str = Psych.load('--- 1.1.1') assert_equal '1.1.1', str end + + # This behavior is not to YML spec, but is kept for backwards compatibility + def test_string_with_commas + number = Psych.load('--- 12,34,56') + assert_equal 123456, number + end + + def test_string_with_commas_with_strict_integer + str = Psych.load('--- 12,34,56', strict_integer: true) + assert_equal '12,34,56', str + end end end diff --git a/test/psych/test_scalar_scanner.rb b/test/psych/test_scalar_scanner.rb index ebc9fbdcd2..145db58fd9 100644 --- a/test/psych/test_scalar_scanner.rb +++ b/test/psych/test_scalar_scanner.rb @@ -149,6 +149,31 @@ module Psych assert_equal 0x123456789abcdef, ss.tokenize('0x12_,34,_56,_789abcdef__') end + def test_scan_strict_int_commas_and_underscores + # this test is to ensure adherance to YML spec using the 'strict_integer' option + scanner = Psych::ScalarScanner.new ClassLoader.new, strict_integer: true + assert_equal 123_456_789, scanner.tokenize('123_456_789') + assert_equal '123,456,789', scanner.tokenize('123,456,789') + assert_equal '1_2,3,4_5,6_789', scanner.tokenize('1_2,3,4_5,6_789') + + assert_equal 1, scanner.tokenize('1') + assert_equal 1, scanner.tokenize('+1') + assert_equal(-1, scanner.tokenize('-1')) + + assert_equal 0b010101010, scanner.tokenize('0b010101010') + assert_equal 0b010101010, scanner.tokenize('0b01_01_01_010') + assert_equal '0b0,1_0,1_,0,1_01,0', scanner.tokenize('0b0,1_0,1_,0,1_01,0') + + assert_equal 01234567, scanner.tokenize('01234567') + assert_equal '0_,,,1_2,_34567', scanner.tokenize('0_,,,1_2,_34567') + + assert_equal 0x123456789abcdef, scanner.tokenize('0x123456789abcdef') + assert_equal 0x123456789abcdef, scanner.tokenize('0x12_34_56_789abcdef') + assert_equal '0x12_,34,_56,_789abcdef', scanner.tokenize('0x12_,34,_56,_789abcdef') + assert_equal '0x_12_,34,_56,_789abcdef', scanner.tokenize('0x_12_,34,_56,_789abcdef') + assert_equal '0x12_,34,_56,_789abcdef__', scanner.tokenize('0x12_,34,_56,_789abcdef__') + end + def test_scan_dot assert_equal '.', ss.tokenize('.') end diff --git a/test/racc/case.rb b/test/racc/case.rb index f4240bfd21..d917f3a4e4 100644 --- a/test/racc/case.rb +++ b/test/racc/case.rb @@ -90,8 +90,7 @@ module Racc actual = File.read("#{@TAB_DIR}/#{file}") result = (strip_version(expected) == strip_version(actual)) - assert(result, "Output of test/assets/#{file}.y differed from " \ - "expectation. Try compiling it and diff with test/regress/#{file}.") + assert(result, proc {`diff -u #{REGRESS_DIR}/#{file} #{@TAB_DIR}/#{file}`}) end def racc(*arg, **opt) diff --git a/test/rdoc/helper.rb b/test/rdoc/helper.rb index 2ba26c296b..7985433060 100644 --- a/test/rdoc/helper.rb +++ b/test/rdoc/helper.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true -require_relative './support/test_case' -require_relative './support/formatter_test_case' -require_relative './support/text_formatter_test_case' +require_relative 'support/test_case' +require_relative 'support/formatter_test_case' +require_relative 'support/text_formatter_test_case' diff --git a/test/rdoc/support/test_case.rb b/test/rdoc/support/test_case.rb index 7617fc8471..36009111e2 100644 --- a/test/rdoc/support/test_case.rb +++ b/test/rdoc/support/test_case.rb @@ -13,7 +13,7 @@ require 'tempfile' require 'tmpdir' require 'stringio' -require 'rdoc' +require_relative '../../../lib/rdoc' ## # RDoc::TestCase is an abstract TestCase to provide common setup and teardown diff --git a/test/rdoc/test_rdoc_alias.rb b/test/rdoc/test_rdoc_alias.rb index 89ae2d5a56..3c096a49b4 100644 --- a/test/rdoc/test_rdoc_alias.rb +++ b/test/rdoc/test_rdoc_alias.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true -require File.expand_path '../xref_test_case', __FILE__ +require_relative 'xref_test_case' class TestRDocAlias < XrefTestCase @@ -11,4 +11,3 @@ class TestRDocAlias < XrefTestCase end end - diff --git a/test/rdoc/test_rdoc_any_method.rb b/test/rdoc/test_rdoc_any_method.rb index caff86b059..826ef1c8d8 100644 --- a/test/rdoc/test_rdoc_any_method.rb +++ b/test/rdoc/test_rdoc_any_method.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true -require File.expand_path '../xref_test_case', __FILE__ +require_relative 'xref_test_case' class TestRDocAnyMethod < XrefTestCase diff --git a/test/rdoc/test_rdoc_class_module.rb b/test/rdoc/test_rdoc_class_module.rb index ad185671cf..27d37cb7dd 100644 --- a/test/rdoc/test_rdoc_class_module.rb +++ b/test/rdoc/test_rdoc_class_module.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true -require File.expand_path '../xref_test_case', __FILE__ +require_relative 'xref_test_case' class TestRDocClassModule < XrefTestCase @@ -63,7 +63,7 @@ class TestRDocClassModule < XrefTestCase end def test_ancestors - assert_equal [@parent, "Object"], @child.ancestors + assert_equal [@parent, @object, "BasicObject"], @child.ancestors end def test_comment_equals @@ -129,7 +129,7 @@ class TestRDocClassModule < XrefTestCase end def test_each_ancestor - assert_equal [@parent], @child.each_ancestor.to_a + assert_equal [@parent, @object], @child.each_ancestor.to_a end def test_each_ancestor_cycle @@ -1501,4 +1501,3 @@ class TestRDocClassModule < XrefTestCase end end - diff --git a/test/rdoc/test_rdoc_code_object.rb b/test/rdoc/test_rdoc_code_object.rb index fad182722a..24e228cce1 100644 --- a/test/rdoc/test_rdoc_code_object.rb +++ b/test/rdoc/test_rdoc_code_object.rb @@ -1,7 +1,7 @@ # coding: US-ASCII # frozen_string_literal: true -require File.expand_path '../xref_test_case', __FILE__ +require_relative 'xref_test_case' class TestRDocCodeObject < XrefTestCase diff --git a/test/rdoc/test_rdoc_constant.rb b/test/rdoc/test_rdoc_constant.rb index 79dcdad57e..32ffe3f84d 100644 --- a/test/rdoc/test_rdoc_constant.rb +++ b/test/rdoc/test_rdoc_constant.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true -require File.expand_path '../xref_test_case', __FILE__ +require_relative 'xref_test_case' class TestRDocConstant < XrefTestCase diff --git a/test/rdoc/test_rdoc_context.rb b/test/rdoc/test_rdoc_context.rb index ecdb3cbd67..85665599fb 100644 --- a/test/rdoc/test_rdoc_context.rb +++ b/test/rdoc/test_rdoc_context.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true -require File.expand_path '../xref_test_case', __FILE__ +require_relative 'xref_test_case' class TestRDocContext < XrefTestCase @@ -125,7 +125,7 @@ class TestRDocContext < XrefTestCase basic = @c1.find_module_named 'BasicObject' - assert_equal 'Object', basic.superclass + assert_equal @object, basic.superclass end def test_add_class_object diff --git a/test/rdoc/test_rdoc_cross_reference.rb b/test/rdoc/test_rdoc_cross_reference.rb index 94ddc1e1e4..cbda77a798 100644 --- a/test/rdoc/test_rdoc_cross_reference.rb +++ b/test/rdoc/test_rdoc_cross_reference.rb @@ -1,7 +1,10 @@ # frozen_string_literal: true -require File.expand_path '../xref_test_case', __FILE__ +require_relative 'xref_test_case' class TestRDocCrossReference < XrefTestCase + EXAMPLE_METHODS = %w'== === != =~ !~ < > <= >= <=> [] []= << >> + -@ +@ ! - + * / % ** !@ ` | & ^ ~ __id__ + ' def setup super @@ -18,9 +21,9 @@ class TestRDocCrossReference < XrefTestCase end def test_METHOD_REGEXP_STR - re = /#{RDoc::CrossReference::METHOD_REGEXP_STR}/ + re = /\A(?:#{RDoc::CrossReference::METHOD_REGEXP_STR})\z/ - %w'== === [] []= << >>'.each do |x| + EXAMPLE_METHODS.each do |x| re =~ x assert_equal x, $& end @@ -88,6 +91,15 @@ class TestRDocCrossReference < XrefTestCase assert_ref @c4_c4, 'C4' end + def test_resolve_class_and_method_of_the_same_name + assert_ref @c10_class, 'C10' + assert_ref @c10_method, '#C10' + assert_ref @c11_class, 'C11' + assert_ref @c11_method, '#C11' + assert_ref @c10_c11_class, 'C10::C11' + assert_ref @c10_c11_method, 'C10#C11' + end + def test_resolve_class assert_ref @c1, 'C1' refute_ref 'H1' @@ -154,34 +166,35 @@ class TestRDocCrossReference < XrefTestCase assert_ref @c9_a_c_bar, 'C9::B.bar' end - def test_resolve_method_equals3 - m = RDoc::AnyMethod.new '', '===' - @c1.add_method m - - assert_ref m, '===' - end - def test_resolve_page page = @store.add_file 'README.txt', parser: RDoc::Parser::Simple assert_ref page, 'README' end - def test_resolve_percent - i_percent = RDoc::AnyMethod.new nil, '%' - i_percent.singleton = false - @c1.add_method i_percent + def assert_resolve_method(x) + @c1.methods_hash.clear - c_percent = RDoc::AnyMethod.new nil, '%' - c_percent.singleton = true - @c1.add_method c_percent + i_op = RDoc::AnyMethod.new nil, x + i_op.singleton = false + @c1.add_method i_op - assert_ref i_percent, '%' - assert_ref i_percent, '#%' - assert_ref c_percent, '::%' + c_op = RDoc::AnyMethod.new nil, x + c_op.singleton = true + @c1.add_method c_op - assert_ref i_percent, 'C1#%' - assert_ref c_percent, 'C1::%' + assert_ref i_op, x + assert_ref i_op, "##{x}" + assert_ref c_op, "::#{x}" + + assert_ref i_op, "C1##{x}" + assert_ref c_op, "C1::#{x}" + end + + EXAMPLE_METHODS.each do |x| + define_method("test_resolve_method:#{x}") do + assert_resolve_method(x) + end end def test_resolve_no_ref @@ -204,4 +217,3 @@ class TestRDocCrossReference < XrefTestCase end end - diff --git a/test/rdoc/test_rdoc_extend.rb b/test/rdoc/test_rdoc_extend.rb index f4c8425864..cc5038cc51 100644 --- a/test/rdoc/test_rdoc_extend.rb +++ b/test/rdoc/test_rdoc_extend.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true -require File.expand_path '../xref_test_case', __FILE__ +require_relative 'xref_test_case' class TestRDocExtend < XrefTestCase @@ -43,7 +43,7 @@ class TestRDocExtend < XrefTestCase m1_m2_k0.add_extend e0_m3 assert_equal [e0_m4, e0_m5, e0_m6, e0_m1, e0_m2, e0_m3], m1_m2_k0.extends - assert_equal ['Object'], m1_m2_k0.ancestors + assert_equal [@object, 'BasicObject'], m1_m2_k0.ancestors m1_k1 = m1.add_class RDoc::NormalClass, 'Klass1' @@ -60,7 +60,7 @@ class TestRDocExtend < XrefTestCase m1_k1.add_extend e1_k0_m4 assert_equal [e1_m1, e1_m2, e1_m3, e1_m4, e1_k0_m4], m1_k1.extends - assert_equal ['Object'], m1_k1.ancestors + assert_equal [@object, 'BasicObject'], m1_k1.ancestors m1_k2 = m1.add_class RDoc::NormalClass, 'Klass2' @@ -75,7 +75,7 @@ class TestRDocExtend < XrefTestCase m1_k2.add_extend e2_k0_m4 assert_equal [e2_m1, e2_m3, e2_m2, e2_k0_m4], m1_k2.extends - assert_equal ['Object'], m1_k2.ancestors + assert_equal [@object, 'BasicObject'], m1_k2.ancestors m1_k3 = m1.add_class RDoc::NormalClass, 'Klass3' @@ -88,8 +88,7 @@ class TestRDocExtend < XrefTestCase m1_k3.add_extend e3_m4 assert_equal [e3_m1, e3_m2, e3_m4], m1_k3.extends - assert_equal ['Object'], m1_k3.ancestors + assert_equal [@object, 'BasicObject'], m1_k3.ancestors end end - diff --git a/test/rdoc/test_rdoc_generator_darkfish.rb b/test/rdoc/test_rdoc_generator_darkfish.rb index b78a3fb45f..ae3a4c5ebf 100644 --- a/test/rdoc/test_rdoc_generator_darkfish.rb +++ b/test/rdoc/test_rdoc_generator_darkfish.rb @@ -72,11 +72,14 @@ class TestRDocGeneratorDarkfish < RDoc::TestCase def test_generate top_level = @store.add_file 'file.rb' top_level.add_class @klass.class, @klass.name + @klass.add_class RDoc::NormalClass, 'Inner' @g.generate assert_file 'index.html' assert_file 'Object.html' + assert_file 'Klass.html' + assert_file 'Klass/Inner.html' assert_file 'table_of_contents.html' assert_file 'js/search_index.js' @@ -92,6 +95,25 @@ class TestRDocGeneratorDarkfish < RDoc::TestCase assert_match %r%<meta charset="#{encoding}">%, File.read('Object.html') refute_match(/Ignored/, File.read('index.html')) + summary = File.read('index.html')[%r[<summary.*Klass\.html.*</summary>.*</details>]m] + assert_match(%r[Klass/Inner\.html".*>Inner<], summary) + end + + def test_generate_page + @store.add_file 'outer.rdoc', parser: RDoc::Parser::Simple + @store.add_file 'outer/inner.rdoc', parser: RDoc::Parser::Simple + @g.generate + assert_file 'outer_rdoc.html' + assert_file 'outer/inner_rdoc.html' + index = File.read('index.html') + re = %r[<summary><a href="\./outer_rdoc\.html">outer</a></summary>.*?</details>]m + assert_match(re, index) + summary = index[re] + assert_match %r[<a href="\./outer/inner_rdoc.html">inner</a>], summary + re = %r[<details open><summary><a href="\./outer_rdoc\.html">outer</a></summary>.*?</details>]m + assert_match(re, File.read('outer_rdoc.html')) + re = %r[<details open><summary><a href="\.\./outer_rdoc\.html">outer</a></summary>.*?</details>]m + assert_match(re, File.read('outer/inner_rdoc.html')) end def test_generate_dry_run diff --git a/test/rdoc/test_rdoc_include.rb b/test/rdoc/test_rdoc_include.rb index 67d3dfd88e..380464f6cc 100644 --- a/test/rdoc/test_rdoc_include.rb +++ b/test/rdoc/test_rdoc_include.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true -require File.expand_path '../xref_test_case', __FILE__ +require_relative 'xref_test_case' class TestRDocInclude < XrefTestCase @@ -46,7 +46,7 @@ class TestRDocInclude < XrefTestCase assert_equal [i0_m4, i0_m5, i0_m6, i0_m1, i0_m2, i0_m3], m1_m2_k0.includes assert_equal [m1_m2_m3, m1_m2, m1, m1_m2_k0_m4_m6, m1_m2_k0_m5, - m1_m2_k0_m4, 'Object'], m1_m2_k0.ancestors + m1_m2_k0_m4, @object, 'BasicObject'], m1_m2_k0.ancestors m1_k1 = m1.add_class RDoc::NormalClass, 'Klass1' @@ -63,8 +63,8 @@ class TestRDocInclude < XrefTestCase m1_k1.add_include i1_k0_m4 assert_equal [i1_m1, i1_m2, i1_m3, i1_m4, i1_k0_m4], m1_k1.includes - assert_equal [m1_m2_k0_m4, m1_m2_m3_m4, m1_m2_m3, m1_m2, m1, 'Object'], - m1_k1.ancestors + assert_equal [m1_m2_k0_m4, m1_m2_m3_m4, m1_m2_m3, m1_m2, m1, @object, + 'BasicObject'], m1_k1.ancestors m1_k2 = m1.add_class RDoc::NormalClass, 'Klass2' @@ -79,7 +79,8 @@ class TestRDocInclude < XrefTestCase m1_k2.add_include i2_k0_m4 assert_equal [i2_m1, i2_m3, i2_m2, i2_k0_m4], m1_k2.includes - assert_equal [m1_m2_k0_m4, m1_m2, m1_m3, m1, 'Object'], m1_k2.ancestors + assert_equal [m1_m2_k0_m4, m1_m2, m1_m3, m1, @object, 'BasicObject'], + m1_k2.ancestors m1_k3 = m1.add_class RDoc::NormalClass, 'Klass3' @@ -92,7 +93,7 @@ class TestRDocInclude < XrefTestCase m1_k3.add_include i3_m4 assert_equal [i3_m1, i3_m2, i3_m4], m1_k3.includes - assert_equal [m1_m2_m4, m1_m2, m1, 'Object'], m1_k3.ancestors + assert_equal [m1_m2_m4, m1_m2, m1, @object, 'BasicObject'], m1_k3.ancestors end def test_store_equals @@ -106,4 +107,3 @@ class TestRDocInclude < XrefTestCase end end - diff --git a/test/rdoc/test_rdoc_markdown.rb b/test/rdoc/test_rdoc_markdown.rb index ad53e9473c..c223c44c12 100644 --- a/test/rdoc/test_rdoc_markdown.rb +++ b/test/rdoc/test_rdoc_markdown.rb @@ -2,8 +2,8 @@ # frozen_string_literal: true require_relative 'helper' -require 'rdoc/markup/block_quote' -require 'rdoc/markdown' +require_relative '../../lib/rdoc/markup/block_quote' +require_relative '../../lib/rdoc/markdown' class TestRDocMarkdown < RDoc::TestCase @@ -1068,4 +1068,3 @@ and an extra note.[^2] end end - diff --git a/test/rdoc/test_rdoc_markdown_test.rb b/test/rdoc/test_rdoc_markdown_test.rb index 0ecd000136..d4f894c924 100644 --- a/test/rdoc/test_rdoc_markdown_test.rb +++ b/test/rdoc/test_rdoc_markdown_test.rb @@ -2,8 +2,8 @@ require_relative 'helper' require 'pp' -require 'rdoc' -require 'rdoc/markdown' +require_relative '../../lib/rdoc' +require_relative '../../lib/rdoc/markdown' class TestRDocMarkdownTest < RDoc::TestCase diff --git a/test/rdoc/test_rdoc_markup_attribute_manager.rb b/test/rdoc/test_rdoc_markup_attribute_manager.rb index 944364ba89..e8ff602f96 100644 --- a/test/rdoc/test_rdoc_markup_attribute_manager.rb +++ b/test/rdoc/test_rdoc_markup_attribute_manager.rb @@ -145,6 +145,8 @@ class TestRDocMarkupAttributeManager < RDoc::TestCase assert_equal(["cat and ", @em_on, "5", @em_off, " dogs"], @am.flow("cat and _5_ dogs")) + + assert_equal([@tt_on, "__id__", @tt_off], @am.flow("+__id__+")) end def test_bold diff --git a/test/rdoc/test_rdoc_markup_to_html.rb b/test/rdoc/test_rdoc_markup_to_html.rb index b2b21de806..e5d7a35710 100644 --- a/test/rdoc/test_rdoc_markup_to_html.rb +++ b/test/rdoc/test_rdoc_markup_to_html.rb @@ -707,6 +707,7 @@ EXPECTED def test_convert_with_exclude_tag assert_equal "\n<p><code>aaa</code>[:symbol]</p>\n", @to.convert('+aaa+[:symbol]') assert_equal "\n<p><code>aaa[:symbol]</code></p>\n", @to.convert('+aaa[:symbol]+') + assert_equal "\n<p><code>https:</code>-foobar</p>\n", @to.convert('<tt>https:</tt>-foobar') assert_equal "\n<p><a href=\":symbol\">aaa</a></p>\n", @to.convert('aaa[:symbol]') end diff --git a/test/rdoc/test_rdoc_markup_to_html_crossref.rb b/test/rdoc/test_rdoc_markup_to_html_crossref.rb index f6fabfb7db..4b87dd5da5 100644 --- a/test/rdoc/test_rdoc_markup_to_html_crossref.rb +++ b/test/rdoc/test_rdoc_markup_to_html_crossref.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true -require File.expand_path '../xref_test_case', __FILE__ +require_relative 'xref_test_case' class TestRDocMarkupToHtmlCrossref < XrefTestCase @@ -17,6 +17,12 @@ class TestRDocMarkupToHtmlCrossref < XrefTestCase assert_equal para("<a href=\"C1.html\"><code>C1</code></a>"), result end + def test_convert_CROSSREF_method + result = @to.convert 'C1#m(foo, bar, baz)' + + assert_equal para("<a href=\"C1.html#method-i-m\"><code>C1#m(foo, bar, baz)</code></a>"), result + end + def test_convert_CROSSREF_label result = @to.convert 'C1@foo' assert_equal para("<a href=\"C1.html#class-C1-label-foo\">foo at <code>C1</code></a>"), result @@ -260,4 +266,3 @@ class TestRDocMarkupToHtmlCrossref < XrefTestCase end end - diff --git a/test/rdoc/test_rdoc_method_attr.rb b/test/rdoc/test_rdoc_method_attr.rb index 68a9d6cc21..d607619a60 100644 --- a/test/rdoc/test_rdoc_method_attr.rb +++ b/test/rdoc/test_rdoc_method_attr.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true -require File.expand_path '../xref_test_case', __FILE__ +require_relative 'xref_test_case' class TestRDocMethodAttr < XrefTestCase @@ -191,4 +191,3 @@ class TestRDocMethodAttr < XrefTestCase end end - diff --git a/test/rdoc/test_rdoc_normal_class.rb b/test/rdoc/test_rdoc_normal_class.rb index 874eaaa88c..3d097ebb52 100644 --- a/test/rdoc/test_rdoc_normal_class.rb +++ b/test/rdoc/test_rdoc_normal_class.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true -require File.expand_path '../xref_test_case', __FILE__ +require_relative 'xref_test_case' class TestRDocNormalClass < XrefTestCase @@ -11,7 +11,7 @@ class TestRDocNormalClass < XrefTestCase sub_klass.superclass = klass sub_klass.add_include incl - assert_equal [incl.name, klass, 'Object'], sub_klass.ancestors + assert_equal [incl.name, klass, @object, 'BasicObject'], sub_klass.ancestors end def test_ancestors_multilevel @@ -19,7 +19,7 @@ class TestRDocNormalClass < XrefTestCase c2 = @top_level.add_class RDoc::NormalClass, 'Middle', c1.full_name c3 = @top_level.add_class RDoc::NormalClass, 'Inner', c2.full_name - assert_equal [c2, c1, 'Object'], c3.ancestors + assert_equal [c2, c1, @object, 'BasicObject'], c3.ancestors end def test_aref @@ -45,4 +45,3 @@ class TestRDocNormalClass < XrefTestCase end end - diff --git a/test/rdoc/test_rdoc_normal_module.rb b/test/rdoc/test_rdoc_normal_module.rb index 68e776c41f..cccee5c44c 100644 --- a/test/rdoc/test_rdoc_normal_module.rb +++ b/test/rdoc/test_rdoc_normal_module.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true -require File.expand_path '../xref_test_case', __FILE__ +require_relative 'xref_test_case' class TestRDocNormalModule < XrefTestCase @@ -40,4 +40,3 @@ class TestRDocNormalModule < XrefTestCase end end - diff --git a/test/rdoc/test_rdoc_options.rb b/test/rdoc/test_rdoc_options.rb index 7c264c5e86..009dcdd998 100644 --- a/test/rdoc/test_rdoc_options.rb +++ b/test/rdoc/test_rdoc_options.rb @@ -55,11 +55,10 @@ class TestRDocOptions < RDoc::TestCase refute @options.dry_run end - def test_encode_with - coder = {} - class << coder; alias add []=; end + def test_to_yaml + RDoc.load_yaml - @options.encode_with coder + coder = YAML.load(@options.to_yaml) encoding = 'UTF-8' @@ -89,10 +88,11 @@ class TestRDocOptions < RDoc::TestCase assert_equal expected, coder end - def test_encode_with_trim_paths + def test_to_yaml_trim_paths + RDoc.load_yaml + subdir = nil - coder = {} - class << coder; alias add []=; end + coder = nil temp_dir do |dir| FileUtils.mkdir 'project' @@ -113,7 +113,7 @@ class TestRDocOptions < RDoc::TestCase --include / ] - @options.encode_with coder + coder = YAML.load(@options.to_yaml) end end @@ -145,7 +145,9 @@ class TestRDocOptions < RDoc::TestCase @options.encoding = Encoding::IBM437 - options = YAML.safe_load(YAML.dump(@options), permitted_classes: [RDoc::Options, Symbol]) + options = @options.to_yaml + options = YAML.safe_load(options, permitted_classes: [Symbol]) + options = RDoc::Options.new(options) assert_equal Encoding::IBM437, options.encoding end @@ -154,14 +156,15 @@ class TestRDocOptions < RDoc::TestCase RDoc.load_yaml yaml = <<-YAML ---- !ruby/object:RDoc::Options +--- static_path: - /etc rdoc_include: - /etc YAML - options = YAML.safe_load(yaml, permitted_classes: [RDoc::Options, Symbol]) + options = YAML.safe_load(yaml, permitted_classes: [Symbol]) + options = RDoc::Options.new(options) assert_empty options.rdoc_include assert_empty options.static_path @@ -243,6 +246,7 @@ rdoc_include: def test_parse_default @options.parse [] + @options.finish assert_equal RDoc::Generator::Darkfish, @options.generator assert_equal 'darkfish', @options.template @@ -502,6 +506,7 @@ rdoc_include: out, err = capture_output do @options.parse %W[--page-dir #{Dir.tmpdir}] + @options.finish end assert_empty out @@ -530,6 +535,7 @@ rdoc_include: out, err = capture_output do @options.parse %W[--page-dir #{abs_page_dir} --root #{abs_root}] + @options.finish end assert_empty out @@ -558,6 +564,8 @@ rdoc_include: assert_empty err assert_equal Pathname(Dir.tmpdir), @options.root + + @options.finish assert_includes @options.rdoc_include, @options.root.to_s end @@ -602,6 +610,7 @@ rdoc_include: assert_empty out assert_equal "could not find template NONEXISTENT\n", err + @options.finish assert_equal 'darkfish', @options.template assert_match %r%rdoc/generator/template/darkfish$%, @options.template_dir end @@ -668,6 +677,7 @@ rdoc_include: Dir.chdir tmpdir do e = assert_raise SystemExit do @options.parse %w[--write-options] + @options.finish end assert_equal 0, e.status @@ -764,7 +774,9 @@ rdoc_include: assert File.exist? '.rdoc_options' - assert_equal @options, YAML.safe_load(File.read('.rdoc_options'), permitted_classes: [RDoc::Options, Symbol]) + options = File.read('.rdoc_options') + options = YAML.safe_load(options, permitted_classes: [Symbol]) + assert_equal @options, RDoc::Options.new(options) end end @@ -834,20 +846,34 @@ rdoc_include: def test_load_options_partial_override temp_dir do File.open '.rdoc_options', 'w' do |io| - io.write "markup: Markdown" + io.puts "markup: Markdown" + io.puts "encoding: iso-8859-1" + io.puts "static_path: [static]" + io.puts "rdoc_include: [.]" + io.puts "page_dir: pages" end options = RDoc::Options.load_options assert_equal 'Markdown', options.markup + assert_equal Encoding::ISO_8859_1, options.encoding + assert_equal ["static"], options.static_path + assert_equal ["."], options.rdoc_include + assert_equal "pages", options.page_dir end end - def load_options_no_file + def test_load_options_no_file temp_dir do options = RDoc::Options.load_options assert_kind_of RDoc::Options, options end end + + class DummyCoder < Hash + alias add :[]= + def tag=(tag) + end + end end diff --git a/test/rdoc/test_rdoc_parser_c.rb b/test/rdoc/test_rdoc_parser_c.rb index 8f51f32f26..d3138d23aa 100644 --- a/test/rdoc/test_rdoc_parser_c.rb +++ b/test/rdoc/test_rdoc_parser_c.rb @@ -355,6 +355,35 @@ VALUE cFoo = rb_define_class("Foo", rb_cObject); /* Document-class: Foo * this is the Foo class */ +VALUE cFoo = rb_struct_define( + "Foo", + "some", "various", "fields", NULL); + EOF + + klass = util_get_class content, 'cFoo' + assert_equal "this is the Foo class", klass.comment.text + end + + def test_do_classes_struct_under + content = <<-EOF +/* Document-class: Kernel::Foo + * this is the Foo class under Kernel + */ +VALUE cFoo = rb_struct_define_under( + rb_mKernel, "Foo", + "some", "various", "fields", NULL); + EOF + + klass = util_get_class content, 'cFoo' + assert_equal 'Kernel::Foo', klass.full_name + assert_equal "this is the Foo class under Kernel", klass.comment.text + end + + def test_do_classes_struct_without_accessor + content = <<-EOF +/* Document-class: Foo + * this is the Foo class + */ VALUE cFoo = rb_struct_define_without_accessor( "Foo", rb_cObject, foo_alloc, "some", "various", "fields", NULL); @@ -364,6 +393,21 @@ VALUE cFoo = rb_struct_define_without_accessor( assert_equal "this is the Foo class", klass.comment.text end + def test_do_classes_struct_without_accessor_under + content = <<-EOF +/* Document-class: Kernel::Foo + * this is the Foo class under Kernel + */ +VALUE cFoo = rb_struct_define_without_accessor_under( + rb_mKernel, "Foo", rb_cObject, foo_alloc, + "some", "various", "fields", NULL); + EOF + + klass = util_get_class content, 'cFoo' + assert_equal 'Kernel::Foo', klass.full_name + assert_equal "this is the Foo class under Kernel", klass.comment.text + end + def test_do_classes_class_under content = <<-EOF /* Document-class: Kernel::Foo @@ -594,6 +638,17 @@ void Init_File(void) { assert_equal 'LOCK_SH', constant.name assert_equal 'INT2FIX(LOCK_SH)', constant.value assert_equal 'Shared lock', constant.comment.text + + @parser = util_parser <<-EOF +void Init_File(void) { + rb_cFile = rb_define_class("File", rb_cIO); + rb_mFConst = rb_define_module_under(rb_cFile, "Constants"); +} + EOF + @parser.do_classes_and_modules + @parser.do_constants + + assert_equal 'File::Constants', klass.full_name end def test_do_includes diff --git a/test/rdoc/test_rdoc_parser_ruby.rb b/test/rdoc/test_rdoc_parser_ruby.rb index 337cf9ea1a..ef8ad91668 100644 --- a/test/rdoc/test_rdoc_parser_ruby.rb +++ b/test/rdoc/test_rdoc_parser_ruby.rb @@ -921,7 +921,7 @@ end @parser.parse_class @top_level, RDoc::Parser::Ruby::NORMAL, tk, @comment end err = stds[1] - assert_match(/Expected class name or '<<'\. Got/, err) + assert_match(/Expected class name or '<<\'\. Got/, err) end def test_parse_syntax_error_code @@ -4345,4 +4345,17 @@ end assert_equal 'Hello', meth.comment.text end + def test_parenthesized_cdecl + util_parser <<-RUBY +module DidYouMean + class << (NameErrorCheckers = Object.new) + end +end + RUBY + + @parser.scan + + refute_predicate @store.find_class_or_module('DidYouMean'), :nil? + refute_predicate @store.find_class_or_module('DidYouMean::NameErrorCheckers'), :nil? + end end diff --git a/test/rdoc/test_rdoc_rdoc.rb b/test/rdoc/test_rdoc_rdoc.rb index eaf92c8a9f..e958e5f2f6 100644 --- a/test/rdoc/test_rdoc_rdoc.rb +++ b/test/rdoc/test_rdoc_rdoc.rb @@ -254,6 +254,7 @@ class TestRDocRDoc < RDoc::TestCase top_level = nil temp_dir do |dir| @rdoc.options.parse %W[--root #{test_path}] + @rdoc.options.finish File.open 'include.txt', 'w' do |io| io.puts ':include: test.txt' diff --git a/test/rdoc/test_rdoc_require.rb b/test/rdoc/test_rdoc_require.rb index 46c225299a..4cc53e6c6c 100644 --- a/test/rdoc/test_rdoc_require.rb +++ b/test/rdoc/test_rdoc_require.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true -require File.expand_path '../xref_test_case', __FILE__ +require_relative 'xref_test_case' class TestRDocRequire < XrefTestCase @@ -23,4 +23,3 @@ class TestRDocRequire < XrefTestCase end end - diff --git a/test/rdoc/test_rdoc_ri_driver.rb b/test/rdoc/test_rdoc_ri_driver.rb index 87e4ebd2b1..5f3468c368 100644 --- a/test/rdoc/test_rdoc_ri_driver.rb +++ b/test/rdoc/test_rdoc_ri_driver.rb @@ -32,8 +32,8 @@ class TestRDocRIDriver < RDoc::TestCase end def teardown - ENV['RI'] = @orig_ri - FileUtils.rm_rf @tmpdir + defined?(@orig_ri) and ENV['RI'] = @orig_ri + defined?(@tmpdir) and FileUtils.rm_rf @tmpdir super end diff --git a/test/rdoc/test_rdoc_rubygems_hook.rb b/test/rdoc/test_rdoc_rubygems_hook.rb index 04f84d4bcc..59a7ed0f89 100644 --- a/test/rdoc/test_rdoc_rubygems_hook.rb +++ b/test/rdoc/test_rdoc_rubygems_hook.rb @@ -1,9 +1,9 @@ # frozen_string_literal: true -require "rubygems" -require "fileutils" -require "tmpdir" -require 'rdoc/rubygems_hook' -require "test/unit" +require 'rubygems' +require 'fileutils' +require 'tmpdir' +require_relative '../../lib/rdoc/rubygems_hook' +require 'test/unit' class TestRDocRubygemsHook < Test::Unit::TestCase def setup diff --git a/test/rdoc/test_rdoc_store.rb b/test/rdoc/test_rdoc_store.rb index 82340e6b7a..aa4db4c65e 100644 --- a/test/rdoc/test_rdoc_store.rb +++ b/test/rdoc/test_rdoc_store.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true -require File.expand_path '../xref_test_case', __FILE__ +require_relative 'xref_test_case' class TestRDocStore < XrefTestCase @@ -161,9 +161,10 @@ class TestRDocStore < XrefTestCase def test_all_classes_and_modules expected = %w[ - C1 C2 C2::C3 C2::C3::H1 C3 C3::H1 C3::H2 C4 C4::C4 C5 C5::C1 C6 C7 C8 C8::S1 C9 C9::A C9::B + C1 C10 C10::C11 C11 C2 C2::C3 C2::C3::H1 C3 C3::H1 C3::H2 C4 C4::C4 C5 C5::C1 C6 C7 C8 C8::S1 C9 C9::A C9::B Child M1 M1::M2 + Object Parent ] @@ -212,8 +213,9 @@ class TestRDocStore < XrefTestCase def test_classes expected = %w[ - C1 C2 C2::C3 C2::C3::H1 C3 C3::H1 C3::H2 C4 C4::C4 C5 C5::C1 C6 C7 C8 C8::S1 C9 C9::A C9::B + C1 C10 C10::C11 C11 C2 C2::C3 C2::C3::H1 C3 C3::H1 C3::H2 C4 C4::C4 C5 C5::C1 C6 C7 C8 C8::S1 C9 C9::A C9::B Child + Object Parent ] diff --git a/test/rdoc/test_rdoc_task.rb b/test/rdoc/test_rdoc_task.rb index 77f2af33a3..23add7d5fe 100644 --- a/test/rdoc/test_rdoc_task.rb +++ b/test/rdoc/test_rdoc_task.rb @@ -171,4 +171,3 @@ class TestRDocTask < RDoc::TestCase end end if defined?(Rake::Task) - diff --git a/test/rdoc/test_rdoc_top_level.rb b/test/rdoc/test_rdoc_top_level.rb index a954fde981..3cfaa9b763 100644 --- a/test/rdoc/test_rdoc_top_level.rb +++ b/test/rdoc/test_rdoc_top_level.rb @@ -1,5 +1,5 @@ # frozen_string_literal: true -require File.expand_path '../xref_test_case', __FILE__ +require_relative 'xref_test_case' class TestRDocTopLevel < XrefTestCase @@ -90,7 +90,7 @@ class TestRDocTopLevel < XrefTestCase @top_level.add_method method object = @store.find_class_named 'Object' - assert_equal [method], object.method_list + assert_equal [@c10_method, @c11_method, method], object.method_list assert_includes object.in_files, @top_level end @@ -101,7 +101,7 @@ class TestRDocTopLevel < XrefTestCase @top_level.add_method method object = @store.find_class_named('Object') - assert_empty object.method_list + assert_equal [@c10_method, @c11_method], object.method_list assert_includes object.in_files, @top_level end @@ -288,4 +288,3 @@ class TestRDocTopLevel < XrefTestCase end end - diff --git a/test/rdoc/xref_data.rb b/test/rdoc/xref_data.rb index aa9faaecd9..de76a90602 100644 --- a/test/rdoc/xref_data.rb +++ b/test/rdoc/xref_data.rb @@ -115,6 +115,23 @@ class C9 end end +class C10 + class C11 + end + + def C11 + end +end + +def C10 +end + +class C11 +end + +def C11 +end + module M1 def m end diff --git a/test/rdoc/xref_test_case.rb b/test/rdoc/xref_test_case.rb index 729e4a70b7..22b00d04bc 100644 --- a/test/rdoc/xref_test_case.rb +++ b/test/rdoc/xref_test_case.rb @@ -70,6 +70,14 @@ class XrefTestCase < RDoc::TestCase @c9_b_c_foo = @c9_b.method_list.first @c9_b_i_bar = @c9_b.method_list.last + @object = @xref_data.find_module_named 'Object' + @c10_class = @xref_data.find_module_named 'C10' + @c10_method = @object.find_method_named 'C10' + @c11_class = @xref_data.find_module_named 'C11' + @c10_c11_class = @c10_class.find_module_named 'C11' + @c10_c11_method = @c10_class.find_method_named 'C11' + @c11_method = @object.find_method_named 'C11' + @m1 = @xref_data.find_module_named 'M1' @m1_m = @m1.method_list.first diff --git a/test/readline/test_readline.rb b/test/readline/test_readline.rb index f59e9ee900..be338c6c0d 100644 --- a/test/readline/test_readline.rb +++ b/test/readline/test_readline.rb @@ -494,18 +494,17 @@ module BasetestReadline # Maybe the same issue: https://github.com/facebookresearch/nle/issues/120 omit if /i[3-6]86-linux/ =~ RUBY_PLATFORM + if defined?(TestReadline) && self.class == TestReadline + use = "use_ext_readline" + elsif defined?(TestRelineAsReadline) && self.class == TestRelineAsReadline + use = "use_lib_reline" + end code = <<-"end;" $stdout.sync = true require 'readline' require 'helper' + #{use} puts "Readline::VERSION is \#{Readline::VERSION}." - #{ - if defined?(TestReadline) && self.class == TestReadline - "use_ext_readline" - elsif defined?(TestRelineAsReadline) && self.class == TestRelineAsReadline - "use_lib_reline" - end - } Readline.input = STDIN # 0. Send SIGINT to this script. begin @@ -535,11 +534,12 @@ module BasetestReadline loop do c = _out.read(1) log << c if c - break if log.include?('input>') + break if log.include?('input> ') end log << "** SIGINT **" + sleep 0.5 Process.kill(:INT, pid) - sleep 0.1 + sleep 0.5 loop do c = _out.read(1) log << c if c @@ -568,10 +568,21 @@ module BasetestReadline assert interrupt_suppressed, "Should handle SIGINT correctly but raised interrupt.\nLog: #{log}\n----" end rescue Timeout::Error => e + Process.kill(:KILL, pid) + log << "\nKilled by timeout" assert false, "Timed out to handle SIGINT!\nLog: #{log}\nBacktrace:\n#{e.full_message(highlight: false)}\n----" ensure - status = Process.wait2(pid).last - assert status.success?, "Unknown failure with exit status #{status}\nLog: #{log}\n----" + status = nil + begin + Timeout.timeout(TIMEOUT) do + status = Process.wait2(pid).last + end + rescue Timeout::Error => e + log << "\nKilled by timeout to wait2" + Process.kill(:KILL, pid) + assert false, "Timed out to wait for terminating a process in a test of SIGINT!\nLog: #{log}\nBacktrace:\n#{e.full_message(highlight: false)}\n----" + end + assert status&.success?, "Unknown failure with exit status #{status.inspect}\nLog: #{log}\n----" end assert log.include?('INT'), "Interrupt was handled correctly." diff --git a/test/reline/helper.rb b/test/reline/helper.rb index cd3783ddb8..e8b8e3a6e1 100644 --- a/test/reline/helper.rb +++ b/test/reline/helper.rb @@ -77,6 +77,13 @@ class Reline::TestCase < Test::Unit::TestCase end end + def input_raw_keys(input, convert = true) + input = convert_str(input) if convert + input.bytes.each do |b| + @line_editor.input_key(Reline::Key.new(b, b, false)) + end + end + def assert_line(expected) expected = convert_str(expected) assert_equal(expected, @line_editor.line) @@ -85,9 +92,13 @@ class Reline::TestCase < Test::Unit::TestCase def assert_byte_pointer_size(expected) expected = convert_str(expected) byte_pointer = @line_editor.instance_variable_get(:@byte_pointer) + chunk = @line_editor.line.byteslice(0, byte_pointer) assert_equal( expected.bytesize, byte_pointer, - "<#{expected.inspect}> expected but was\n<#{@line_editor.line.byteslice(0, byte_pointer).inspect}>") + <<~EOM) + <#{expected.inspect} (#{expected.encoding.inspect})> expected but was + <#{chunk.inspect} (#{chunk.encoding.inspect})> in <Terminal #{Reline::GeneralIO.encoding.inspect}> + EOM end def assert_cursor(expected) diff --git a/test/reline/test_config.rb b/test/reline/test_config.rb index aa549a392d..99d190d246 100644 --- a/test/reline/test_config.rb +++ b/test/reline/test_config.rb @@ -11,12 +11,14 @@ class Reline::Config::Test < Reline::TestCase Dir.mkdir(@tmpdir) end Dir.chdir(@tmpdir) + Reline.test_mode @config = Reline::Config.new end def teardown Dir.chdir(@pwd) FileUtils.rm_rf(@tmpdir) + Reline.test_reset @config.reset end @@ -81,6 +83,22 @@ class Reline::Config::Test < Reline::TestCase assert_equal '(Emacs)', @config.instance_variable_get(:@emacs_mode_string) end + def test_encoding_is_ascii + @config.reset + Reline::IOGate.reset(encoding: Encoding::US_ASCII) + @config = Reline::Config.new + + assert_equal true, @config.convert_meta + end + + def test_encoding_is_not_ascii + @config.reset + Reline::IOGate.reset(encoding: Encoding::UTF_8) + @config = Reline::Config.new + + assert_equal nil, @config.convert_meta + end + def test_comment_line @config.read_lines([" #a: error\n"]) assert_not_include @config.key_bindings, nil @@ -256,6 +274,28 @@ class Reline::Config::Test < Reline::TestCase assert_equal expected, @config.key_bindings end + def test_additional_key_bindings_for_auxiliary_emacs_keymaps + @config.read_lines(<<~'LINES'.lines) + set keymap emacs + "ab": "AB" + set keymap emacs-standard + "cd": "CD" + set keymap emacs-ctlx + "ef": "EF" + set keymap emacs-meta + "gh": "GH" + set editing-mode emacs # keymap changes to be emacs + LINES + + expected = { + 'ab'.bytes => 'AB'.bytes, + 'cd'.bytes => 'CD'.bytes, + "\C-xef".bytes => 'EF'.bytes, + "\egh".bytes => 'GH'.bytes, + } + assert_equal expected, @config.key_bindings + end + def test_history_size @config.read_lines(<<~LINES.lines) set history-size 5000 diff --git a/test/reline/test_key_actor_emacs.rb b/test/reline/test_key_actor_emacs.rb index 8053225d24..40b26e5058 100644 --- a/test/reline/test_key_actor_emacs.rb +++ b/test/reline/test_key_actor_emacs.rb @@ -255,31 +255,31 @@ class Reline::KeyActor::Emacs::Test < Reline::TestCase end def test_em_kill_line - input_keys("\C-u", false) + @line_editor.input_key(Reline::Key.new(:em_kill_line, :em_kill_line, false)) assert_byte_pointer_size('') assert_cursor(0) assert_cursor_max(0) assert_line('') input_keys('abc') - assert_byte_pointer_size('abc') - assert_cursor(3) - assert_cursor_max(3) - input_keys("\C-u", false) + @line_editor.input_key(Reline::Key.new(:em_kill_line, :em_kill_line, false)) assert_byte_pointer_size('') assert_cursor(0) assert_cursor_max(0) assert_line('') input_keys('abc') - input_keys("\C-b\C-u", false) + input_keys("\C-b", false) + @line_editor.input_key(Reline::Key.new(:em_kill_line, :em_kill_line, false)) assert_byte_pointer_size('') assert_cursor(0) - assert_cursor_max(1) - assert_line('c') - input_keys("\C-u", false) + assert_cursor_max(0) + assert_line('') + input_keys('abc') + input_keys("\C-a", false) + @line_editor.input_key(Reline::Key.new(:em_kill_line, :em_kill_line, false)) assert_byte_pointer_size('') assert_cursor(0) - assert_cursor_max(1) - assert_line('c') + assert_cursor_max(0) + assert_line('') end def test_ed_move_to_beg @@ -2306,6 +2306,22 @@ class Reline::KeyActor::Emacs::Test < Reline::TestCase assert_line('abcd') end + def test_halfwidth_kana_width_dakuten + input_raw_keys('ガギゲゴ') + assert_byte_pointer_size('ガギゲゴ') + assert_cursor(8) + assert_cursor_max(8) + input_keys("\C-b\C-b", false) + assert_byte_pointer_size('ガギ') + assert_cursor(4) + assert_cursor_max(8) + input_raw_keys('グ', false) + assert_byte_pointer_size('ガギグ') + assert_cursor(6) + assert_cursor_max(10) + assert_line('ガギグゲゴ') + end + def test_input_unknown_char input_keys('') # U+0378 (unassigned) assert_line('') @@ -2313,4 +2329,26 @@ class Reline::KeyActor::Emacs::Test < Reline::TestCase assert_cursor(1) assert_cursor_max(1) end + + def test_unix_line_discard + input_keys("\C-u", false) + assert_byte_pointer_size('') + assert_cursor(0) + assert_cursor_max(0) + assert_line('') + input_keys('abc') + assert_byte_pointer_size('abc') + assert_cursor(3) + assert_cursor_max(3) + input_keys("\C-b\C-u", false) + assert_byte_pointer_size('') + assert_cursor(0) + assert_cursor_max(1) + assert_line('c') + input_keys("\C-f\C-u", false) + assert_byte_pointer_size('') + assert_cursor(0) + assert_cursor_max(0) + assert_line('') + end end diff --git a/test/reline/test_key_actor_vi.rb b/test/reline/test_key_actor_vi.rb index 722cdc0b75..b3d49c9bbb 100644 --- a/test/reline/test_key_actor_vi.rb +++ b/test/reline/test_key_actor_vi.rb @@ -1426,4 +1426,32 @@ class Reline::KeyActor::ViInsert::Test < Reline::TestCase assert_cursor(4) assert_cursor_max(4) end + + def test_vi_kill_line_prev + input_keys("\C-u", false) + assert_byte_pointer_size('') + assert_cursor(0) + assert_cursor_max(0) + assert_line('') + input_keys('abc') + assert_byte_pointer_size('abc') + assert_cursor(3) + assert_cursor_max(3) + input_keys("\C-u", false) + assert_byte_pointer_size('') + assert_cursor(0) + assert_cursor_max(0) + assert_line('') + input_keys('abc') + input_keys("\C-[\C-u", false) + assert_byte_pointer_size('') + assert_cursor(0) + assert_cursor_max(1) + assert_line('c') + input_keys("\C-u", false) + assert_byte_pointer_size('') + assert_cursor(0) + assert_cursor_max(1) + assert_line('c') + end end diff --git a/test/reline/test_reline.rb b/test/reline/test_reline.rb index dd049ac127..0d45c5da54 100644 --- a/test/reline/test_reline.rb +++ b/test/reline/test_reline.rb @@ -137,14 +137,14 @@ class Reline::Test < Reline::TestCase end def test_completion_proc - skip unless Reline.completion_proc == nil + omit unless Reline.completion_proc == nil # Another test can set Reline.completion_proc # assert_equal(nil, Reline.completion_proc) - p = proc {} - Reline.completion_proc = p - assert_equal(p, Reline.completion_proc) + dummy_proc = proc {} + Reline.completion_proc = dummy_proc + assert_equal(dummy_proc, Reline.completion_proc) l = lambda {} Reline.completion_proc = l @@ -161,9 +161,9 @@ class Reline::Test < Reline::TestCase def test_output_modifier_proc assert_equal(nil, Reline.output_modifier_proc) - p = proc {} - Reline.output_modifier_proc = p - assert_equal(p, Reline.output_modifier_proc) + dummy_proc = proc {} + Reline.output_modifier_proc = dummy_proc + assert_equal(dummy_proc, Reline.output_modifier_proc) l = lambda {} Reline.output_modifier_proc = l @@ -180,9 +180,9 @@ class Reline::Test < Reline::TestCase def test_prompt_proc assert_equal(nil, Reline.prompt_proc) - p = proc {} - Reline.prompt_proc = p - assert_equal(p, Reline.prompt_proc) + dummy_proc = proc {} + Reline.prompt_proc = dummy_proc + assert_equal(dummy_proc, Reline.prompt_proc) l = lambda {} Reline.prompt_proc = l @@ -199,9 +199,9 @@ class Reline::Test < Reline::TestCase def test_auto_indent_proc assert_equal(nil, Reline.auto_indent_proc) - p = proc {} - Reline.auto_indent_proc = p - assert_equal(p, Reline.auto_indent_proc) + dummy_proc = proc {} + Reline.auto_indent_proc = dummy_proc + assert_equal(dummy_proc, Reline.auto_indent_proc) l = lambda {} Reline.auto_indent_proc = l @@ -218,9 +218,9 @@ class Reline::Test < Reline::TestCase def test_pre_input_hook assert_equal(nil, Reline.pre_input_hook) - p = proc {} - Reline.pre_input_hook = p - assert_equal(p, Reline.pre_input_hook) + dummy_proc = proc {} + Reline.pre_input_hook = dummy_proc + assert_equal(dummy_proc, Reline.pre_input_hook) l = lambda {} Reline.pre_input_hook = l @@ -230,9 +230,9 @@ class Reline::Test < Reline::TestCase def test_dig_perfect_match_proc assert_equal(nil, Reline.dig_perfect_match_proc) - p = proc {} - Reline.dig_perfect_match_proc = p - assert_equal(p, Reline.dig_perfect_match_proc) + dummy_proc = proc {} + Reline.dig_perfect_match_proc = dummy_proc + assert_equal(dummy_proc, Reline.dig_perfect_match_proc) l = lambda {} Reline.dig_perfect_match_proc = l @@ -310,6 +310,48 @@ class Reline::Test < Reline::TestCase assert_equal(Reline::KeyActor::Emacs, Reline.send(:core).config.editing_mode.class) end + def test_add_dialog_proc + dummy_proc = proc {} + Reline.add_dialog_proc(:test_proc, dummy_proc) + d = Reline.dialog_proc(:test_proc) + assert_equal(dummy_proc, d.dialog_proc) + + dummy_proc_2 = proc {} + Reline.add_dialog_proc(:test_proc, dummy_proc_2) + d = Reline.dialog_proc(:test_proc) + assert_equal(dummy_proc_2, d.dialog_proc) + + l = lambda {} + Reline.add_dialog_proc(:test_lambda, l) + d = Reline.dialog_proc(:test_lambda) + assert_equal(l, d.dialog_proc) + + assert_equal(nil, Reline.dialog_proc(:test_nothing)) + + assert_raise(ArgumentError) { Reline.add_dialog_proc(:error, 42) } + assert_raise(ArgumentError) { Reline.add_dialog_proc(:error, 'hoge') } + assert_raise(ArgumentError) { Reline.add_dialog_proc('error', proc {} ) } + + dummy = DummyCallbackObject.new + Reline.add_dialog_proc(:dummy, dummy) + d = Reline.dialog_proc(:dummy) + assert_equal(dummy, d.dialog_proc) + end + + def test_add_dialog_proc_with_context + dummy_proc = proc {} + array = Array.new + Reline.add_dialog_proc(:test_proc, dummy_proc, array) + d = Reline.dialog_proc(:test_proc) + assert_equal(dummy_proc, d.dialog_proc) + assert_equal(array, d.context) + + Reline.add_dialog_proc(:test_proc, dummy_proc, nil) + d = Reline.dialog_proc(:test_proc) + assert_equal(dummy_proc, d.dialog_proc) + assert_equal(nil, d.context) + end + def test_readmultiline # readmultiline is module function assert_include(Reline.methods, :readmultiline) @@ -322,22 +364,10 @@ class Reline::Test < Reline::TestCase assert_include(Reline.private_instance_methods, :readline) end - def test_inner_readline - # TODO in Reline::Core - end - def test_read_io # TODO in Reline::Core end - def test_read_escaped_key - # TODO in Reline::Core - end - - def test_may_req_ambiguous_char_width - # TODO in Reline::Core - end - def get_reline_encoding if encoding = Reline::IOGate.encoding encoding diff --git a/test/reline/test_terminfo.rb b/test/reline/test_terminfo.rb index f1bf197931..dda9b32495 100644 --- a/test/reline/test_terminfo.rb +++ b/test/reline/test_terminfo.rb @@ -9,24 +9,53 @@ class Reline::Terminfo::Test < Reline::TestCase def test_tigetstr assert Reline::Terminfo.tigetstr('khome') rescue Reline::Terminfo::TerminfoError => e - skip e.message + omit e.message + end + + def test_tigetstr_with_error + assert_raise(Reline::Terminfo::TerminfoError) { Reline::Terminfo.tigetstr('unknown') } + assert_raise(Reline::Terminfo::TerminfoError) { Reline::Terminfo.tigetstr(nil) } end def test_tiparm assert Reline::Terminfo.tigetstr('khome').tiparm rescue Reline::Terminfo::TerminfoError => e - skip e.message + omit e.message end def test_tigetstr_with_param assert Reline::Terminfo.tigetstr('cuu').include?('%p1%d') rescue Reline::Terminfo::TerminfoError => e - skip e.message + omit e.message end def test_tiparm_with_param assert Reline::Terminfo.tigetstr('cuu').tiparm(4649).include?('4649') rescue Reline::Terminfo::TerminfoError => e - skip e.message + omit e.message + end + + def test_tigetflag + assert_instance_of Integer, Reline::Terminfo.tigetflag('xenl') + rescue Reline::Terminfo::TerminfoError => e + omit e.message + end + + def test_tigetflag_with_error + assert_raise(Reline::Terminfo::TerminfoError) { Reline::Terminfo.tigetflag('cuu') } + assert_raise(Reline::Terminfo::TerminfoError) { Reline::Terminfo.tigetflag('unknown') } + assert_raise(Reline::Terminfo::TerminfoError) { Reline::Terminfo.tigetflag(nil) } + end + + def test_tigetnum + assert_instance_of Integer, Reline::Terminfo.tigetnum('colors') + rescue Reline::Terminfo::TerminfoError => e + omit e.message + end + + def test_tigetnum_with_error + assert_raise(Reline::Terminfo::TerminfoError) { Reline::Terminfo.tigetnum('cuu') } + assert_raise(Reline::Terminfo::TerminfoError) { Reline::Terminfo.tigetnum('unknown') } + assert_raise(Reline::Terminfo::TerminfoError) { Reline::Terminfo.tigetnum(nil) } end end if Reline::Terminfo.enabled? diff --git a/test/reline/test_within_pipe.rb b/test/reline/test_within_pipe.rb index ff2d68bb82..43a66f45f4 100644 --- a/test/reline/test_within_pipe.rb +++ b/test/reline/test_within_pipe.rb @@ -9,7 +9,7 @@ class Reline::WithinPipeTest < Reline::TestCase @reader, @output_writer = IO.pipe(@encoding) @output = Reline.output = @output_writer @config = Reline.send(:core).config - @config.keyseq_timeout *= 600 if defined?(RubyVM::JIT) && RubyVM::JIT.enabled? # for --jit-wait CI + @config.keyseq_timeout *= 600 if defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? # for --jit-wait CI @line_editor = Reline.send(:core).line_editor end diff --git a/test/reline/yamatanooroti/multiline_repl b/test/reline/yamatanooroti/multiline_repl index 1f2a023724..d27d216652 100755 --- a/test/reline/yamatanooroti/multiline_repl +++ b/test/reline/yamatanooroti/multiline_repl @@ -1,5 +1,9 @@ #!/usr/bin/env ruby + +require 'bundler' +Bundler.require + require 'reline' require 'optparse' require_relative 'termination_checker' @@ -27,6 +31,14 @@ opt.on('--broken-dynamic-prompt') { opt.on('--dynamic-prompt-returns-empty') { Reline.prompt_proc = proc { |l| [] } } +opt.on('--dynamic-prompt-with-newline') { + Reline.prompt_proc = proc { |lines| + range = lines.size > 1 ? (0..(lines.size - 2)) : (0..0) + lines[range].each_with_index.map { |l, i| + '[%04d\n]> ' % i + } + } +} opt.on('--auto-indent') { AutoIndent.new } diff --git a/test/reline/yamatanooroti/termination_checker.rb b/test/reline/yamatanooroti/termination_checker.rb index 9c2c3ae740..24fb24c4b1 100644 --- a/test/reline/yamatanooroti/termination_checker.rb +++ b/test/reline/yamatanooroti/termination_checker.rb @@ -4,7 +4,7 @@ require 'irb/ruby-lex' class TerminationChecker < RubyLex def terminated?(code) code.gsub!(/\n*$/, '').concat("\n") - @tokens = Ripper.lex(code) + @tokens = self.class.ripper_lex_without_warning(code) continue = process_continue code_block_open = check_code_block(code) indent = process_nesting_level diff --git a/test/reline/yamatanooroti/test_rendering.rb b/test/reline/yamatanooroti/test_rendering.rb index f68b614327..c383112131 100644 --- a/test/reline/yamatanooroti/test_rendering.rb +++ b/test/reline/yamatanooroti/test_rendering.rb @@ -121,6 +121,7 @@ begin end def test_finish_autowrapped_line_in_the_middle_of_multilines + omit if RUBY_VERSION < '2.7' start_terminal(30, 16, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') write("<<~EOM\n ABCDEFG\nEOM\n") close @@ -739,6 +740,16 @@ begin EOC end + def test_not_meta_key + start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') + write("おだんご") # "だ" in UTF-8 contains "\xA0" + close + assert_screen(<<~EOC) + Multiline REPL. + prompt> おだんご + EOC + end + def test_force_enter start_terminal(30, 120, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') write("def hoge\nend\C-p\C-e") @@ -756,6 +767,7 @@ begin omit if Reline::IOGate.win? cmd = %Q{ruby -e 'print(%Q{abc def \\e\\r})' | ruby -I#{@pwd}/lib -rreline -e 'p Reline.readline(%{> })'} start_terminal(40, 50, ['bash', '-c', cmd]) + sleep 1 close assert_screen(<<~'EOC') > abc def @@ -937,7 +949,7 @@ begin def test_dialog_with_fullwidth_chars ENV['RELINE_TEST_PROMPT'] = '> ' - start_terminal(30, 5, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --dialog fullwidth,scrollkey,scrollbar}, startup_message: 'Multiline REPL.') + start_terminal(20, 5, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --dialog fullwidth,scrollkey,scrollbar}, startup_message: 'Multiline REPL.') 6.times{ write('j') } close assert_screen(<<~'EOC') @@ -954,7 +966,7 @@ begin def test_dialog_with_fullwidth_chars_split ENV['RELINE_TEST_PROMPT'] = '> ' - start_terminal(30, 6, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --dialog fullwidth,scrollkey,scrollbar}, startup_message: 'Multiline REPL.') + start_terminal(20, 6, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --dialog fullwidth,scrollkey,scrollbar}, startup_message: 'Multiline REPL.') 6.times{ write('j') } close assert_screen(<<~'EOC') @@ -1187,6 +1199,140 @@ begin EOC end + def test_scroll_at_bottom_for_dialog + start_terminal(10, 40, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.') + write("\n\n\n\n\n\n") + write("def hoge\n\n\n\n\n\n\nend\C-p\C-p\C-p\C-e") + write(" S") + close + assert_screen(<<~'EOC') + prompt> def hoge + prompt> + prompt> + prompt> + prompt> S + prompt> String + prompt> Struct + prompt> enSymbol + ScriptError + Signal + EOC + end + + def test_clear_dialog_in_pasting + start_terminal(10, 40, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.') + write("S") + write("tring ") + close + assert_screen(<<~'EOC') + Multiline REPL. + prompt> String + EOC + end + + def test_prompt_with_newline + ENV['RELINE_TEST_PROMPT'] = "::\n> " + start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl}, startup_message: 'Multiline REPL.') + write("def hoge\n 3\nend") + close + assert_screen(<<~'EOC') + Multiline REPL. + ::\n> def hoge + ::\n> 3 + ::\n> end + EOC + end + + def test_dynamic_prompt_with_newline + start_terminal(5, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --dynamic-prompt-with-newline}, startup_message: 'Multiline REPL.') + write("def hoge\n 3\nend") + close + assert_screen(<<~'EOC') + Multiline REPL. + [0000\n]> def hoge + [0001\n]> 3 + [0001\n]> end + EOC + end + + def test_clear_dialog_when_just_move_cursor_at_last_line + start_terminal(10, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.') + write("class A\n 3\nend\n") + write("\C-p\C-p\C-p\C-e\C-hS") + write("\C-n") + write("1") + close + assert_screen(<<~'EOC') + prompt> 3 + prompt> end + => 3 + prompt> class S + prompt> 31 + prompt> end + EOC + end + + def test_clear_dialog_when_adding_new_line_to_end_of_buffer + start_terminal(10, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.') + write("class A\n def a\n 3\n end\nend") + write("\n") + write("class S") + write("\n") + write(" 3") + close + assert_screen(<<~'EOC') + prompt> end + prompt> end + => :a + prompt> class S + prompt> 3 + EOC + end + + def test_insert_newline_in_the_middle_of_buffer_just_after_dialog + start_terminal(10, 30, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.') + write("class A\n def a\n 3\n end\nend") + write("\n") + write("\C-p\C-p\C-p\C-p\C-p\C-e\C-hS") + write("\M-\x0D") + write(" 3") + close + assert_screen(<<~'EOC') + prompt> end + prompt> end + => :a + prompt> class S + prompt> 3 + prompt> def a + prompt> 3 + prompt> end + prompt> end + EOC + end + + def test_incremental_search_on_not_last_line + start_terminal(10, 40, %W{ruby -I#{@pwd}/lib #{@pwd}/test/reline/yamatanooroti/multiline_repl --autocomplete}, startup_message: 'Multiline REPL.') + write("def abc\nend\n") + write("def def\nend\n") + write("\C-p\C-p\C-e") + write("\C-r") + write("a") + write("\n\n") + close + assert_screen(<<~'EOC') + prompt> def abc + prompt> end + => :abc + prompt> def def + prompt> end + => :def + prompt> def abc + prompt> end + => :abc + prompt> + EOC + end + def write_inputrc(content) File.open(@inputrc_file, 'w') do |f| f.write content diff --git a/test/resolv/test_addr.rb b/test/resolv/test_addr.rb index 62092676ba..f701c31d3e 100644 --- a/test/resolv/test_addr.rb +++ b/test/resolv/test_addr.rb @@ -28,6 +28,10 @@ class TestResolvAddr < Test::Unit::TestCase assert_match(Resolv::IPv6::Regex, "FE80:2:3:4:5:6:7:8%EM1", bug17112) assert_match(Resolv::IPv6::Regex, "FE80::20D:3AFF:FE7D:9760%ETH0", bug17112) assert_match(Resolv::IPv6::Regex, "FE80::1%EM1", bug17112) + + bug17524 = "[ruby-core:101992]" + assert_match(Resolv::IPv6::Regex, "FE80::20D:3AFF:FE7D:9760%ruby_3.0.0-1", bug17524) + assert_match(Resolv::IPv6::Regex, "fe80::1%ruby_3.0.0-1", bug17524) end def test_valid_socket_ip_address_list diff --git a/test/resolv/test_dns.rb b/test/resolv/test_dns.rb index 5171604a82..9d243bbf50 100644 --- a/test/resolv/test_dns.rb +++ b/test/resolv/test_dns.rb @@ -72,7 +72,7 @@ class TestResolvDNS < Test::Unit::TestCase begin OpenSSL rescue LoadError - skip 'autoload problem. see [ruby-dev:45021][Bug #5786]' + omit 'autoload problem. see [ruby-dev:45021][Bug #5786]' end if defined?(OpenSSL) with_udp('127.0.0.1', 0) {|u| @@ -161,7 +161,7 @@ class TestResolvDNS < Test::Unit::TestCase begin OpenSSL rescue LoadError - skip 'autoload problem. see [ruby-dev:45021][Bug #5786]' + omit 'autoload problem. see [ruby-dev:45021][Bug #5786]' end if defined?(OpenSSL) with_udp('127.0.0.1', 0) {|u| @@ -297,7 +297,7 @@ class TestResolvDNS < Test::Unit::TestCase end def test_no_server - skip if /mswin/ =~ RUBY_PLATFORM && ENV.key?('GITHUB_ACTIONS') # not working from the beginning + omit if /mswin/ =~ RUBY_PLATFORM && ENV.key?('GITHUB_ACTIONS') # not working from the beginning u = UDPSocket.new u.bind("127.0.0.1", 0) _, port, _, host = u.addr @@ -314,7 +314,7 @@ class TestResolvDNS < Test::Unit::TestCase rescue Timeout::Error if RUBY_PLATFORM.match?(/mingw/) # cannot repo locally - skip 'Timeout Error on MinGW CI' + omit 'Timeout Error on MinGW CI' else raise Timeout::Error end diff --git a/test/rinda/test_rinda.rb b/test/rinda/test_rinda.rb index f155e88de1..d937cd0f45 100644 --- a/test/rinda/test_rinda.rb +++ b/test/rinda/test_rinda.rb @@ -402,7 +402,7 @@ module TupleSpaceTestModule end def test_cancel_02 - skip 'this test is unstable with --jit-wait' if defined?(RubyVM::JIT) && RubyVM::JIT.enabled? + omit 'this test is unstable with --jit-wait' if defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? entry = @ts.write([:removeme, 1]) assert_equal([[:removeme, 1]], @ts.read_all([nil, nil])) entry.cancel @@ -528,7 +528,7 @@ class TupleSpaceProxyTest < Test::Unit::TestCase end def test_take_bug_8215 - skip "this test randomly fails on mswin" if /mswin/ =~ RUBY_PLATFORM + omit "this test randomly fails on mswin" if /mswin/ =~ RUBY_PLATFORM service = DRb.start_service("druby://localhost:0", @ts_base) uri = service.uri @@ -591,7 +591,7 @@ module RingIPv6 return if Socket.ip_address_list.any? { |addrinfo| addrinfo.ipv6? && !addrinfo.ipv6_loopback? } end - skip 'IPv6 not available' + omit 'IPv6 not available' end def ipv6_mc(rf, hops = nil) @@ -662,7 +662,7 @@ class TestRingServer < Test::Unit::TestCase end def test_do_reply_local - skip 'timeout-based test becomes unstable with --jit-wait' if defined?(RubyVM::JIT) && RubyVM::JIT.enabled? + omit 'timeout-based test becomes unstable with --jit-wait' if defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? with_timeout(30) {_test_do_reply_local} end @@ -693,7 +693,7 @@ class TestRingServer < Test::Unit::TestCase begin v4mc = @rs.make_socket('239.0.0.1') rescue Errno::ENOBUFS => e - skip "Missing multicast support in OS: #{e.message}" + omit "Missing multicast support in OS: #{e.message}" end begin @@ -704,7 +704,7 @@ class TestRingServer < Test::Unit::TestCase end rescue TypeError if /aix/ =~ RUBY_PLATFORM - skip "Known bug in getsockopt(2) on AIX" + omit "Known bug in getsockopt(2) on AIX" end raise $! end @@ -714,7 +714,7 @@ class TestRingServer < Test::Unit::TestCase end def test_make_socket_ipv6_multicast - skip 'IPv6 not available' unless + omit 'IPv6 not available' unless Socket.ip_address_list.any? { |addrinfo| addrinfo.ipv6? && !addrinfo.ipv6_loopback? } begin @@ -722,7 +722,7 @@ class TestRingServer < Test::Unit::TestCase rescue Errno::EADDRNOTAVAIL return # IPv6 address for multicast not available rescue Errno::ENOBUFS => e - skip "Missing multicast support in OS: #{e.message}" + omit "Missing multicast support in OS: #{e.message}" end if Socket.const_defined?(:SO_REUSEPORT) then @@ -740,7 +740,7 @@ class TestRingServer < Test::Unit::TestCase begin @rs = Rinda::RingServer.new(@ts, [['239.0.0.1', '0.0.0.0']], @port) rescue Errno::ENOBUFS => e - skip "Missing multicast support in OS: #{e.message}" + omit "Missing multicast support in OS: #{e.message}" end v4mc = @rs.instance_variable_get('@sockets').first @@ -753,7 +753,7 @@ class TestRingServer < Test::Unit::TestCase end rescue TypeError if /aix/ =~ RUBY_PLATFORM - skip "Known bug in getsockopt(2) on AIX" + omit "Known bug in getsockopt(2) on AIX" end raise $! end @@ -763,7 +763,7 @@ class TestRingServer < Test::Unit::TestCase end def test_ring_server_ipv6_multicast - skip 'IPv6 not available' unless + omit 'IPv6 not available' unless Socket.ip_address_list.any? { |addrinfo| addrinfo.ipv6? && !addrinfo.ipv6_loopback? } @rs.shutdown @@ -852,7 +852,7 @@ class TestRingFinger < Test::Unit::TestCase assert(v4.getsockopt(:SOL_SOCKET, :SO_BROADCAST).bool) rescue TypeError if /aix/ =~ RUBY_PLATFORM - skip "Known bug in getsockopt(2) on AIX" + omit "Known bug in getsockopt(2) on AIX" end raise $! ensure diff --git a/test/ripper/test_scanner_events.rb b/test/ripper/test_scanner_events.rb index cef584c157..13bd44e83d 100644 --- a/test/ripper/test_scanner_events.rb +++ b/test/ripper/test_scanner_events.rb @@ -56,13 +56,13 @@ class TestRipper::ScannerEvents < Test::Unit::TestCase end def test_lex - assert_equal [], + assert_lex [], Ripper.lex('') - assert_equal [[[1,0], :on_ident, "a", Ripper::EXPR_CMDARG]], + assert_lex [[[1,0], :on_ident, "a", Ripper::EXPR_CMDARG]], Ripper.lex('a') - assert_equal [[[1, 0], :on_kw, "nil", Ripper::EXPR_END]], + assert_lex [[[1, 0], :on_kw, "nil", Ripper::EXPR_END]], Ripper.lex("nil") - assert_equal [[[1, 0], :on_kw, "def", Ripper::EXPR_FNAME], + assert_lex [[[1, 0], :on_kw, "def", Ripper::EXPR_FNAME], [[1, 3], :on_sp, " ", Ripper::EXPR_FNAME], [[1, 4], :on_ident, "m", Ripper::EXPR_ENDFN], [[1, 5], :on_lparen, "(", Ripper::EXPR_BEG | Ripper::EXPR_LABEL], @@ -70,39 +70,39 @@ class TestRipper::ScannerEvents < Test::Unit::TestCase [[1, 7], :on_rparen, ")", Ripper::EXPR_ENDFN], [[1, 8], :on_kw, "end", Ripper::EXPR_END]], Ripper.lex("def m(a)end") - assert_equal [[[1, 0], :on_int, "1", Ripper::EXPR_END], + assert_lex [[[1, 0], :on_int, "1", Ripper::EXPR_END], [[1, 1], :on_nl, "\n", Ripper::EXPR_BEG], [[2, 0], :on_int, "2", Ripper::EXPR_END], [[2, 1], :on_nl, "\n", Ripper::EXPR_BEG], [[3, 0], :on_int, "3", Ripper::EXPR_END]], Ripper.lex("1\n2\n3") - assert_equal [[[1, 0], :on_heredoc_beg, "<<""EOS", Ripper::EXPR_BEG], + assert_lex [[[1, 0], :on_heredoc_beg, "<<""EOS", Ripper::EXPR_BEG], [[1, 5], :on_nl, "\n", Ripper::EXPR_BEG], [[2, 0], :on_tstring_content, "heredoc\n", Ripper::EXPR_BEG], [[3, 0], :on_heredoc_end, "EOS", Ripper::EXPR_BEG]], Ripper.lex("<<""EOS\nheredoc\nEOS") - assert_equal [[[1, 0], :on_heredoc_beg, "<<""EOS", Ripper::EXPR_BEG], + assert_lex [[[1, 0], :on_heredoc_beg, "<<""EOS", Ripper::EXPR_BEG], [[1, 5], :on_nl, "\n", Ripper::EXPR_BEG], [[2, 0], :on_heredoc_end, "EOS", Ripper::EXPR_BEG]], Ripper.lex("<<""EOS\nEOS"), "bug#4543" - assert_equal [[[1, 0], :on_regexp_beg, "/", Ripper::EXPR_BEG], + assert_lex [[[1, 0], :on_regexp_beg, "/", Ripper::EXPR_BEG], [[1, 1], :on_tstring_content, "foo\nbar", Ripper::EXPR_BEG], [[2, 3], :on_regexp_end, "/", Ripper::EXPR_BEG]], Ripper.lex("/foo\nbar/") - assert_equal [[[1, 0], :on_regexp_beg, "/", Ripper::EXPR_BEG], + assert_lex [[[1, 0], :on_regexp_beg, "/", Ripper::EXPR_BEG], [[1, 1], :on_tstring_content, "foo\n\u3020", Ripper::EXPR_BEG], [[2, 3], :on_regexp_end, "/", Ripper::EXPR_BEG]], Ripper.lex("/foo\n\u3020/") - assert_equal [[[1, 0], :on_tstring_beg, "'", Ripper::EXPR_BEG], + assert_lex [[[1, 0], :on_tstring_beg, "'", Ripper::EXPR_BEG], [[1, 1], :on_tstring_content, "foo\n\xe3\x80\xa0", Ripper::EXPR_BEG], [[2, 3], :on_tstring_end, "'", Ripper::EXPR_END]], Ripper.lex("'foo\n\xe3\x80\xa0'") - assert_equal [[[1, 0], :on_tstring_beg, "'", Ripper::EXPR_BEG], + assert_lex [[[1, 0], :on_tstring_beg, "'", Ripper::EXPR_BEG], [[1, 1], :on_tstring_content, "\u3042\n\u3044", Ripper::EXPR_BEG], [[2, 3], :on_tstring_end, "'", Ripper::EXPR_END]], Ripper.lex("'\u3042\n\u3044'") - assert_equal [[[1, 0], :on_rational, "1r", Ripper::EXPR_END], + assert_lex [[[1, 0], :on_rational, "1r", Ripper::EXPR_END], [[1, 2], :on_nl, "\n", Ripper::EXPR_BEG], [[2, 0], :on_imaginary, "2i", Ripper::EXPR_END], [[2, 2], :on_nl, "\n", Ripper::EXPR_BEG], @@ -113,18 +113,25 @@ class TestRipper::ScannerEvents < Test::Unit::TestCase [[5, 0], :on_imaginary, "5.6ri", Ripper::EXPR_END], ], Ripper.lex("1r\n2i\n3ri\n4.2r\n5.6ri") - assert_equal [[[1, 0], :on_heredoc_beg, "<<~EOS", Ripper::EXPR_BEG], + assert_lex [[[1, 0], :on_heredoc_beg, "<<~EOS", Ripper::EXPR_BEG], [[1, 6], :on_nl, "\n", Ripper::EXPR_BEG], [[2, 0], :on_ignored_sp, " ", Ripper::EXPR_BEG], [[2, 2], :on_tstring_content, "heredoc\n", Ripper::EXPR_BEG], [[3, 0], :on_heredoc_end, "EOS", Ripper::EXPR_BEG] ], Ripper.lex("<<~EOS\n heredoc\nEOS") - assert_equal [[[1, 0], :on_tstring_beg, "'", Ripper::EXPR_BEG], + assert_lex [[[1, 0], :on_tstring_beg, "'", Ripper::EXPR_BEG], [[1, 1], :on_tstring_content, "foo", Ripper::EXPR_BEG]], Ripper.lex("'foo") end + def assert_lex(expected, *rest) + expected = expected.map do |pos, type, tok, state, *rest| + [pos, type, tok, Ripper::Lexer::State.new(state), *rest] + end + assert_equal(expected, *rest) + end + def test_location assert_location "" assert_location " " diff --git a/test/ruby/enc/test_case_comprehensive.rb b/test/ruby/enc/test_case_comprehensive.rb index bde47017a2..bc57d57ee4 100644 --- a/test/ruby/enc/test_case_comprehensive.rb +++ b/test/ruby/enc/test_case_comprehensive.rb @@ -24,7 +24,7 @@ class TestComprehensiveCaseMapping < Test::Unit::TestCase def test_data_files_available unless TestComprehensiveCaseMapping.data_files_available? - skip "Unicode data files not available in #{UNICODE_DATA_PATH}." + omit "Unicode data files not available in #{UNICODE_DATA_PATH}." end end end diff --git a/test/ruby/enc/test_emoji_breaks.rb b/test/ruby/enc/test_emoji_breaks.rb index cdde4da9bf..c96d6088f5 100644 --- a/test/ruby/enc/test_emoji_breaks.rb +++ b/test/ruby/enc/test_emoji_breaks.rb @@ -4,50 +4,47 @@ require "test/unit" class TestEmojiBreaks < Test::Unit::TestCase -end - -class TestEmojiBreaks::BreakTest - attr_reader :string, :comment, :filename, :line_number, :type, :shortname - - def initialize(filename, line_number, data, comment='') - @filename = filename - @line_number = line_number - @comment = comment.gsub(/\s+/, ' ').strip - if filename=='emoji-test' or filename=='emoji-variation-sequences' - codes, @type = data.split(/\s*;\s*/) - @shortname = '' - else - codes, @type, @shortname = data.split(/\s*;\s*/) + class BreakTest + attr_reader :string, :comment, :filename, :line_number, :type, :shortname + + def initialize(filename, line_number, data, comment='') + @filename = filename + @line_number = line_number + @comment = comment.gsub(/\s+/, ' ').strip + if filename=='emoji-test' or filename=='emoji-variation-sequences' + codes, @type = data.split(/\s*;\s*/) + @shortname = '' + else + codes, @type, @shortname = data.split(/\s*;\s*/) + end + @type = @type.gsub(/\s+/, ' ').strip + @shortname = @shortname.gsub(/\s+/, ' ').strip + @string = codes.split(/\s+/) + .map do |ch| + c = ch.to_i(16) + # eliminate cases with surrogates + # raise ArgumentError if 0xD800 <= c and c <= 0xDFFF + c.chr('UTF-8') + end.join end - @type = @type.gsub(/\s+/, ' ').strip - @shortname = @shortname.gsub(/\s+/, ' ').strip - @string = codes.split(/\s+/) - .map do |ch| - c = ch.to_i(16) - # eliminate cases with surrogates - # raise ArgumentError if 0xD800 <= c and c <= 0xDFFF - c.chr('UTF-8') - end.join end -end -class TestEmojiBreaks::BreakFile - attr_reader :basename, :fullname, :version - FILES = [] + class BreakFile + attr_reader :basename, :fullname, :version + FILES = [] - def initialize(basename, path, version) - @basename = basename - @fullname = "#{path}/#{basename}.txt" # File.expand_path(path + version, __dir__) - @version = version - FILES << self - end + def initialize(basename, path, version) + @basename = basename + @fullname = "#{path}/#{basename}.txt" # File.expand_path(path + version, __dir__) + @version = version + FILES << self + end - def self.files - FILES + def self.files + FILES + end end -end -class TestEmojiBreaks < Test::Unit::TestCase UNICODE_VERSION = RbConfig::CONFIG['UNICODE_VERSION'] UNICODE_DATA_PATH = File.expand_path("../../../enc/unicode/data/#{UNICODE_VERSION}/ucd/emoji", __dir__) EMOJI_VERSION = RbConfig::CONFIG['UNICODE_EMOJI_VERSION'] @@ -56,7 +53,7 @@ class TestEmojiBreaks < Test::Unit::TestCase EMOJI_DATA_FILES = %w[emoji-sequences emoji-test emoji-zwj-sequences].map do |basename| BreakFile.new(basename, EMOJI_DATA_PATH, EMOJI_VERSION) end - UNICODE_DATA_FILE = BreakFile.new('emoji-variation-sequences', UNICODE_DATA_PATH, UNICODE_VERSION[0..-3]) # [0..-3] deals with a versioning mismatch problem in Unicode + UNICODE_DATA_FILE = BreakFile.new('emoji-variation-sequences', UNICODE_DATA_PATH, UNICODE_VERSION) EMOJI_DATA_FILES << UNICODE_DATA_FILE def self.data_files_available? @@ -68,83 +65,89 @@ class TestEmojiBreaks < Test::Unit::TestCase def test_data_files_available assert_equal 4, EMOJI_DATA_FILES.size # debugging test unless TestEmojiBreaks.data_files_available? - skip "Emoji data files not available in #{EMOJI_DATA_PATH}." + omit "Emoji data files not available in #{EMOJI_DATA_PATH}." end end -end -TestEmojiBreaks.data_files_available? and class TestEmojiBreaks - def read_data - tests = [] - EMOJI_DATA_FILES.each do |file| - version_mismatch = true - file_tests = [] - IO.foreach(file.fullname, encoding: Encoding::UTF_8) do |line| - line.chomp! - raise "File Name Mismatch: line: #{line}, expected filename: #{file.basename}.txt" if $.==1 and not line=="# #{file.basename}.txt" - version_mismatch = false if line =~ /^# Version: #{file.version}/ - next if line.match?(/\A(#|\z)/) - if line =~ /^(\h{4,6})\.\.(\h{4,6}) *(;.+)/ # deal with Unicode ranges in emoji-sequences.txt (Bug #18028) - range_start = $1.to_i(16) - range_end = $2.to_i(16) - rest = $3 - (range_start..range_end).each do |code_point| - file_tests << BreakTest.new(file.basename, $., *(code_point.to_s(16)+rest).split('#', 2)) + if data_files_available? + def read_data + tests = [] + EMOJI_DATA_FILES.each do |file| + version_mismatch = true + file_tests = [] + IO.foreach(file.fullname, encoding: Encoding::UTF_8) do |line| + line.chomp! + if $.==1 + if line=="# #{file.basename}-#{file.version}.txt" + version_mismatch = false + elsif line!="# #{file.basename}.txt" + raise "File Name Mismatch: line: #{line}, expected filename: #{file.basename}.txt" + end + end + version_mismatch = false if line =~ /^# Version: #{file.version}/ + next if line.match?(/\A(#|\z)/) + if line =~ /^(\h{4,6})\.\.(\h{4,6}) *(;.+)/ # deal with Unicode ranges in emoji-sequences.txt (Bug #18028) + range_start = $1.to_i(16) + range_end = $2.to_i(16) + rest = $3 + (range_start..range_end).each do |code_point| + file_tests << BreakTest.new(file.basename, $., *(code_point.to_s(16)+rest).split('#', 2)) + end + else + file_tests << BreakTest.new(file.basename, $., *line.split('#', 2)) end - else - file_tests << BreakTest.new(file.basename, $., *line.split('#', 2)) end + raise "File Version Mismatch: file: #{file.fullname}, version: #{file.version}" if version_mismatch + tests += file_tests end - raise "File Version Mismatch: file: #{file.fullname}, version: #{file.version}" if version_mismatch - tests += file_tests + tests end - tests - end - - def all_tests - @@tests ||= read_data - rescue Errno::ENOENT - @@tests ||= [] - end - def test_single_emoji - all_tests.each do |test| - expected = [test.string] - actual = test.string.each_grapheme_cluster.to_a - assert_equal expected, actual, - "file: #{test.filename}, line #{test.line_number}, " + - "type: #{test.type}, shortname: #{test.shortname}, comment: #{test.comment}" + def all_tests + @@tests ||= read_data + rescue Errno::ENOENT + @@tests ||= [] end - end - def test_embedded_emoji - all_tests.each do |test| - expected = ["\t", test.string, "\t"] - actual = "\t#{test.string}\t".each_grapheme_cluster.to_a - assert_equal expected, actual, - "file: #{test.filename}, line #{test.line_number}, " + - "type: #{test.type}, shortname: #{test.shortname}, comment: #{test.comment}" + def test_single_emoji + all_tests.each do |test| + expected = [test.string] + actual = test.string.each_grapheme_cluster.to_a + assert_equal expected, actual, + "file: #{test.filename}, line #{test.line_number}, " + + "type: #{test.type}, shortname: #{test.shortname}, comment: #{test.comment}" + end end - end - # test some pseodorandom combinations of emoji - def test_mixed_emoji - srand 0 - length = all_tests.length - step = 503 # use a prime number - all_tests.each do |test1| - start = rand step - start.step(by: step, to: length-1) do |t2| - test2 = all_tests[t2] - # exclude skin tones, because they glue to previous grapheme clusters - next if (0x1F3FB..0x1F3FF).include? test2.string.ord - expected = [test1.string, test2.string] - actual = (test1.string+test2.string).each_grapheme_cluster.to_a + def test_embedded_emoji + all_tests.each do |test| + expected = ["\t", test.string, "\t"] + actual = "\t#{test.string}\t".each_grapheme_cluster.to_a assert_equal expected, actual, - "file1: #{test1.filename}, line1 #{test1.line_number}, " + - "file2: #{test2.filename}, line2 #{test2.line_number},\n" + - "type1: #{test1.type}, shortname1: #{test1.shortname}, comment1: #{test1.comment},\n" + - "type2: #{test2.type}, shortname2: #{test2.shortname}, comment2: #{test2.comment}" + "file: #{test.filename}, line #{test.line_number}, " + + "type: #{test.type}, shortname: #{test.shortname}, comment: #{test.comment}" + end + end + + # test some pseodorandom combinations of emoji + def test_mixed_emoji + srand 0 + length = all_tests.length + step = 503 # use a prime number + all_tests.each do |test1| + start = rand step + start.step(by: step, to: length-1) do |t2| + test2 = all_tests[t2] + # exclude skin tones, because they glue to previous grapheme clusters + next if (0x1F3FB..0x1F3FF).include? test2.string.ord + expected = [test1.string, test2.string] + actual = (test1.string+test2.string).each_grapheme_cluster.to_a + assert_equal expected, actual, + "file1: #{test1.filename}, line1 #{test1.line_number}, " + + "file2: #{test2.filename}, line2 #{test2.line_number},\n" + + "type1: #{test1.type}, shortname1: #{test1.shortname}, comment1: #{test1.comment},\n" + + "type2: #{test2.type}, shortname2: #{test2.shortname}, comment2: #{test2.comment}" + end end end end diff --git a/test/ruby/enc/test_grapheme_breaks.rb b/test/ruby/enc/test_grapheme_breaks.rb index 2d210946a9..f4e3c93b47 100644 --- a/test/ruby/enc/test_grapheme_breaks.rb +++ b/test/ruby/enc/test_grapheme_breaks.rb @@ -4,31 +4,28 @@ require "test/unit" class TestGraphemeBreaksFromFile < Test::Unit::TestCase -end - -class TestGraphemeBreaksFromFile::BreakTest - attr_reader :clusters, :string, :comment, :line_number + class BreakTest + attr_reader :clusters, :string, :comment, :line_number - def initialize(line_number, data, comment) - @line_number = line_number - @comment = comment - @clusters = data.sub(/\A\s*÷\s*/, '') - .sub(/\s*÷\s*\z/, '') - .split(/\s*÷\s*/) - .map do |cl| - cl.split(/\s*×\s*/) - .map do |ch| - c = ch.to_i(16) - # eliminate cases with surrogates - raise ArgumentError if 0xD800 <= c and c <= 0xDFFF - c.chr('UTF-8') - end.join - end - @string = @clusters.join + def initialize(line_number, data, comment) + @line_number = line_number + @comment = comment + @clusters = data.sub(/\A\s*÷\s*/, '') + .sub(/\s*÷\s*\z/, '') + .split(/\s*÷\s*/) + .map do |cl| + cl.split(/\s*×\s*/) + .map do |ch| + c = ch.to_i(16) + # eliminate cases with surrogates + raise ArgumentError if 0xD800 <= c and c <= 0xDFFF + c.chr('UTF-8') + end.join + end + @string = @clusters.join + end end -end -class TestGraphemeBreaksFromFile < Test::Unit::TestCase UNICODE_VERSION = RbConfig::CONFIG['UNICODE_VERSION'] path = File.expand_path("../../../enc/unicode/data/#{UNICODE_VERSION}", __dir__) UNICODE_DATA_PATH = File.directory?("#{path}/ucd/auxiliary") ? "#{path}/ucd/auxiliary" : path @@ -40,56 +37,56 @@ class TestGraphemeBreaksFromFile < Test::Unit::TestCase def test_data_files_available unless TestGraphemeBreaksFromFile.file_available? - skip "Unicode data file GraphemeBreakTest not available in #{UNICODE_DATA_PATH}." + omit "Unicode data file GraphemeBreakTest not available in #{UNICODE_DATA_PATH}." end end -end -TestGraphemeBreaksFromFile.file_available? and class TestGraphemeBreaksFromFile - def read_data - tests = [] - IO.foreach(GRAPHEME_BREAK_TEST_FILE, encoding: Encoding::UTF_8) do |line| - if $. == 1 and not line.start_with?("# GraphemeBreakTest-#{UNICODE_VERSION}.txt") - raise "File Version Mismatch" + if file_available? + def read_data + tests = [] + IO.foreach(GRAPHEME_BREAK_TEST_FILE, encoding: Encoding::UTF_8) do |line| + if $. == 1 and not line.start_with?("# GraphemeBreakTest-#{UNICODE_VERSION}.txt") + raise "File Version Mismatch" + end + next if /\A#/.match? line + tests << BreakTest.new($., *line.chomp.split('#')) rescue 'whatever' end - next if /\A#/.match? line - tests << BreakTest.new($., *line.chomp.split('#')) rescue 'whatever' + tests end - tests - end - def all_tests - @@tests ||= read_data - rescue Errno::ENOENT - @@tests ||= [] - end + def all_tests + @@tests ||= read_data + rescue Errno::ENOENT + @@tests ||= [] + end - def test_each_grapheme_cluster - all_tests.each do |test| - expected = test.clusters - actual = test.string.each_grapheme_cluster.to_a - assert_equal expected, actual, - "line #{test.line_number}, expected '#{expected}', " + - "but got '#{actual}', comment: #{test.comment}" + def test_each_grapheme_cluster + all_tests.each do |test| + expected = test.clusters + actual = test.string.each_grapheme_cluster.to_a + assert_equal expected, actual, + "line #{test.line_number}, expected '#{expected}', " + + "but got '#{actual}', comment: #{test.comment}" + end end - end - def test_backslash_X - all_tests.each do |test| - clusters = test.clusters.dup - string = test.string.dup - removals = 0 - while string.sub!(/\A\X/, '') - removals += 1 - clusters.shift - expected = clusters.join + def test_backslash_X + all_tests.each do |test| + clusters = test.clusters.dup + string = test.string.dup + removals = 0 + while string.sub!(/\A\X/, '') + removals += 1 + clusters.shift + expected = clusters.join + assert_equal expected, string, + "line #{test.line_number}, removals: #{removals}, expected '#{expected}', " + + "but got '#{string}', comment: #{test.comment}" + end assert_equal expected, string, - "line #{test.line_number}, removals: #{removals}, expected '#{expected}', " + + "line #{test.line_number}, after last removal, expected '#{expected}', " + "but got '#{string}', comment: #{test.comment}" end - assert_equal expected, string, - "line #{test.line_number}, after last removal, expected '#{expected}', " + - "but got '#{string}', comment: #{test.comment}" end end end diff --git a/test/ruby/enc/test_regex_casefold.rb b/test/ruby/enc/test_regex_casefold.rb index ec5dc7f220..eaabbc58a2 100644 --- a/test/ruby/enc/test_regex_casefold.rb +++ b/test/ruby/enc/test_regex_casefold.rb @@ -39,7 +39,7 @@ class TestCaseFold < Test::Unit::TestCase @@tests ||= read_tests rescue Errno::ENOENT => e @@tests ||= [] - skip e.message + omit e.message end def self.generate_test_casefold(encoding) diff --git a/test/ruby/test_alias.rb b/test/ruby/test_alias.rb index 271d552bf5..0d33cb993c 100644 --- a/test/ruby/test_alias.rb +++ b/test/ruby/test_alias.rb @@ -253,4 +253,43 @@ class TestAlias < Test::Unit::TestCase assert_equal(:foo, k.instance_method(:bar).original_name) assert_equal(:foo, name) end + + def test_alias_suppressing_redefinition + assert_in_out_err(%w[-w], "#{<<~"begin;"}\n#{<<~'end;'}") + begin; + class A + def foo; end + alias foo foo + def foo; end + end + end; + end + + class C2 + public :system + alias_method :bar, :system + alias_method :system, :bar + end + + def test_zsuper_alias_visibility + assert(C2.new.respond_to?(:system)) + end + + def test_alias_memory_leak + assert_no_memory_leak([], "#{<<~"begin;"}", "#{<<~'end;'}", rss: true) + begin; + class A + 500.times do + 1000.times do |i| + define_method(:"foo_#{i}") {} + + alias :"foo_#{i}" :"foo_#{i}" + + remove_method :"foo_#{i}" + end + GC.start + end + end + end; + end end diff --git a/test/ruby/test_argf.rb b/test/ruby/test_argf.rb index e3bd1cd075..dbffd24370 100644 --- a/test/ruby/test_argf.rb +++ b/test/ruby/test_argf.rb @@ -257,13 +257,13 @@ class TestArgf < Test::Unit::TestCase def test_inplace_nonascii ext = Encoding.default_external or - skip "no default external encoding" + omit "no default external encoding" t = nil ["\u{3042}", "\u{e9}"].any? do |n| t = make_tempfile(n.encode(ext)) rescue Encoding::UndefinedConversionError end - t or skip "no name to test" + t or omit "no name to test" assert_in_out_err(["-i.bak", "-", t.path], "#{<<~"{#"}\n#{<<~'};'}") {# diff --git a/test/ruby/test_arity.rb b/test/ruby/test_arity.rb index b98248f603..d26338e0aa 100644 --- a/test/ruby/test_arity.rb +++ b/test/ruby/test_arity.rb @@ -2,7 +2,7 @@ require 'test/unit' class TestArity < Test::Unit::TestCase - def err_mess(method_proc = nil, argc = 0) + def assert_arity(expected, method_proc = nil, argc = 0) args = (1..argc).to_a assert_raise_with_message(ArgumentError, /wrong number of arguments \(.*\b(\d+)\b.* (\d\S*?)\)/) do case method_proc @@ -14,7 +14,7 @@ class TestArity < Test::Unit::TestCase method_proc.call(*args) end end - [$1, $2] + assert_equal expected, [$1, $2] end def a @@ -36,22 +36,22 @@ class TestArity < Test::Unit::TestCase end def test_method_err_mess - assert_equal %w[1 0], err_mess(:a, 1) - assert_equal %w[10 7..9], err_mess(:b, 10) - assert_equal %w[2 3+], err_mess(:c, 2) - assert_equal %w[2 1], err_mess(:d, 2) - assert_equal %w[0 1], err_mess(:d, 0) - assert_equal %w[2 1], err_mess(:e, 2) - assert_equal %w[0 1], err_mess(:e, 0) - assert_equal %w[1 2+], err_mess(:f, 1) + assert_arity(%w[1 0], :a, 1) + assert_arity(%w[10 7..9], :b, 10) + assert_arity(%w[2 3+], :c, 2) + assert_arity(%w[2 1], :d, 2) + assert_arity(%w[0 1], :d, 0) + assert_arity(%w[2 1], :e, 2) + assert_arity(%w[0 1], :e, 0) + assert_arity(%w[1 2+], :f, 1) end def test_proc_err_mess - assert_equal %w[0 1..2], err_mess(->(b, c=42){}, 0) - assert_equal %w[1 2+], err_mess(->(a, b, c=42, *d){}, 1) - assert_equal %w[3 4+], err_mess(->(a, b, *c, d, e){}, 3) - assert_equal %w[3 1..2], err_mess(->(b, c=42){}, 3) - assert_equal %w[1 0], err_mess(->(&block){}, 1) + assert_arity(%w[0 1..2], ->(b, c=42){}, 0) + assert_arity(%w[1 2+], ->(a, b, c=42, *d){}, 1) + assert_arity(%w[3 4+], ->(a, b, *c, d, e){}, 3) + assert_arity(%w[3 1..2], ->(b, c=42){}, 3) + assert_arity(%w[1 0], ->(&block){}, 1) # Double checking: p = Proc.new{|b, c=42| :ok} assert_equal :ok, p.call(1, 2, 3) @@ -59,12 +59,12 @@ class TestArity < Test::Unit::TestCase end def test_message_change_issue_6085 - assert_equal %w[3 1..2], err_mess{ SignalException.new(1, "", nil) } - assert_equal %w[1 0], err_mess{ Hash.new(1){} } - assert_equal %w[3 1..2], err_mess{ Module.send :define_method, 1, 2, 3 } - assert_equal %w[1 2], err_mess{ "".sub!(//) } - assert_equal %w[0 1..2], err_mess{ "".sub!{} } - assert_equal %w[0 1+], err_mess{ exec } - assert_equal %w[0 1+], err_mess{ Struct.new } + assert_arity(%w[3 1..2]) { SignalException.new(1, "", nil) } + assert_arity(%w[1 0]) { Hash.new(1){} } + assert_arity(%w[3 1..2]) { Module.send :define_method, 1, 2, 3 } + assert_arity(%w[1 2]) { "".sub!(//) } + assert_arity(%w[0 1..2]) { "".sub!{} } + assert_arity(%w[0 1+]) { exec } + assert_arity(%w[0 1+]) { Struct.new } end end diff --git a/test/ruby/test_array.rb b/test/ruby/test_array.rb index a97a9c2558..e376d76a16 100644 --- a/test/ruby/test_array.rb +++ b/test/ruby/test_array.rb @@ -1439,6 +1439,14 @@ class TestArray < Test::Unit::TestCase assert_raise(FrozenError) { fa.replace(42) } end + def test_replace_wb_variable_width_alloc + small_embed = [] + 4.times { GC.start } # age small_embed + large_embed = [1, 2, 3, 4, 5, Array.new] # new young object + small_embed.replace(large_embed) # adds old to young reference + GC.verify_internal_consistency + end + def test_reverse a = @cls[*%w( dog cat bee ant )] assert_equal(@cls[*%w(ant bee cat dog)], a.reverse) @@ -3270,7 +3278,7 @@ class TestArray < Test::Unit::TestCase end EOS rescue Timeout::Error => e - skip e.message + omit e.message end end diff --git a/test/ruby/test_assignment.rb b/test/ruby/test_assignment.rb index 41e8bffe82..3a8dafb7f0 100644 --- a/test/ruby/test_assignment.rb +++ b/test/ruby/test_assignment.rb @@ -139,6 +139,104 @@ class TestAssignment < Test::Unit::TestCase order.clear end + def test_massign_const_order + order = [] + + test_mod_class = Class.new(Module) do + define_method(:x1){order << :x1; self} + define_method(:y1){order << :y1; self} + define_method(:x2){order << :x2; self} + define_method(:x3){order << :x3; self} + define_method(:x4){order << :x4; self} + define_method(:[]){|*args| order << [:[], *args]; self} + define_method(:r1){order << :r1; :r1} + define_method(:r2){order << :r2; :r2} + + define_method(:constant_values) do + h = {} + constants.each do |sym| + h[sym] = const_get(sym) + end + h + end + + define_singleton_method(:run) do |code| + m = new + m.instance_eval(code) + ret = [order.dup, m.constant_values] + order.clear + ret + end + end + + ord, constants = test_mod_class.run( + "x1.y1::A, x2[1, 2, 3]::B, self[4]::C = r1, 6, r2" + ) + assert_equal([:x1, :y1, :x2, [:[], 1, 2, 3], [:[], 4], :r1, :r2], ord) + assert_equal({:A=>:r1, :B=>6, :C=>:r2}, constants) + + ord, constants = test_mod_class.run( + "x1.y1::A, *x2[1, 2, 3]::B, self[4]::C = r1, 6, 7, r2" + ) + assert_equal([:x1, :y1, :x2, [:[], 1, 2, 3], [:[], 4], :r1, :r2], ord) + assert_equal({:A=>:r1, :B=>[6, 7], :C=>:r2}, constants) + + ord, constants = test_mod_class.run( + "x1.y1::A, *x2[1, 2, 3]::B, x3[4]::C = r1, 6, 7, r2" + ) + assert_equal([:x1, :y1, :x2, [:[], 1, 2, 3], :x3, [:[], 4], :r1, :r2], ord) + assert_equal({:A=>:r1, :B=>[6, 7], :C=>:r2}, constants) + + + ord, constants = test_mod_class.run( + "x1.y1::A, *x2[1, 2, 3]::B, x3[4]::C, x4::D = r1, 6, 7, r2, 8" + ) + assert_equal([:x1, :y1, :x2, [:[], 1, 2, 3], :x3, [:[], 4], :x4, :r1, :r2], ord) + assert_equal({:A=>:r1, :B=>[6, 7], :C=>:r2, :D=>8}, constants) + + ord, constants = test_mod_class.run( + "(x1.y1::A, x2::B), _a = [r1, r2], 7" + ) + assert_equal([:x1, :y1, :x2, :r1, :r2], ord) + assert_equal({:A=>:r1, :B=>:r2}, constants) + + ord, constants = test_mod_class.run( + "(x1.y1::A, x1::B), *x2[1, 2, 3]::C = [r1, 5], 6, 7, r2, 8" + ) + assert_equal([:x1, :y1, :x1, :x2, [:[], 1, 2, 3], :r1, :r2], ord) + assert_equal({:A=>:r1, :B=>5, :C=>[6, 7, :r2, 8]}, constants) + + ord, constants = test_mod_class.run( + "*x2[1, 2, 3]::A, (x3[4]::B, x4::C) = 6, 7, [r2, 8]" + ) + assert_equal([:x2, [:[], 1, 2, 3], :x3, [:[], 4], :x4, :r2], ord) + assert_equal({:A=>[6, 7], :B=>:r2, :C=>8}, constants) + + ord, constants = test_mod_class.run( + "(x1.y1::A, x1::B), *x2[1, 2, 3]::C, x3[4]::D, x4::E = [r1, 5], 6, 7, r2, 8" + ) + assert_equal([:x1, :y1, :x1, :x2, [:[], 1, 2, 3], :x3, [:[], 4], :x4, :r1, :r2], ord) + assert_equal({:A=>:r1, :B=>5, :C=>[6, 7], :D=>:r2, :E=>8}, constants) + + ord, constants = test_mod_class.run( + "(x1.y1::A, x1::B), *x2[1, 2, 3]::C, (x3[4]::D, x4::E) = [r1, 5], 6, 7, [r2, 8]" + ) + assert_equal([:x1, :y1, :x1, :x2, [:[], 1, 2, 3], :x3, [:[], 4], :x4, :r1, :r2], ord) + assert_equal({:A=>:r1, :B=>5, :C=>[6, 7], :D=>:r2, :E=>8}, constants) + + ord, constants = test_mod_class.run( + "((x1.y1::A, x1::B), _a), *x2[1, 2, 3]::C, ((x3[4]::D, x4::E), _b) = [[r1, 5], 10], 6, 7, [[r2, 8], 11]" + ) + assert_equal([:x1, :y1, :x1, :x2, [:[], 1, 2, 3], :x3, [:[], 4], :x4, :r1, :r2], ord) + assert_equal({:A=>:r1, :B=>5, :C=>[6, 7], :D=>:r2, :E=>8}, constants) + + ord, constants = test_mod_class.run( + "((x1.y1::A, x1::B), _a), *x2[1, 2, 3]::C, ((*x3[4]::D, x4::E), _b) = [[r1, 5], 10], 6, 7, [[r2, 8], 11]" + ) + assert_equal([:x1, :y1, :x1, :x2, [:[], 1, 2, 3], :x3, [:[], 4], :x4, :r1, :r2], ord) + assert_equal({:A=>:r1, :B=>5, :C=>[6, 7], :D=>[:r2], :E=>8}, constants) + end + def test_massign_splat a,b,*c = *[]; assert_equal([nil,nil,[]], [a,b,c]) a,b,*c = *[1]; assert_equal([1,nil,[]], [a,b,c]) @@ -619,6 +717,16 @@ class TestAssignment < Test::Unit::TestCase result = eval("if (a, b = MyObj.new); [a, b]; end", nil, __FILE__, __LINE__) assert_equal [[1,2],[3,4]], result end + + def test_const_assign_order + assert_raise(RuntimeError) do + eval('raise("recv")::C = raise(ArgumentError, "bar")') + end + + assert_raise(RuntimeError) do + eval('m = 1; m::C = raise("bar")') + end + end end require_relative 'sentence' diff --git a/test/ruby/test_ast.rb b/test/ruby/test_ast.rb index 953c8435c3..cd96027654 100644 --- a/test/ruby/test_ast.rb +++ b/test/ruby/test_ast.rb @@ -185,7 +185,7 @@ class TestAst < Test::Unit::TestCase end end - def test_of + def test_of_proc_and_method proc = Proc.new { 1 + 2 } method = self.method(__method__) @@ -194,7 +194,6 @@ class TestAst < Test::Unit::TestCase assert_instance_of(RubyVM::AbstractSyntaxTree::Node, node_proc) assert_instance_of(RubyVM::AbstractSyntaxTree::Node, node_method) - assert_raise(TypeError) { RubyVM::AbstractSyntaxTree.of("1 + 2") } Tempfile.create(%w"test_of .rb") do |tmp| tmp.print "#{<<-"begin;"}\n#{<<-'end;'}" @@ -211,7 +210,25 @@ class TestAst < Test::Unit::TestCase end end - def test_of_eval + def sample_backtrace_location + [caller_locations(0).first, __LINE__] + end + + def test_of_backtrace_location + backtrace_location, lineno = sample_backtrace_location + node = RubyVM::AbstractSyntaxTree.of(backtrace_location) + assert_instance_of(RubyVM::AbstractSyntaxTree::Node, node) + assert_equal(lineno, node.first_lineno) + end + + def test_of_error + assert_raise(TypeError) { RubyVM::AbstractSyntaxTree.of("1 + 2") } + end + + def test_of_proc_and_method_under_eval + keep_script_lines_back = RubyVM.keep_script_lines + RubyVM.keep_script_lines = false + method = self.method(eval("def example_method_#{$$}; end")) assert_raise(ArgumentError) { RubyVM::AbstractSyntaxTree.of(method) } @@ -229,6 +246,83 @@ class TestAst < Test::Unit::TestCase method = eval("Class.new{def example_method; end}.instance_method(:example_method)") assert_raise(ArgumentError) { RubyVM::AbstractSyntaxTree.of(method) } + + method = eval("Class.new{def example_method; end}.instance_method(:example_method)") + assert_raise(ArgumentError) { RubyVM::AbstractSyntaxTree.of(method) } + + ensure + RubyVM.keep_script_lines = keep_script_lines_back + end + + def test_of_proc_and_method_under_eval_with_keep_script_lines + pend if ENV['RUBY_ISEQ_DUMP_DEBUG'] # TODO + + keep_script_lines_back = RubyVM.keep_script_lines + RubyVM.keep_script_lines = true + + method = self.method(eval("def example_method_#{$$}_with_keep_script_lines; end")) + assert_instance_of(RubyVM::AbstractSyntaxTree::Node, RubyVM::AbstractSyntaxTree.of(method)) + + method = self.method(eval("def self.example_singleton_method_#{$$}_with_keep_script_lines; end")) + assert_instance_of(RubyVM::AbstractSyntaxTree::Node, RubyVM::AbstractSyntaxTree.of(method)) + + method = eval("proc{}") + assert_instance_of(RubyVM::AbstractSyntaxTree::Node, RubyVM::AbstractSyntaxTree.of(method)) + + method = self.method(eval("singleton_class.define_method(:example_define_method_#{$$}_with_keep_script_lines){}")) + assert_instance_of(RubyVM::AbstractSyntaxTree::Node, RubyVM::AbstractSyntaxTree.of(method)) + + method = self.method(eval("define_singleton_method(:example_dsm_#{$$}_with_keep_script_lines){}")) + assert_instance_of(RubyVM::AbstractSyntaxTree::Node, RubyVM::AbstractSyntaxTree.of(method)) + + method = eval("Class.new{def example_method_with_keep_script_lines; end}.instance_method(:example_method_with_keep_script_lines)") + assert_instance_of(RubyVM::AbstractSyntaxTree::Node, RubyVM::AbstractSyntaxTree.of(method)) + + method = eval("Class.new{def example_method_with_keep_script_lines; end}.instance_method(:example_method_with_keep_script_lines)") + assert_instance_of(RubyVM::AbstractSyntaxTree::Node, RubyVM::AbstractSyntaxTree.of(method)) + + ensure + RubyVM.keep_script_lines = keep_script_lines_back + end + + def test_of_backtrace_location_under_eval + keep_script_lines_back = RubyVM.keep_script_lines + RubyVM.keep_script_lines = false + + m = Module.new do + eval(<<-END, nil, __FILE__, __LINE__) + def self.sample_backtrace_location + caller_locations(0).first + end + END + end + backtrace_location = m.sample_backtrace_location + assert_raise(ArgumentError) { RubyVM::AbstractSyntaxTree.of(backtrace_location) } + + ensure + RubyVM.keep_script_lines = keep_script_lines_back + end + + def test_of_backtrace_location_under_eval_with_keep_script_lines + pend if ENV['RUBY_ISEQ_DUMP_DEBUG'] # TODO + + keep_script_lines_back = RubyVM.keep_script_lines + RubyVM.keep_script_lines = true + + m = Module.new do + eval(<<-END, nil, __FILE__, __LINE__) + def self.sample_backtrace_location + caller_locations(0).first + end + END + end + backtrace_location = m.sample_backtrace_location + node = RubyVM::AbstractSyntaxTree.of(backtrace_location) + assert_instance_of(RubyVM::AbstractSyntaxTree::Node, node) + assert_equal(2, node.first_lineno) + + ensure + RubyVM.keep_script_lines = keep_script_lines_back end def test_of_c_method @@ -447,4 +541,9 @@ dummy assert_equal("{ 1 + 2 }", node_proc.source) assert_equal("def test_keep_script_lines_for_of\n", node_method.source.lines.first) end + + def test_e_option + assert_in_out_err(["-e", "def foo; end; pp RubyVM::AbstractSyntaxTree.of(method(:foo)).type"], + "", [":SCOPE"], []) + end end diff --git a/test/ruby/test_autoload.rb b/test/ruby/test_autoload.rb index 7709760d19..bac6337eb9 100644 --- a/test/ruby/test_autoload.rb +++ b/test/ruby/test_autoload.rb @@ -491,4 +491,53 @@ p Foo::Bar ::Object.class_eval {remove_const(:AutoloadTest)} if defined? Object::AutoloadTest TestAutoload.class_eval {remove_const(:AutoloadTest)} if defined? TestAutoload::AutoloadTest end + + def test_autoload_module_gc + Dir.mktmpdir('autoload') do |tmpdir| + autoload_path = File.join(tmpdir, "autoload_module_gc.rb") + File.write(autoload_path, "X = 1; Y = 2;") + + x = Module.new + x.autoload :X, "./feature.rb" + + 1000.times do + y = Module.new + y.autoload :Y, "./feature.rb" + end + + x = y = nil + + # Ensure the internal data structures are cleaned up correctly / don't crash: + GC.start + end + end + + def test_autoload_parallel_race + Dir.mktmpdir('autoload') do |tmpdir| + autoload_path = File.join(tmpdir, "autoload_parallel_race.rb") + File.write(autoload_path, 'module Foo; end; module Bar; end') + + assert_separately([], <<-RUBY, timeout: 100) + autoload_path = #{File.realpath(autoload_path).inspect} + + # This should work with no errors or failures. + 1000.times do + autoload :Foo, autoload_path + autoload :Bar, autoload_path + + t1 = Thread.new {Foo} + t2 = Thread.new {Bar} + + t1.join + GC.start # force GC. + t2.join + + Object.send(:remove_const, :Foo) + Object.send(:remove_const, :Bar) + + $LOADED_FEATURES.delete(autoload_path) + end + RUBY + end + end end diff --git a/test/ruby/test_backtrace.rb b/test/ruby/test_backtrace.rb index aa79db24cb..bb0562c0bb 100644 --- a/test/ruby/test_backtrace.rb +++ b/test/ruby/test_backtrace.rb @@ -154,6 +154,35 @@ class TestBacktrace < Test::Unit::TestCase assert_equal caller(0), caller(0, nil) end + def test_each_backtrace_location + i = 0 + cl = caller_locations(1, 1)[0]; ecl = Thread.each_caller_location{|x| i+=1; break x if i == 1} + assert_equal(cl.to_s, ecl.to_s) + assert_kind_of(Thread::Backtrace::Location, ecl) + + i = 0 + ary = [] + cllr = caller_locations(1, 2); last = Thread.each_caller_location{|x| ary << x; i+=1; break x if i == 2} + assert_equal(cllr.map(&:to_s), ary.map(&:to_s)) + assert_kind_of(Thread::Backtrace::Location, last) + + i = 0 + ary = [] + ->{->{ + cllr = caller_locations(1, 2); last = Thread.each_caller_location{|x| ary << x; i+=1; break x if i == 2} + }.()}.() + assert_equal(cllr.map(&:to_s), ary.map(&:to_s)) + assert_kind_of(Thread::Backtrace::Location, last) + + cllr = caller_locations(1, 2); ary = Thread.to_enum(:each_caller_location).to_a[2..3] + assert_equal(cllr.map(&:to_s), ary.map(&:to_s)) + + ecl = Thread.to_enum(:each_caller_location) + assert_raise(StopIteration) { + ecl.next + } + end + def test_caller_locations_first_label def self.label caller_locations.first.label diff --git a/test/ruby/test_bignum.rb b/test/ruby/test_bignum.rb index 3ffe7114b5..53a2b20cc8 100644 --- a/test/ruby/test_bignum.rb +++ b/test/ruby/test_bignum.rb @@ -644,7 +644,7 @@ class TestBignum < Test::Unit::TestCase thread.raise thread.join time = Time.now - time - skip "too fast cpu" if end_flag + omit "too fast cpu" if end_flag assert_operator(time, :<, 10) end @@ -675,7 +675,7 @@ class TestBignum < Test::Unit::TestCase return end end - skip "cannot create suitable test case" + omit "cannot create suitable test case" ensure Signal.trap(:INT, oldtrap) if oldtrap end diff --git a/test/ruby/test_class.rb b/test/ruby/test_class.rb index 0ceb36bb1d..07c34ce9d5 100644 --- a/test/ruby/test_class.rb +++ b/test/ruby/test_class.rb @@ -738,38 +738,6 @@ class TestClass < Test::Unit::TestCase assert_same(c, Module.new.const_set(:Foo, c)) end - def test_descendants - c = Class.new - sc = Class.new(c) - ssc = Class.new(sc) - [c, sc, ssc].each do |k| - k.include Module.new - k.new.define_singleton_method(:force_singleton_class){} - end - assert_equal([sc, ssc], c.descendants) - assert_equal([ssc], sc.descendants) - assert_equal([], ssc.descendants) - - object_descendants = Object.descendants - assert_include(object_descendants, c) - assert_include(object_descendants, sc) - assert_include(object_descendants, ssc) - end - - def test_descendants_gc - c = Class.new - 100000.times { Class.new(c) } - assert(c.descendants.size <= 100000) - end - - def test_descendants_gc_stress - 10000.times do - c = Class.new - 100.times { Class.new(c) } - assert(c.descendants.size <= 100) - end - end - def test_subclasses c = Class.new sc = Class.new(c) @@ -793,11 +761,11 @@ class TestClass < Test::Unit::TestCase def test_subclass_gc c = Class.new - 100000.times do + 10_000.times do cc = Class.new(c) 100.times { Class.new(cc) } end - assert(c.subclasses.size <= 100000) + assert(c.subclasses.size <= 10_000) end def test_subclass_gc_stress diff --git a/test/ruby/test_complex2.rb b/test/ruby/test_complex2.rb index 594fc3f45a..b89e83efb2 100644 --- a/test/ruby/test_complex2.rb +++ b/test/ruby/test_complex2.rb @@ -4,7 +4,7 @@ require 'test/unit' class Complex_Test2 < Test::Unit::TestCase def test_kumi - skip unless defined?(Rational) + omit unless defined?(Rational) assert_equal(Complex(1, 0), +Complex(1, 0)) assert_equal(Complex(-1, 0), -Complex(1, 0)) diff --git a/test/ruby/test_complexrational.rb b/test/ruby/test_complexrational.rb index bf4e2b1809..31d11fe317 100644 --- a/test/ruby/test_complexrational.rb +++ b/test/ruby/test_complexrational.rb @@ -4,7 +4,7 @@ require 'test/unit' class ComplexRational_Test < Test::Unit::TestCase def test_rat_srat - skip unless defined?(Rational) + omit unless defined?(Rational) c = SimpleRat(1,3) cc = Rational(3,2) @@ -89,7 +89,7 @@ class ComplexRational_Test < Test::Unit::TestCase end def test_comp_srat - skip unless defined?(Rational) + omit unless defined?(Rational) c = Complex(SimpleRat(2,3),SimpleRat(1,2)) cc = Complex(Rational(3,2),Rational(2,1)) diff --git a/test/ruby/test_default_gems.rb b/test/ruby/test_default_gems.rb index 3c4aea1561..467e5ecf83 100644 --- a/test/ruby/test_default_gems.rb +++ b/test/ruby/test_default_gems.rb @@ -4,7 +4,7 @@ require 'rubygems' class TestDefaultGems < Test::Unit::TestCase def test_validate_gemspec - skip "git not found" unless system("git", "rev-parse", %i[out err]=>IO::NULL) + omit "git not found" unless system("git", "rev-parse", %i[out err]=>IO::NULL) srcdir = File.expand_path('../../..', __FILE__) Dir.glob("#{srcdir}/{lib,ext}/**/*.gemspec").map do |src| assert_nothing_raised do diff --git a/test/ruby/test_dir.rb b/test/ruby/test_dir.rb index 9474c6e927..514c6e5921 100644 --- a/test/ruby/test_dir.rb +++ b/test/ruby/test_dir.rb @@ -152,7 +152,7 @@ class TestDir < Test::Unit::TestCase end def test_chroot_nodir - skip if RUBY_PLATFORM =~ /android/ + omit if RUBY_PLATFORM =~ /android/ assert_raise(NotImplementedError, Errno::ENOENT, Errno::EPERM ) { Dir.chroot(File.join(@nodir, "")) } end @@ -490,9 +490,9 @@ class TestDir < Test::Unit::TestCase def test_glob_legacy_short_name bug10819 = '[ruby-core:67954] [Bug #10819]' bug11206 = '[ruby-core:69435] [Bug #11206]' - skip unless /\A\w:/ =~ ENV["ProgramFiles"] + omit unless /\A\w:/ =~ ENV["ProgramFiles"] short = "#$&/PROGRA~1" - skip unless File.directory?(short) + omit unless File.directory?(short) entries = Dir.glob("#{short}/Common*") assert_not_empty(entries, bug10819) long = File.expand_path(short) diff --git a/test/ruby/test_enum.rb b/test/ruby/test_enum.rb index f6375a4ffc..cc217b05cc 100644 --- a/test/ruby/test_enum.rb +++ b/test/ruby/test_enum.rb @@ -234,6 +234,8 @@ class TestEnumerable < Test::Unit::TestCase assert_equal(24, @obj.inject(2) {|z, x| z * x }) assert_equal(24, assert_warning(/given block not used/) {@obj.inject(2, :*) {|z, x| z * x }}) assert_equal(nil, @empty.inject() {9}) + + assert_raise(ArgumentError) {@obj.inject} end FIXNUM_MIN = RbConfig::LIMITS['FIXNUM_MIN'] @@ -461,6 +463,17 @@ class TestEnumerable < Test::Unit::TestCase empty.first empty.block.call end; + + bug18475 = '[ruby-dev:107059]' + assert_in_out_err([], <<-'end;', [], /unexpected break/, bug18475) + e = Enumerator.new do |g| + Thread.new do + g << 1 + end.join + end + + e.first + end; end def test_sort diff --git a/test/ruby/test_env.rb b/test/ruby/test_env.rb index ea0f367334..87ccd5102b 100644 --- a/test/ruby/test_env.rb +++ b/test/ruby/test_env.rb @@ -503,7 +503,7 @@ class TestEnv < Test::Unit::TestCase end def test_huge_value - if /mswin/ =~ RUBY_PLATFORM || /ucrt/ =~ RbConfig::CONFIG['sitearch'] + if /mswin|ucrt/ =~ RUBY_PLATFORM # On Windows >= Vista each environment variable can be max 32768 characters huge_value = "bar" * 10900 else @@ -578,6 +578,892 @@ class TestEnv < Test::Unit::TestCase assert_nil(e1, bug12475) end + def ignore_case_str + IGNORE_CASE ? "true" : "false" + end + + def str_for_yielding_exception_class(code_str, exception_var: "raised_exception") + <<-"end;" + #{exception_var} = nil + begin + #{code_str} + rescue Exception => e + #{exception_var} = e + end + Ractor.yield #{exception_var}.class + end; + end + + def str_for_assert_raise_on_yielded_exception_class(expected_error_class, ractor_var) + <<-"end;" + error_class = #{ractor_var}.take + assert_raise(#{expected_error_class}) do + if error_class < Exception + raise error_class + end + end + end; + end + + def str_to_yield_invalid_envvar_errors(var_name, code_str) + <<-"end;" + envvars_to_check = [ + "foo\0bar", + "#{'\xa1\xa1'}".force_encoding(Encoding::UTF_16LE), + "foo".force_encoding(Encoding::ISO_2022_JP), + ] + envvars_to_check.each do |#{var_name}| + #{str_for_yielding_exception_class(code_str)} + end + end; + end + + def str_to_receive_invalid_envvar_errors(ractor_var) + <<-"end;" + 3.times do + #{str_for_assert_raise_on_yielded_exception_class(ArgumentError, ractor_var)} + end + end; + end + + STR_DEFINITION_FOR_CHECK = %Q{ + def check(as, bs) + if #{IGNORE_CASE ? "true" : "false"} + as = as.map {|k, v| [k.upcase, v] } + bs = bs.map {|k, v| [k.upcase, v] } + end + assert_equal(as.sort, bs.sort) + end + } + + def test_bracket_in_ractor + assert_ractor(<<-"end;") + r = Ractor.new do + Ractor.yield ENV['test'] + Ractor.yield ENV['TEST'] + ENV['test'] = 'foo' + Ractor.yield ENV['test'] + Ractor.yield ENV['TEST'] + ENV['TEST'] = 'bar' + Ractor.yield ENV['TEST'] + Ractor.yield ENV['test'] + #{str_for_yielding_exception_class("ENV[1]")} + #{str_for_yielding_exception_class("ENV[1] = 'foo'")} + #{str_for_yielding_exception_class("ENV['test'] = 0")} + end + assert_nil(r.take) + assert_nil(r.take) + assert_equal('foo', r.take) + if #{ignore_case_str} + assert_equal('foo', r.take) + else + assert_nil(r.take) + end + assert_equal('bar', r.take) + if #{ignore_case_str} + assert_equal('bar', r.take) + else + assert_equal('foo', r.take) + end + 3.times do + #{str_for_assert_raise_on_yielded_exception_class(TypeError, "r")} + end + end; + end + + def test_dup_in_ractor + assert_ractor(<<-"end;") + r = Ractor.new do + #{str_for_yielding_exception_class("ENV.dup")} + end + #{str_for_assert_raise_on_yielded_exception_class(TypeError, "r")} + end; + end + + def test_clone_in_ractor + assert_ractor(<<-"end;") + r = Ractor.new do + original_warning_state = Warning[:deprecated] + Warning[:deprecated] = false + + begin + Ractor.yield ENV.clone.object_id + Ractor.yield ENV.clone(freeze: false).object_id + Ractor.yield ENV.clone(freeze: nil).object_id + + #{str_for_yielding_exception_class("ENV.clone(freeze: true)")} + #{str_for_yielding_exception_class("ENV.clone(freeze: 1)")} + #{str_for_yielding_exception_class("ENV.clone(foo: false)")} + #{str_for_yielding_exception_class("ENV.clone(1)")} + #{str_for_yielding_exception_class("ENV.clone(1, foo: false)")} + + ensure + Warning[:deprecated] = original_warning_state + end + end + assert_equal(ENV.object_id, r.take) + assert_equal(ENV.object_id, r.take) + assert_equal(ENV.object_id, r.take) + #{str_for_assert_raise_on_yielded_exception_class(TypeError, "r")} + 4.times do + #{str_for_assert_raise_on_yielded_exception_class(ArgumentError, "r")} + end + end; + end + + def test_has_value_in_ractor + assert_ractor(<<-"end;") + r = Ractor.new do + val = 'a' + val.succ! while ENV.has_value?(val) || ENV.has_value?(val.upcase) + ENV['test'] = val[0...-1] + Ractor.yield(ENV.has_value?(val)) + Ractor.yield(ENV.has_value?(val.upcase)) + ENV['test'] = val + Ractor.yield(ENV.has_value?(val)) + Ractor.yield(ENV.has_value?(val.upcase)) + ENV['test'] = val.upcase + Ractor.yield ENV.has_value?(val) + Ractor.yield ENV.has_value?(val.upcase) + end + assert_equal(false, r.take) + assert_equal(false, r.take) + assert_equal(true, r.take) + assert_equal(false, r.take) + assert_equal(false, r.take) + assert_equal(true, r.take) + end; + end + + def test_key_in_ractor + assert_ractor(<<-"end;") + r = Ractor.new do + val = 'a' + val.succ! while ENV.has_value?(val) || ENV.has_value?(val.upcase) + ENV['test'] = val[0...-1] + Ractor.yield ENV.key(val) + Ractor.yield ENV.key(val.upcase) + ENV['test'] = val + Ractor.yield ENV.key(val) + Ractor.yield ENV.key(val.upcase) + ENV['test'] = val.upcase + Ractor.yield ENV.key(val) + Ractor.yield ENV.key(val.upcase) + end + assert_nil(r.take) + assert_nil(r.take) + if #{ignore_case_str} + assert_equal('TEST', r.take.upcase) + else + assert_equal('test', r.take) + end + assert_nil(r.take) + assert_nil(r.take) + if #{ignore_case_str} + assert_equal('TEST', r.take.upcase) + else + assert_equal('test', r.take) + end + end; + + end + + def test_delete_in_ractor + assert_ractor(<<-"end;") + r = Ractor.new do + #{str_to_yield_invalid_envvar_errors("v", "ENV.delete(v)")} + Ractor.yield ENV.delete("TEST") + #{str_for_yielding_exception_class("ENV.delete('#{PATH_ENV}')")} + Ractor.yield(ENV.delete("TEST"){|name| "NO "+name}) + end + #{str_to_receive_invalid_envvar_errors("r")} + assert_nil(r.take) + exception_class = r.take + assert_equal(NilClass, exception_class) + assert_equal("NO TEST", r.take) + end; + end + + def test_getenv_in_ractor + assert_ractor(<<-"end;") + r = Ractor.new do + #{str_to_yield_invalid_envvar_errors("v", "ENV[v]")} + ENV["#{PATH_ENV}"] = "" + Ractor.yield ENV["#{PATH_ENV}"] + Ractor.yield ENV[""] + end + #{str_to_receive_invalid_envvar_errors("r")} + assert_equal("", r.take) + assert_nil(r.take) + end; + end + + def test_fetch_in_ractor + assert_ractor(<<-"end;") + r = Ractor.new do + ENV["test"] = "foo" + Ractor.yield ENV.fetch("test") + ENV.delete("test") + #{str_for_yielding_exception_class("ENV.fetch('test')", exception_var: "ex")} + Ractor.yield ex.receiver.object_id + Ractor.yield ex.key + Ractor.yield ENV.fetch("test", "foo") + Ractor.yield(ENV.fetch("test"){"bar"}) + #{str_to_yield_invalid_envvar_errors("v", "ENV.fetch(v)")} + #{str_for_yielding_exception_class("ENV.fetch('#{PATH_ENV}', 'foo')")} + ENV['#{PATH_ENV}'] = "" + Ractor.yield ENV.fetch('#{PATH_ENV}') + end + assert_equal("foo", r.take) + #{str_for_assert_raise_on_yielded_exception_class(KeyError, "r")} + assert_equal(ENV.object_id, r.take) + assert_equal("test", r.take) + assert_equal("foo", r.take) + assert_equal("bar", r.take) + #{str_to_receive_invalid_envvar_errors("r")} + exception_class = r.take + assert_equal(NilClass, exception_class) + assert_equal("", r.take) + end; + end + + def test_aset_in_ractor + assert_ractor(<<-"end;") + r = Ractor.new do + #{str_for_yielding_exception_class("ENV['test'] = nil")} + ENV["test"] = nil + Ractor.yield ENV["test"] + #{str_to_yield_invalid_envvar_errors("v", "ENV[v] = 'test'")} + #{str_to_yield_invalid_envvar_errors("v", "ENV['test'] = v")} + end + exception_class = r.take + assert_equal(NilClass, exception_class) + assert_nil(r.take) + #{str_to_receive_invalid_envvar_errors("r")} + #{str_to_receive_invalid_envvar_errors("r")} + end; + end + + def test_keys_in_ractor + assert_ractor(<<-"end;") + r = Ractor.new do + a = ENV.keys + Ractor.yield a + end + a = r.take + assert_kind_of(Array, a) + a.each {|k| assert_kind_of(String, k) } + end; + + end + + def test_each_key_in_ractor + assert_ractor(<<-"end;") + r = Ractor.new do + ENV.each_key {|k| Ractor.yield(k)} + Ractor.yield "finished" + end + while((x=r.take) != "finished") + assert_kind_of(String, x) + end + end; + end + + def test_values_in_ractor + assert_ractor(<<-"end;") + r = Ractor.new do + a = ENV.values + Ractor.yield a + end + a = r.take + assert_kind_of(Array, a) + a.each {|k| assert_kind_of(String, k) } + end; + end + + def test_each_value_in_ractor + assert_ractor(<<-"end;") + r = Ractor.new do + ENV.each_value {|k| Ractor.yield(k)} + Ractor.yield "finished" + end + while((x=r.take) != "finished") + assert_kind_of(String, x) + end + end; + end + + def test_each_pair_in_ractor + assert_ractor(<<-"end;") + r = Ractor.new do + ENV.each_pair {|k, v| Ractor.yield([k,v])} + Ractor.yield "finished" + end + while((k,v=r.take) != "finished") + assert_kind_of(String, k) + assert_kind_of(String, v) + end + end; + end + + def test_reject_bang_in_ractor + assert_ractor(<<-"end;") + r = Ractor.new do + h1 = {} + ENV.each_pair {|k, v| h1[k] = v } + ENV["test"] = "foo" + ENV.reject! {|k, v| #{ignore_case_str} ? k.upcase == "TEST" : k == "test" } + h2 = {} + ENV.each_pair {|k, v| h2[k] = v } + Ractor.yield [h1, h2] + Ractor.yield(ENV.reject! {|k, v| #{ignore_case_str} ? k.upcase == "TEST" : k == "test" }) + end + h1, h2 = r.take + assert_equal(h1, h2) + assert_nil(r.take) + end; + end + + def test_delete_if_in_ractor + assert_ractor(<<-"end;") + r = Ractor.new do + h1 = {} + ENV.each_pair {|k, v| h1[k] = v } + ENV["test"] = "foo" + ENV.delete_if {|k, v| #{ignore_case_str} ? k.upcase == "TEST" : k == "test" } + h2 = {} + ENV.each_pair {|k, v| h2[k] = v } + Ractor.yield [h1, h2] + Ractor.yield (ENV.delete_if {|k, v| #{ignore_case_str} ? k.upcase == "TEST" : k == "test" }).object_id + end + h1, h2 = r.take + assert_equal(h1, h2) + assert_equal(ENV.object_id, r.take) + end; + end + + def test_select_bang_in_ractor + assert_ractor(<<-"end;") + r = Ractor.new do + h1 = {} + ENV.each_pair {|k, v| h1[k] = v } + ENV["test"] = "foo" + ENV.select! {|k, v| #{ignore_case_str} ? k.upcase != "TEST" : k != "test" } + h2 = {} + ENV.each_pair {|k, v| h2[k] = v } + Ractor.yield [h1, h2] + Ractor.yield(ENV.select! {|k, v| #{ignore_case_str} ? k.upcase != "TEST" : k != "test" }) + end + h1, h2 = r.take + assert_equal(h1, h2) + assert_nil(r.take) + end; + end + + def test_filter_bang_in_ractor + assert_ractor(<<-"end;") + r = Ractor.new do + h1 = {} + ENV.each_pair {|k, v| h1[k] = v } + ENV["test"] = "foo" + ENV.filter! {|k, v| #{ignore_case_str} ? k.upcase != "TEST" : k != "test" } + h2 = {} + ENV.each_pair {|k, v| h2[k] = v } + Ractor.yield [h1, h2] + Ractor.yield(ENV.filter! {|k, v| #{ignore_case_str} ? k.upcase != "TEST" : k != "test" }) + end + h1, h2 = r.take + assert_equal(h1, h2) + assert_nil(r.take) + end; + end + + def test_keep_if_in_ractor + assert_ractor(<<-"end;") + r = Ractor.new do + h1 = {} + ENV.each_pair {|k, v| h1[k] = v } + ENV["test"] = "foo" + ENV.keep_if {|k, v| #{ignore_case_str} ? k.upcase != "TEST" : k != "test" } + h2 = {} + ENV.each_pair {|k, v| h2[k] = v } + Ractor.yield [h1, h2] + Ractor.yield (ENV.keep_if {|k, v| #{ignore_case_str} ? k.upcase != "TEST" : k != "test" }).object_id + end + h1, h2 = r.take + assert_equal(h1, h2) + assert_equal(ENV.object_id, r.take) + end; + end + + def test_values_at_in_ractor + assert_ractor(<<-"end;") + r = Ractor.new do + ENV["test"] = "foo" + Ractor.yield ENV.values_at("test", "test") + end + assert_equal(["foo", "foo"], r.take) + end; + end + + def test_select_in_ractor + assert_ractor(<<-"end;") + r = Ractor.new do + ENV["test"] = "foo" + h = ENV.select {|k| #{ignore_case_str} ? k.upcase == "TEST" : k == "test" } + Ractor.yield h.size + k = h.keys.first + v = h.values.first + Ractor.yield [k, v] + end + assert_equal(1, r.take) + k, v = r.take + if #{ignore_case_str} + assert_equal("TEST", k.upcase) + assert_equal("FOO", v.upcase) + else + assert_equal("test", k) + assert_equal("foo", v) + end + end; + end + + def test_filter_in_ractor + assert_ractor(<<-"end;") + r = Ractor.new do + ENV["test"] = "foo" + h = ENV.filter {|k| #{ignore_case_str} ? k.upcase == "TEST" : k == "test" } + Ractor.yield(h.size) + k = h.keys.first + v = h.values.first + Ractor.yield [k, v] + end + assert_equal(1, r.take) + k, v = r.take + if #{ignore_case_str} + assert_equal("TEST", k.upcase) + assert_equal("FOO", v.upcase) + else + assert_equal("test", k) + assert_equal("foo", v) + end + end; + end + + def test_slice_in_ractor + assert_ractor(<<-"end;") + r = Ractor.new do + ENV.clear + ENV["foo"] = "bar" + ENV["baz"] = "qux" + ENV["bar"] = "rab" + Ractor.yield(ENV.slice()) + Ractor.yield(ENV.slice("")) + Ractor.yield(ENV.slice("unknown")) + Ractor.yield(ENV.slice("foo", "baz")) + end + assert_equal({}, r.take) + assert_equal({}, r.take) + assert_equal({}, r.take) + assert_equal({"foo"=>"bar", "baz"=>"qux"}, r.take) + end; + end + + def test_except_in_ractor + assert_ractor(<<-"end;") + r = Ractor.new do + ENV.clear + ENV["foo"] = "bar" + ENV["baz"] = "qux" + ENV["bar"] = "rab" + Ractor.yield ENV.except() + Ractor.yield ENV.except("") + Ractor.yield ENV.except("unknown") + Ractor.yield ENV.except("foo", "baz") + end + assert_equal({"bar"=>"rab", "baz"=>"qux", "foo"=>"bar"}, r.take) + assert_equal({"bar"=>"rab", "baz"=>"qux", "foo"=>"bar"}, r.take) + assert_equal({"bar"=>"rab", "baz"=>"qux", "foo"=>"bar"}, r.take) + assert_equal({"bar"=>"rab"}, r.take) + end; + end + + def test_clear_in_ractor + assert_ractor(<<-"end;") + r = Ractor.new do + ENV.clear + Ractor.yield ENV.size + end + assert_equal(0, r.take) + end; + end + + def test_to_s_in_ractor + assert_ractor(<<-"end;") + r = Ractor.new do + ENV.to_s + end + assert_equal("ENV", r.take) + end; + end + + def test_inspect_in_ractor + assert_ractor(<<-"end;") + r = Ractor.new do + ENV.clear + ENV["foo"] = "bar" + ENV["baz"] = "qux" + s = ENV.inspect + Ractor.yield s + end + s = r.take + if #{ignore_case_str} + s = s.upcase + assert(s == '{"FOO"=>"BAR", "BAZ"=>"QUX"}' || s == '{"BAZ"=>"QUX", "FOO"=>"BAR"}') + else + assert(s == '{"foo"=>"bar", "baz"=>"qux"}' || s == '{"baz"=>"qux", "foo"=>"bar"}') + end + end; + end + + def test_to_a_in_ractor + assert_ractor(<<-"end;") + r = Ractor.new do + ENV.clear + ENV["foo"] = "bar" + ENV["baz"] = "qux" + a = ENV.to_a + Ractor.yield a + end + a = r.take + assert_equal(2, a.size) + if #{ignore_case_str} + a = a.map {|x| x.map {|y| y.upcase } } + assert(a == [%w(FOO BAR), %w(BAZ QUX)] || a == [%w(BAZ QUX), %w(FOO BAR)]) + else + assert(a == [%w(foo bar), %w(baz qux)] || a == [%w(baz qux), %w(foo bar)]) + end + end; + end + + def test_rehash_in_ractor + assert_ractor(<<-"end;") + r = Ractor.new do + ENV.rehash + end + assert_nil(r.take) + end; + end + + def test_size_in_ractor + assert_ractor(<<-"end;") + r = Ractor.new do + s = ENV.size + ENV["test"] = "foo" + Ractor.yield [s, ENV.size] + end + s, s2 = r.take + assert_equal(s + 1, s2) + end; + end + + def test_empty_p_in_ractor + assert_ractor(<<-"end;") + r = Ractor.new do + ENV.clear + Ractor.yield ENV.empty? + ENV["test"] = "foo" + Ractor.yield ENV.empty? + end + assert r.take + assert !r.take + end; + end + + def test_has_key_in_ractor + assert_ractor(<<-"end;") + r = Ractor.new do + Ractor.yield ENV.has_key?("test") + ENV["test"] = "foo" + Ractor.yield ENV.has_key?("test") + #{str_to_yield_invalid_envvar_errors("v", "ENV.has_key?(v)")} + end + assert !r.take + assert r.take + #{str_to_receive_invalid_envvar_errors("r")} + end; + end + + def test_assoc_in_ractor + assert_ractor(<<-"end;") + r = Ractor.new do + Ractor.yield ENV.assoc("test") + ENV["test"] = "foo" + Ractor.yield ENV.assoc("test") + #{str_to_yield_invalid_envvar_errors("v", "ENV.assoc(v)")} + end + assert_nil(r.take) + k, v = r.take + if #{ignore_case_str} + assert_equal("TEST", k.upcase) + assert_equal("FOO", v.upcase) + else + assert_equal("test", k) + assert_equal("foo", v) + end + #{str_to_receive_invalid_envvar_errors("r")} + encoding = /mswin|mingw/ =~ RUBY_PLATFORM ? Encoding::UTF_8 : Encoding.find("locale") + assert_equal(encoding, v.encoding) + end; + end + + def test_has_value2_in_ractor + assert_ractor(<<-"end;") + r = Ractor.new do + ENV.clear + Ractor.yield ENV.has_value?("foo") + ENV["test"] = "foo" + Ractor.yield ENV.has_value?("foo") + end + assert !r.take + assert r.take + end; + end + + def test_rassoc_in_ractor + assert_ractor(<<-"end;") + r = Ractor.new do + ENV.clear + Ractor.yield ENV.rassoc("foo") + ENV["foo"] = "bar" + ENV["test"] = "foo" + ENV["baz"] = "qux" + Ractor.yield ENV.rassoc("foo") + end + assert_nil(r.take) + k, v = r.take + if #{ignore_case_str} + assert_equal("TEST", k.upcase) + assert_equal("FOO", v.upcase) + else + assert_equal("test", k) + assert_equal("foo", v) + end + end; + end + + def test_to_hash_in_ractor + assert_ractor(<<-"end;") + r = Ractor.new do + h = {} + ENV.each {|k, v| h[k] = v } + Ractor.yield [h, ENV.to_hash] + end + h, h2 = r.take + assert_equal(h, h2) + end; + end + + def test_to_h_in_ractor + assert_ractor(<<-"end;") + r = Ractor.new do + Ractor.yield [ENV.to_hash, ENV.to_h] + Ractor.yield [ENV.map {|k, v| ["$\#{k}", v.size]}.to_h, ENV.to_h {|k, v| ["$\#{k}", v.size]}] + end + a, b = r.take + assert_equal(a,b) + c, d = r.take + assert_equal(c,d) + end; + end + + def test_reject_in_ractor + assert_ractor(<<-"end;") + r = Ractor.new do + h1 = {} + ENV.each_pair {|k, v| h1[k] = v } + ENV["test"] = "foo" + h2 = ENV.reject {|k, v| #{ignore_case_str} ? k.upcase == "TEST" : k == "test" } + Ractor.yield [h1, h2] + end + h1, h2 = r.take + assert_equal(h1, h2) + end; + end + + def test_shift_in_ractor + assert_ractor(<<-"end;") + #{STR_DEFINITION_FOR_CHECK} + r = Ractor.new do + ENV.clear + ENV["foo"] = "bar" + ENV["baz"] = "qux" + a = ENV.shift + b = ENV.shift + Ractor.yield [a,b] + Ractor.yield ENV.shift + end + a,b = r.take + check([a, b], [%w(foo bar), %w(baz qux)]) + assert_nil(r.take) + end; + end + + def test_invert_in_ractor + assert_ractor(<<-"end;") + #{STR_DEFINITION_FOR_CHECK} + r = Ractor.new do + ENV.clear + ENV["foo"] = "bar" + ENV["baz"] = "qux" + Ractor.yield(ENV.invert) + end + check(r.take.to_a, [%w(bar foo), %w(qux baz)]) + end; + end + + def test_replace_in_ractor + assert_ractor(<<-"end;") + #{STR_DEFINITION_FOR_CHECK} + r = Ractor.new do + ENV["foo"] = "xxx" + ENV.replace({"foo"=>"bar", "baz"=>"qux"}) + Ractor.yield ENV.to_hash + ENV.replace({"Foo"=>"Bar", "Baz"=>"Qux"}) + Ractor.yield ENV.to_hash + end + check(r.take.to_a, [%w(foo bar), %w(baz qux)]) + check(r.take.to_a, [%w(Foo Bar), %w(Baz Qux)]) + end; + end + + def test_update_in_ractor + assert_ractor(<<-"end;") + #{STR_DEFINITION_FOR_CHECK} + r = Ractor.new do + ENV.clear + ENV["foo"] = "bar" + ENV["baz"] = "qux" + ENV.update({"baz"=>"quux","a"=>"b"}) + Ractor.yield ENV.to_hash + ENV.clear + ENV["foo"] = "bar" + ENV["baz"] = "qux" + ENV.update({"baz"=>"quux","a"=>"b"}) {|k, v1, v2| k + "_" + v1 + "_" + v2 } + Ractor.yield ENV.to_hash + end + check(r.take.to_a, [%w(foo bar), %w(baz quux), %w(a b)]) + check(r.take.to_a, [%w(foo bar), %w(baz baz_qux_quux), %w(a b)]) + end; + end + + def test_huge_value_in_ractor + assert_ractor(<<-"end;") + huge_value = "bar" * 40960 + r = Ractor.new huge_value do |v| + ENV["foo"] = "bar" + #{str_for_yielding_exception_class("ENV['foo'] = v ")} + Ractor.yield ENV["foo"] + end + + if /mswin|ucrt/ =~ RUBY_PLATFORM + #{str_for_assert_raise_on_yielded_exception_class(Errno::EINVAL, "r")} + result = r.take + assert_equal("bar", result) + else + exception_class = r.take + assert_equal(NilClass, exception_class) + result = r.take + assert_equal(huge_value, result) + end + end; + end + + def test_frozen_env_in_ractor + assert_ractor(<<-"end;") + r = Ractor.new do + #{str_for_yielding_exception_class("ENV.freeze")} + end + #{str_for_assert_raise_on_yielded_exception_class(TypeError, "r")} + end; + end + + def test_frozen_in_ractor + assert_ractor(<<-"end;") + r = Ractor.new do + ENV["#{PATH_ENV}"] = "/" + ENV.each do |k, v| + Ractor.yield [k.frozen?] + Ractor.yield [v.frozen?] + end + ENV.each_key do |k| + Ractor.yield [k.frozen?] + end + ENV.each_value do |v| + Ractor.yield [v.frozen?] + end + ENV.each_key do |k| + Ractor.yield [ENV[k].frozen?, "[\#{k.dump}]"] + Ractor.yield [ENV.fetch(k).frozen?, "fetch(\#{k.dump})"] + end + Ractor.yield "finished" + end + while((params=r.take) != "finished") + assert(*params) + end + end; + end + + def test_shared_substring_in_ractor + assert_ractor(<<-"end;") + r = Ractor.new do + bug12475 = '[ruby-dev:49655] [Bug #12475]' + n = [*"0".."9"].join("")*3 + e0 = ENV[n0 = "E\#{n}"] + e1 = ENV[n1 = "E\#{n}."] + ENV[n0] = nil + ENV[n1] = nil + ENV[n1.chop] = "T\#{n}.".chop + ENV[n0], e0 = e0, ENV[n0] + ENV[n1], e1 = e1, ENV[n1] + Ractor.yield [n, e0, e1, bug12475] + end + n, e0, e1, bug12475 = r.take + assert_equal("T\#{n}", e0, bug12475) + assert_nil(e1, bug12475) + end; + end + + def test_ivar_in_env_should_not_be_access_from_non_main_ractors + assert_ractor <<~RUBY + ENV.instance_eval{ @a = "hello" } + assert_equal "hello", ENV.instance_variable_get(:@a) + + r_get = Ractor.new do + ENV.instance_variable_get(:@a) + rescue Ractor::IsolationError => e + e + end + assert_equal Ractor::IsolationError, r_get.take.class + + r_get = Ractor.new do + ENV.instance_eval{ @a } + rescue Ractor::IsolationError => e + e + end + + assert_equal Ractor::IsolationError, r_get.take.class + + r_set = Ractor.new do + ENV.instance_eval{ @b = "hello" } + rescue Ractor::IsolationError => e + e + end + + assert_equal Ractor::IsolationError, r_set.take.class + RUBY + end + if RUBY_PLATFORM =~ /bccwin|mswin|mingw/ def test_memory_leak_aset bug9977 = '[ruby-dev:48323] [Bug #9977]' diff --git a/test/ruby/test_eval.rb b/test/ruby/test_eval.rb index bf551c6845..d55977c986 100644 --- a/test/ruby/test_eval.rb +++ b/test/ruby/test_eval.rb @@ -219,6 +219,12 @@ class TestEval < Test::Unit::TestCase end end + def test_instance_exec_cvar + [Object.new, [], 7, :sym, true, false, nil].each do |obj| + assert_equal(13, obj.instance_exec{@@cvar}) + end + end + def test_instance_eval_method bug2788 = '[ruby-core:28324]' [Object.new, [], nil, true, false].each do |o| @@ -253,6 +259,70 @@ class TestEval < Test::Unit::TestCase assert_equal(2, bar) end + def test_instance_exec_block_basic + forall_TYPE do |o| + assert_equal nil, o.instance_exec { nil } + assert_equal true, o.instance_exec { true } + assert_equal false, o.instance_exec { false } + assert_equal o, o.instance_exec { self } + assert_equal 1, o.instance_exec { 1 } + assert_equal :sym, o.instance_exec { :sym } + + assert_equal 11, o.instance_exec { 11 } + assert_equal 12, o.instance_exec { @ivar } unless o.frozen? + assert_equal 13, o.instance_exec { @@cvar } + assert_equal 14, o.instance_exec { $gvar__eval } + assert_equal 15, o.instance_exec { Const } + assert_equal 16, o.instance_exec { 7 + 9 } + assert_equal 17, o.instance_exec { 17.to_i } + assert_equal "18", o.instance_exec { "18" } + assert_equal "19", o.instance_exec { "1#{9}" } + + 1.times { + assert_equal 12, o.instance_exec { @ivar } unless o.frozen? + assert_equal 13, o.instance_exec { @@cvar } + assert_equal 14, o.instance_exec { $gvar__eval } + assert_equal 15, o.instance_exec { Const } + } + end + end + + def test_instance_exec_method_definition + klass = Class.new + o = klass.new + + o.instance_exec do + def foo + :foo_result + end + end + + assert_respond_to o, :foo + refute_respond_to klass, :foo + refute_respond_to klass.new, :foo + + assert_equal :foo_result, o.foo + end + + def test_instance_exec_eval_method_definition + klass = Class.new + o = klass.new + + o.instance_exec do + eval %{ + def foo + :foo_result + end + } + end + + assert_respond_to o, :foo + refute_respond_to klass, :foo + refute_respond_to klass.new, :foo + + assert_equal :foo_result, o.foo + end + # # From ruby/test/ruby/test_eval.rb # diff --git a/test/ruby/test_exception.rb b/test/ruby/test_exception.rb index 67f38c2e91..0b05ff7c51 100644 --- a/test/ruby/test_exception.rb +++ b/test/ruby/test_exception.rb @@ -252,6 +252,27 @@ class TestException < Test::Unit::TestCase } end + def test_catch_throw_in_require_cant_be_rescued + bug18562 = '[ruby-core:107403]' + Tempfile.create(["dep", ".rb"]) {|t| + t.puts("throw :extdep, 42") + t.close + + rescue_all = Class.new(Exception) + def rescue_all.===(_) + raise "should not reach here" + end + + v = assert_throw(:extdep, bug18562) do + require t.path + rescue rescue_all + assert(false, "should not reach here") + end + + assert_equal(42, v, bug18562) + } + end + def test_throw_false bug12743 = '[ruby-core:77229] [Bug #12743]' Thread.start { @@ -423,7 +444,7 @@ class TestException < Test::Unit::TestCase end def test_thread_signal_location - skip + # pend('TODO: a known bug [Bug #14474]') _, stderr, _ = EnvUtil.invoke_ruby(%w"--disable-gems -d", <<-RUBY, false, true) Thread.start do Thread.current.report_on_exception = false @@ -561,7 +582,7 @@ end.join end def test_ensure_after_nomemoryerror - skip "Forcing NoMemoryError causes problems in some environments" + omit "Forcing NoMemoryError causes problems in some environments" assert_separately([], "$_ = 'a' * 1_000_000_000_000_000_000") rescue NoMemoryError assert_raise(NoMemoryError) do @@ -786,6 +807,7 @@ end.join cause = ArgumentError.new("foobar") e = assert_raise(RuntimeError) {raise msg, cause: cause} assert_same(cause, e.cause) + assert_raise(TypeError) {raise msg, {cause: cause}} end def test_cause_with_no_arguments @@ -970,11 +992,12 @@ $stderr = $stdout; raise "\x82\xa0"') do |outs, errs, status| end assert_not_nil(e) assert_include(e.message, "\0") - assert_in_out_err([], src, [], [], *args, **opts) do |_, err,| - err.each do |e| - assert_not_include(e, "\0") - end - end + # Disabled by [Feature #18367] + #assert_in_out_err([], src, [], [], *args, **opts) do |_, err,| + # err.each do |e| + # assert_not_include(e, "\0") + # end + #end e end @@ -1064,25 +1087,17 @@ $stderr = $stdout; raise "\x82\xa0"') do |outs, errs, status| end def test_warn_deprecated_backwards_compatibility_category - warning = capture_warning_warn { Dir.exists?("non-existent") } + omit "no method to test" + + warning = capture_warning_warn { } assert_match(/deprecated/, warning[0]) end def test_warn_deprecated_category - warning = capture_warning_warn(category: true) { Dir.exists?("non-existent") } - - assert_equal :deprecated, warning[0][1] - end + omit "no method to test" - def test_warn_deprecated_to_remove_backwards_compatibility_category - warning = capture_warning_warn { Object.new.tainted? } - - assert_match(/deprecated/, warning[0]) - end - - def test_warn_deprecated_to_remove_category - warning = capture_warning_warn(category: true) { Object.new.tainted? } + warning = capture_warning_warn(category: true) { } assert_equal :deprecated, warning[0][1] end @@ -1200,6 +1215,14 @@ $stderr = $stdout; raise "\x82\xa0"') do |outs, errs, status| assert_empty warning end + def test_undef_Warning_warn + assert_separately([], "#{<<-"begin;"}\n#{<<-"end;"}") + begin; + Warning.undef_method(:warn) + assert_raise(NoMethodError) { warn "" } + end; + end + def test_undefined_backtrace assert_separately([], "#{<<-"begin;"}\n#{<<-"end;"}") begin; @@ -1399,4 +1422,33 @@ $stderr = $stdout; raise "\x82\xa0"') do |outs, errs, status| end end; end + + def test_detailed_message + e = RuntimeError.new("message") + assert_equal("message (RuntimeError)", e.detailed_message) + assert_equal("\e[1mmessage (\e[1;4mRuntimeError\e[m\e[1m)\e[m", e.detailed_message(highlight: true)) + + e = RuntimeError.new("foo\nbar\nbaz") + assert_equal("foo (RuntimeError)\nbar\nbaz", e.detailed_message) + assert_equal("\e[1mfoo (\e[1;4mRuntimeError\e[m\e[1m)\e[m\n\e[1mbar\e[m\n\e[1mbaz\e[m", e.detailed_message(highlight: true)) + + e = RuntimeError.new("") + assert_equal("unhandled exception", e.detailed_message) + assert_equal("\e[1;4munhandled exception\e[m", e.detailed_message(highlight: true)) + + e = RuntimeError.new + assert_equal("RuntimeError (RuntimeError)", e.detailed_message) + assert_equal("\e[1mRuntimeError (\e[1;4mRuntimeError\e[m\e[1m)\e[m", e.detailed_message(highlight: true)) + end + + def test_full_message_with_custom_detailed_message + e = RuntimeError.new("message") + opt_ = nil + e.define_singleton_method(:detailed_message) do |**opt| + opt_ = opt + "BOO!" + end + assert_match("BOO!", e.full_message.lines.first) + assert_equal({ highlight: Exception.to_tty? }, opt_) + end end diff --git a/test/ruby/test_fiber.rb b/test/ruby/test_fiber.rb index a0fd4a7491..5825aaf6cc 100644 --- a/test/ruby/test_fiber.rb +++ b/test/ruby/test_fiber.rb @@ -34,7 +34,7 @@ class TestFiber < Test::Unit::TestCase end def test_many_fibers - skip 'This is unstable on GitHub Actions --jit-wait. TODO: debug it' if defined?(RubyVM::JIT) && RubyVM::JIT.enabled? + omit 'This is unstable on GitHub Actions --jit-wait. TODO: debug it' if defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? max = 1000 assert_equal(max, max.times{ Fiber.new{} @@ -381,7 +381,7 @@ class TestFiber < Test::Unit::TestCase def test_fork_from_fiber - skip 'fork not supported' unless Process.respond_to?(:fork) + omit 'fork not supported' unless Process.respond_to?(:fork) pid = nil bug5700 = '[ruby-core:41456]' assert_nothing_raised(bug5700) do @@ -396,7 +396,7 @@ class TestFiber < Test::Unit::TestCase Fiber.new {}.transfer Fiber.new { Fiber.yield } end - exit!(0) + exit!(true) end }.transfer _, status = Process.waitpid2(xpid) @@ -405,8 +405,13 @@ class TestFiber < Test::Unit::TestCase end.resume end pid, status = Process.waitpid2(pid) - assert_equal(0, status.exitstatus, bug5700) - assert_equal(false, status.signaled?, bug5700) + assert_not_predicate(status, :signaled?, bug5700) + assert_predicate(status, :success?, bug5700) + + pid = Fiber.new {fork}.resume + pid, status = Process.waitpid2(pid) + assert_not_predicate(status, :signaled?) + assert_predicate(status, :success?) end def test_exit_in_fiber diff --git a/test/ruby/test_file.rb b/test/ruby/test_file.rb index d570b6f6fb..905416911a 100644 --- a/test/ruby/test_file.rb +++ b/test/ruby/test_file.rb @@ -273,7 +273,7 @@ class TestFile < Test::Unit::TestCase begin File.symlink(tst, a) rescue Errno::EACCES, Errno::EPERM - skip "need privilege" + omit "need privilege" end assert_equal(File.join(realdir, tst), File.realpath(a)) File.unlink(a) @@ -317,7 +317,7 @@ class TestFile < Test::Unit::TestCase Dir.mktmpdir('rubytest-realpath') {|tmpdir| Dir.chdir(tmpdir) do Dir.mkdir('foo') - skip "cannot run mklink" unless system('mklink /j bar foo > nul') + omit "cannot run mklink" unless system('mklink /j bar foo > nul') assert_equal(File.realpath('foo'), File.realpath('bar')) end } @@ -475,11 +475,11 @@ class TestFile < Test::Unit::TestCase begin io = File.open(tmpdir, File::RDWR | File::TMPFILE) rescue Errno::EINVAL - skip 'O_TMPFILE not supported (EINVAL)' + omit 'O_TMPFILE not supported (EINVAL)' rescue Errno::EISDIR - skip 'O_TMPFILE not supported (EISDIR)' + omit 'O_TMPFILE not supported (EISDIR)' rescue Errno::EOPNOTSUPP - skip 'O_TMPFILE not supported (EOPNOTSUPP)' + omit 'O_TMPFILE not supported (EOPNOTSUPP)' end io.write "foo" diff --git a/test/ruby/test_file_exhaustive.rb b/test/ruby/test_file_exhaustive.rb index 03675eaebc..579e4d77a9 100644 --- a/test/ruby/test_file_exhaustive.rb +++ b/test/ruby/test_file_exhaustive.rb @@ -173,9 +173,7 @@ class TestFileExhaustive < Test::Unit::TestCase end def chardev - return @chardev if defined? @chardev - @chardev = File::NULL == "/dev/null" ? "/dev/null" : nil - @chardev + File::NULL end def blockdev @@ -332,7 +330,7 @@ class TestFileExhaustive < Test::Unit::TestCase assert_file.not_chardev?(regular_file) assert_file.not_chardev?(utf8_file) assert_file.not_chardev?(nofile) - assert_file.chardev?(chardev) if chardev + assert_file.chardev?(chardev) end def test_exist_p @@ -640,7 +638,7 @@ class TestFileExhaustive < Test::Unit::TestCase end def test_birthtime - skip if RUBY_PLATFORM =~ /android/ + omit if RUBY_PLATFORM =~ /android/ [regular_file, utf8_file].each do |file| t1 = File.birthtime(file) t2 = File.open(file) {|f| f.birthtime} @@ -773,7 +771,7 @@ class TestFileExhaustive < Test::Unit::TestCase def test_readlink_junction base = File.basename(nofile) err = IO.popen(%W"cmd.exe /c mklink /j #{base} .", chdir: @dir, err: %i[child out], &:read) - skip err unless $?.success? + omit err unless $?.success? assert_equal(@dir, File.readlink(nofile)) end @@ -872,9 +870,10 @@ class TestFileExhaustive < Test::Unit::TestCase bug9934 = '[ruby-core:63114] [Bug #9934]' require "objspace" path = File.expand_path("/foo") - assert_operator(ObjectSpace.memsize_of(path), :<=, path.bytesize + GC::INTERNAL_CONSTANTS[:RVALUE_SIZE], bug9934) + assert_operator(ObjectSpace.memsize_of(path), :<=, path.bytesize + GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE], bug9934) path = File.expand_path("/a"*25) - assert_equal(path.bytesize+1 + GC::INTERNAL_CONSTANTS[:RVALUE_SIZE], ObjectSpace.memsize_of(path), bug9934) + assert_operator(ObjectSpace.memsize_of(path), :<=, + (path.bytesize + 1) * 2 + GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE], bug9934) end def test_expand_path_encoding @@ -1119,7 +1118,7 @@ class TestFileExhaustive < Test::Unit::TestCase def test_expand_path_for_existent_username user = ENV['USER'] - skip "ENV['USER'] is not set" unless user + omit "ENV['USER'] is not set" unless user assert_equal(ENV['HOME'], File.expand_path("~#{user}")) end unless DRIVE @@ -1512,6 +1511,31 @@ class TestFileExhaustive < Test::Unit::TestCase assert_equal(File.executable?(f), test(?x, f), f) assert_equal(File.executable_real?(f), test(?X, f), f) assert_equal(File.zero?(f), test(?z, f), f) + + stat = File.stat(f) + assert_equal(stat.atime, File.atime(f), f) + assert_equal(stat.ctime, File.ctime(f), f) + assert_equal(stat.mtime, File.mtime(f), f) + assert_bool_equal(stat.blockdev?, File.blockdev?(f), f) + assert_bool_equal(stat.chardev?, File.chardev?(f), f) + assert_bool_equal(stat.directory?, File.directory?(f), f) + assert_bool_equal(stat.file?, File.file?(f), f) + assert_bool_equal(stat.setgid?, File.setgid?(f), f) + assert_bool_equal(stat.grpowned?, File.grpowned?(f), f) + assert_bool_equal(stat.sticky?, File.sticky?(f), f) + assert_bool_equal(File.lstat(f).symlink?, File.symlink?(f), f) + assert_bool_equal(stat.owned?, File.owned?(f), f) + assert_bool_equal(stat.pipe?, File.pipe?(f), f) + assert_bool_equal(stat.readable?, File.readable?(f), f) + assert_bool_equal(stat.readable_real?, File.readable_real?(f), f) + assert_equal(stat.size?, File.size?(f), f) + assert_bool_equal(stat.socket?, File.socket?(f), f) + assert_bool_equal(stat.setuid?, File.setuid?(f), f) + assert_bool_equal(stat.writable?, File.writable?(f), f) + assert_bool_equal(stat.writable_real?, File.writable_real?(f), f) + assert_bool_equal(stat.executable?, File.executable?(f), f) + assert_bool_equal(stat.executable_real?, File.executable_real?(f), f) + assert_bool_equal(stat.zero?, File.zero?(f), f) end assert_equal(false, test(?-, @dir, fn1)) assert_equal(true, test(?-, fn1, fn1)) @@ -1621,7 +1645,7 @@ class TestFileExhaustive < Test::Unit::TestCase def test_stat_chardev_p assert_not_predicate(File::Stat.new(@dir), :chardev?) assert_not_predicate(File::Stat.new(regular_file), :chardev?) - assert_predicate(File::Stat.new(chardev), :chardev?) if chardev + assert_predicate(File::Stat.new(chardev), :chardev?) end def test_stat_readable_p @@ -1764,4 +1788,8 @@ class TestFileExhaustive < Test::Unit::TestCase dir = File.expand_path("/bar") assert_equal(File.join(dir, "~foo"), File.absolute_path("~foo", dir)) end + + def assert_bool_equal(expected, result, *messages) + assert_equal(expected, true & result, *messages) + end end diff --git a/test/ruby/test_float.rb b/test/ruby/test_float.rb index 4be2cfeeda..57a46fce92 100644 --- a/test/ruby/test_float.rb +++ b/test/ruby/test_float.rb @@ -171,6 +171,24 @@ class TestFloat < Test::Unit::TestCase assert_raise(ArgumentError, n += z + "A") {Float(n)} assert_raise(ArgumentError, n += z + ".0") {Float(n)} end + + x = nil + 2000.times do + x = Float("0x"+"0"*30) + break unless x == 0.0 + end + assert_equal(0.0, x, ->{"%a" % x}) + x = nil + 2000.times do + begin + x = Float("0x1."+"0"*270) + rescue ArgumentError => e + raise unless /"0x1\.0{270}"/ =~ e.message + else + break + end + end + assert_nil(x, ->{"%a" % x}) end def test_divmod diff --git a/test/ruby/test_gc.rb b/test/ruby/test_gc.rb index baf9971c48..b081e9fa78 100644 --- a/test/ruby/test_gc.rb +++ b/test/ruby/test_gc.rb @@ -54,7 +54,7 @@ class TestGc < Test::Unit::TestCase def test_start_full_mark return unless use_rgengc? - skip 'stress' if GC.stress + omit 'stress' if GC.stress 3.times { GC.start } # full mark and next time it should be minor mark GC.start(full_mark: false) @@ -65,7 +65,7 @@ class TestGc < Test::Unit::TestCase end def test_start_immediate_sweep - skip 'stress' if GC.stress + omit 'stress' if GC.stress GC.start(immediate_sweep: false) assert_equal false, GC.latest_gc_info(:immediate_sweep) @@ -117,7 +117,7 @@ class TestGc < Test::Unit::TestCase end def test_stat_single - skip 'stress' if GC.stress + omit 'stress' if GC.stress stat = GC.stat assert_equal stat[:count], GC.stat(:count) @@ -125,7 +125,7 @@ class TestGc < Test::Unit::TestCase end def test_stat_constraints - skip 'stress' if GC.stress + omit 'stress' if GC.stress stat = GC.stat assert_equal stat[:total_allocated_pages], stat[:heap_allocated_pages] + stat[:total_freed_pages] @@ -139,8 +139,78 @@ class TestGc < Test::Unit::TestCase end end + def test_stat_heap + omit 'stress' if GC.stress + + stat_heap = {} + stat = {} + # Initialize to prevent GC in future calls + GC.stat_heap(0, stat_heap) + GC.stat(stat) + + GC::INTERNAL_CONSTANTS[:SIZE_POOL_COUNT].times do |i| + GC.stat_heap(i, stat_heap) + GC.stat(stat) + + assert_equal GC::INTERNAL_CONSTANTS[:BASE_SLOT_SIZE] * (2**i), stat_heap[:slot_size] + assert_operator stat_heap[:heap_allocatable_pages], :<=, stat[:heap_allocatable_pages] + assert_operator stat_heap[:heap_eden_pages], :<=, stat[:heap_eden_pages] + assert_operator stat_heap[:heap_eden_slots], :>=, 0 + assert_operator stat_heap[:heap_tomb_pages], :<=, stat[:heap_tomb_pages] + assert_operator stat_heap[:heap_tomb_slots], :>=, 0 + assert_operator stat_heap[:total_allocated_pages], :>=, 0 + assert_operator stat_heap[:total_freed_pages], :>=, 0 + end + + GC.stat_heap(0, stat_heap) + assert_equal stat_heap[:slot_size], GC.stat_heap(0, :slot_size) + assert_equal stat_heap[:slot_size], GC.stat_heap(0)[:slot_size] + + assert_raise(ArgumentError) { GC.stat_heap(-1) } + assert_raise(ArgumentError) { GC.stat_heap(GC::INTERNAL_CONSTANTS[:SIZE_POOL_COUNT]) } + end + + def test_stat_heap_all + stat_heap_all = {} + stat_heap = {} + + 2.times do + GC.stat_heap(0, stat_heap) + GC.stat_heap(nil, stat_heap_all) + end + + GC::INTERNAL_CONSTANTS[:SIZE_POOL_COUNT].times do |i| + GC.stat_heap(i, stat_heap) + + assert_equal stat_heap, stat_heap_all[i] + end + + assert_raise(TypeError) { GC.stat_heap(nil, :slot_size) } + end + + def test_stat_heap_constraints + omit 'stress' if GC.stress + + stat = GC.stat + stat_heap = GC.stat_heap + GC.stat(stat) + GC.stat_heap(nil, stat_heap) + + stat_heap_sum = Hash.new(0) + stat_heap.values.each do |hash| + hash.each { |k, v| stat_heap_sum[k] += v } + end + + assert_equal stat[:heap_allocatable_pages], stat_heap_sum[:heap_allocatable_pages] + assert_equal stat[:heap_eden_pages], stat_heap_sum[:heap_eden_pages] + assert_equal stat[:heap_tomb_pages], stat_heap_sum[:heap_tomb_pages] + assert_equal stat[:heap_available_slots], stat_heap_sum[:heap_eden_slots] + stat_heap_sum[:heap_tomb_slots] + assert_equal stat[:total_allocated_pages], stat_heap_sum[:total_allocated_pages] + assert_equal stat[:total_freed_pages], stat_heap_sum[:total_freed_pages] + end + def test_latest_gc_info - skip 'stress' if GC.stress + omit 'stress' if GC.stress assert_separately %w[--disable-gem], __FILE__, __LINE__, <<-'eom' GC.start @@ -280,7 +350,7 @@ class TestGc < Test::Unit::TestCase end def test_profiler_clear - skip "for now" + omit "for now" assert_separately %w[--disable-gem], __FILE__, __LINE__, <<-'eom', timeout: 30 GC::Profiler.enable diff --git a/test/ruby/test_gc_compact.rb b/test/ruby/test_gc_compact.rb index c591b1d74e..da0023e6f3 100644 --- a/test/ruby/test_gc_compact.rb +++ b/test/ruby/test_gc_compact.rb @@ -4,20 +4,14 @@ require 'fiddle' require 'etc' if RUBY_PLATFORM =~ /s390x/ - puts "Currently, it is known that the compaction does not work well on s390x; contribution is welcome https://github.com/ruby/ruby/pull/5077" + warn "Currently, it is known that the compaction does not work well on s390x; contribution is welcome https://github.com/ruby/ruby/pull/5077" return end class TestGCCompact < Test::Unit::TestCase - module SupportsCompact - def setup - skip "autocompact not supported on this platform" unless supports_auto_compact? - super - end - - private - + module CompactionSupportInspector def supports_auto_compact? + return false if /wasm/ =~ RUBY_PLATFORM return true unless defined?(Etc::SC_PAGE_SIZE) begin @@ -30,10 +24,19 @@ class TestGCCompact < Test::Unit::TestCase end end - include SupportsCompact + module OmitUnlessCompactSupported + include CompactionSupportInspector + + def setup + omit "autocompact not supported on this platform" unless supports_auto_compact? + super + end + end + + include OmitUnlessCompactSupported class AutoCompact < Test::Unit::TestCase - include SupportsCompact + include OmitUnlessCompactSupported def test_enable_autocompact before = GC.auto_compact @@ -78,7 +81,7 @@ class TestGCCompact < Test::Unit::TestCase n.times do break if count < GC.stat(:compact_count) list2 << Object.new - end and skip "implicit compaction didn't happen within #{n} objects" + end and omit "implicit compaction didn't happen within #{n} objects" compact_stats = GC.latest_compact_info refute_predicate compact_stats[:considered], :empty? refute_predicate compact_stats[:moved], :empty? @@ -87,13 +90,39 @@ class TestGCCompact < Test::Unit::TestCase end end - def os_page_size - return true unless defined?(Etc::SC_PAGE_SIZE) + class CompactMethodsNotImplemented < Test::Unit::TestCase + include CompactionSupportInspector + + def assert_not_implemented(method, *args) + omit "autocompact is supported on this platform" if supports_auto_compact? + + assert_raise(NotImplementedError) { GC.send(method, *args) } + refute(GC.respond_to?(method), "GC.#{method} should be defined as rb_f_notimplement") + end + + def test_gc_compact_not_implemented + assert_not_implemented(:compact) + end + + def test_gc_auto_compact_get_not_implemented + assert_not_implemented(:auto_compact) + end + + def test_gc_auto_compact_set_not_implemented + assert_not_implemented(:auto_compact=, true) + end + + def test_gc_latest_compact_info_not_implemented + assert_not_implemented(:latest_compact_info) + end + + def test_gc_verify_compaction_references_not_implemented + assert_not_implemented(:verify_compaction_references) + end end - def setup - skip "autocompact not supported on this platform" unless supports_auto_compact? - super + def os_page_size + return true unless defined?(Etc::SC_PAGE_SIZE) end def test_gc_compact_stats diff --git a/test/ruby/test_hash.rb b/test/ruby/test_hash.rb index f79879c20a..073a0dabe8 100644 --- a/test/ruby/test_hash.rb +++ b/test/ruby/test_hash.rb @@ -1048,14 +1048,14 @@ class TestHash < Test::Unit::TestCase h = @cls.new {|hh, k| :foo } h[1] = 2 assert_equal([1, 2], h.shift) - assert_equal(:foo, h.shift) - assert_equal(:foo, h.shift) + assert_nil(h.shift) + assert_nil(h.shift) h = @cls.new(:foo) h[1] = 2 assert_equal([1, 2], h.shift) - assert_equal(:foo, h.shift) - assert_equal(:foo, h.shift) + assert_nil(h.shift) + assert_nil(h.shift) h =@cls[1=>2] h.each { assert_equal([1, 2], h.shift) } @@ -1066,7 +1066,20 @@ class TestHash < Test::Unit::TestCase def h.default(k = nil) super.upcase end - assert_equal("FOO", h.shift) + assert_nil(h.shift) + end + + def test_shift_for_empty_hash + # [ruby-dev:51159] + h = @cls[] + 100.times{|n| + while h.size < n + k = Random.rand 0..1<<30 + h[k] = 1 + end + 0 while h.shift + assert_equal({}, h) + } end def test_reject_bang2 diff --git a/test/ruby/test_inlinecache.rb b/test/ruby/test_inlinecache.rb index 6c2d86aefd..d48d95d74e 100644 --- a/test/ruby/test_inlinecache.rb +++ b/test/ruby/test_inlinecache.rb @@ -3,7 +3,7 @@ require 'test/unit' -class TestMethod < Test::Unit::TestCase +class TestMethodInlineCache < Test::Unit::TestCase def test_alias m0 = Module.new do def foo; :M0 end diff --git a/test/ruby/test_integer.rb b/test/ruby/test_integer.rb index 9354514df0..a2b181c642 100644 --- a/test/ruby/test_integer.rb +++ b/test/ruby/test_integer.rb @@ -299,6 +299,31 @@ class TestInteger < Test::Unit::TestCase end end + def test_times_bignum_redefine_plus_lt + assert_separately([], "#{<<-"begin;"}\n#{<<~"end;"}") + begin; + called = false + Integer.class_eval do + alias old_plus + + undef + + define_method(:+){|x| called = true; 1} + alias old_lt < + undef < + define_method(:<){|x| called = true} + end + big = 2**65 + big.times{break 0} + Integer.class_eval do + undef + + alias + old_plus + undef < + alias < old_lt + end + bug18377 = "[ruby-core:106361]" + assert_equal(false, called, bug18377) + end; + end + def assert_int_equal(expected, result, mesg = nil) assert_kind_of(Integer, result, mesg) assert_equal(expected, result, mesg) diff --git a/test/ruby/test_io.rb b/test/ruby/test_io.rb index 96e572b98d..ed0198321d 100644 --- a/test/ruby/test_io.rb +++ b/test/ruby/test_io.rb @@ -476,6 +476,18 @@ class TestIO < Test::Unit::TestCase } end + def test_copy_stream_append_to_nonempty + with_srccontent("foobar") {|src, content| + preface = 'preface' + File.write('dst', preface) + File.open('dst', 'ab') do |dst| + ret = IO.copy_stream(src, dst) + assert_equal(content.bytesize, ret) + assert_equal(preface + content, File.read("dst")) + end + } + end + def test_copy_stream_smaller with_srccontent {|src, content| @@ -643,8 +655,8 @@ class TestIO < Test::Unit::TestCase if have_nonblock? def test_copy_stream_no_busy_wait - skip "MJIT has busy wait on GC. This sometimes fails with --jit." if defined?(RubyVM::JIT) && RubyVM::JIT.enabled? - skip "multiple threads already active" if Thread.list.size > 1 + omit "MJIT has busy wait on GC. This sometimes fails with --jit." if defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? + omit "multiple threads already active" if Thread.list.size > 1 msg = 'r58534 [ruby-core:80969] [Backport #13533]' IO.pipe do |r,w| @@ -663,7 +675,7 @@ class TestIO < Test::Unit::TestCase begin w2.nonblock = true rescue Errno::EBADF - skip "nonblocking IO for pipe is not implemented" + omit "nonblocking IO for pipe is not implemented" end s = w2.syswrite("a" * 100000) t = Thread.new { sleep 0.1; r2.read } @@ -767,7 +779,7 @@ class TestIO < Test::Unit::TestCase r1.nonblock = true w2.nonblock = true rescue Errno::EBADF - skip "nonblocking IO for pipe is not implemented" + omit "nonblocking IO for pipe is not implemented" end t1 = Thread.new { w1 << megacontent; w1.close } t2 = Thread.new { r2.read } @@ -831,7 +843,7 @@ class TestIO < Test::Unit::TestCase assert_equal("bcd", r.read) end) rescue NotImplementedError - skip "pread(2) is not implemtented." + omit "pread(2) is not implemtented." end } end @@ -935,7 +947,7 @@ class TestIO < Test::Unit::TestCase begin s1.nonblock = true rescue Errno::EBADF - skip "nonblocking IO for pipe is not implemented" + omit "nonblocking IO for pipe is not implemented" end t1 = Thread.new { s2.read } t2 = Thread.new { @@ -959,7 +971,7 @@ class TestIO < Test::Unit::TestCase begin s1.nonblock = true rescue Errno::EBADF - skip "nonblocking IO for pipe is not implemented" + omit "nonblocking IO for pipe is not implemented" end trapping_usr2 do |rd| nr = 30 @@ -1482,6 +1494,13 @@ class TestIO < Test::Unit::TestCase end) end + def test_readpartial_zero_size + File.open(IO::NULL) do |r| + assert_empty(r.readpartial(0, s = "01234567")) + assert_empty(s) + end + end + def test_readpartial_buffer_error with_pipe do |r, w| s = "" @@ -1527,6 +1546,13 @@ class TestIO < Test::Unit::TestCase end) end + def test_read_zero_size + File.open(IO::NULL) do |r| + assert_empty(r.read(0, s = "01234567")) + assert_empty(s) + end + end + def test_read_buffer_error with_pipe do |r, w| s = "" @@ -1564,6 +1590,13 @@ class TestIO < Test::Unit::TestCase } end + def test_read_nonblock_zero_size + File.open(IO::NULL) do |r| + assert_empty(r.read_nonblock(0, s = "01234567")) + assert_empty(s) + end + end + def test_write_nonblock_simple_no_exceptions pipe(proc do |w| w.write_nonblock('1', exception: false) @@ -1598,7 +1631,7 @@ class TestIO < Test::Unit::TestCase end if have_nonblock? def test_read_nonblock_no_exceptions - skip '[ruby-core:90895] MJIT worker may leave fd open in a forked child' if defined?(RubyVM::JIT) && RubyVM::JIT.enabled? # TODO: consider acquiring GVL from MJIT worker. + omit '[ruby-core:90895] MJIT worker may leave fd open in a forked child' if defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? # TODO: consider acquiring GVL from MJIT worker. with_pipe {|r, w| assert_equal :wait_readable, r.read_nonblock(4096, exception: false) w.puts "HI!" @@ -2246,7 +2279,7 @@ class TestIO < Test::Unit::TestCase def test_autoclose_true_closed_by_finalizer # http://ci.rvm.jp/results/trunk-mjit@silicon-docker/1465760 # http://ci.rvm.jp/results/trunk-mjit@silicon-docker/1469765 - skip 'this randomly fails with MJIT' if defined?(RubyVM::JIT) && RubyVM::JIT.enabled? + omit 'this randomly fails with MJIT' if defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? feature2250 = '[ruby-core:26222]' pre = 'ft2250' @@ -2258,7 +2291,7 @@ class TestIO < Test::Unit::TestCase t.close rescue Errno::EBADF end - skip "expect IO object was GC'ed but not recycled yet" + omit "expect IO object was GC'ed but not recycled yet" rescue WeakRef::RefError assert_raise(Errno::EBADF, feature2250) {t.close} end @@ -2274,7 +2307,7 @@ class TestIO < Test::Unit::TestCase begin w.close t.close - skip "expect IO object was GC'ed but not recycled yet" + omit "expect IO object was GC'ed but not recycled yet" rescue WeakRef::RefError assert_nothing_raised(Errno::EBADF, feature2250) {t.close} end @@ -2637,7 +2670,7 @@ class TestIO < Test::Unit::TestCase end def test_puts_parallel - skip "not portable" + omit "not portable" pipe(proc do |w| threads = [] 100.times do @@ -3271,7 +3304,7 @@ __END__ begin f = File.open('/dev/tty') rescue Errno::ENOENT, Errno::ENXIO => e - skip e.message + omit e.message else tiocgwinsz=0x5413 winsize="" @@ -3397,10 +3430,10 @@ __END__ with_pipe do |r,w| # Linux 2.6.15 and earlier returned EINVAL instead of ESPIPE assert_raise(Errno::ESPIPE, Errno::EINVAL) { - r.advise(:willneed) or skip "fadvise(2) is not implemented" + r.advise(:willneed) or omit "fadvise(2) is not implemented" } assert_raise(Errno::ESPIPE, Errno::EINVAL) { - w.advise(:willneed) or skip "fadvise(2) is not implemented" + w.advise(:willneed) or omit "fadvise(2) is not implemented" } end end if /linux/ =~ RUBY_PLATFORM @@ -3540,14 +3573,14 @@ __END__ f.write('1') pos = f.tell rescue Errno::ENOSPC - skip "non-sparse file system" + omit "non-sparse file system" rescue SystemCallError else assert_equal(0x1_0000_0000, pos, msg) end end; rescue Timeout::Error - skip "Timeout because of slow file writing" + omit "Timeout because of slow file writing" end } end if /mswin|mingw/ =~ RUBY_PLATFORM diff --git a/test/ruby/test_io_buffer.rb b/test/ruby/test_io_buffer.rb index f7c175b589..0f8a9c5e80 100644 --- a/test/ruby/test_io_buffer.rb +++ b/test/ruby/test_io_buffer.rb @@ -1,5 +1,7 @@ # frozen_string_literal: false +require 'tempfile' + class TestIOBuffer < Test::Unit::TestCase experimental = Warning[:experimental] begin @@ -18,14 +20,14 @@ class TestIOBuffer < Test::Unit::TestCase end def test_flags - assert_equal 0, IO::Buffer::EXTERNAL - assert_equal 1, IO::Buffer::INTERNAL - assert_equal 2, IO::Buffer::MAPPED + assert_equal 1, IO::Buffer::EXTERNAL + assert_equal 2, IO::Buffer::INTERNAL + assert_equal 4, IO::Buffer::MAPPED - assert_equal 16, IO::Buffer::LOCKED - assert_equal 32, IO::Buffer::PRIVATE + assert_equal 32, IO::Buffer::LOCKED + assert_equal 64, IO::Buffer::PRIVATE - assert_equal 64, IO::Buffer::IMMUTABLE + assert_equal 128, IO::Buffer::READONLY end def test_endian @@ -36,6 +38,10 @@ class TestIOBuffer < Test::Unit::TestCase assert_include [IO::Buffer::LITTLE_ENDIAN, IO::Buffer::BIG_ENDIAN], IO::Buffer::HOST_ENDIAN end + def test_default_size + assert_equal IO::Buffer::DEFAULT_SIZE, IO::Buffer.new.size + end + def test_new_internal buffer = IO::Buffer.new(1024, IO::Buffer::INTERNAL) assert_equal 1024, buffer.size @@ -52,41 +58,62 @@ class TestIOBuffer < Test::Unit::TestCase assert buffer.mapped? end - def test_new_immutable - buffer = IO::Buffer.new(128, IO::Buffer::INTERNAL|IO::Buffer::IMMUTABLE) - assert buffer.immutable? + def test_new_readonly + buffer = IO::Buffer.new(128, IO::Buffer::INTERNAL|IO::Buffer::READONLY) + assert buffer.readonly? - assert_raise RuntimeError do - buffer.copy("", 0) + assert_raise IO::Buffer::AccessError do + buffer.set_string("") end - assert_raise RuntimeError do - buffer.copy("!", 1) + assert_raise IO::Buffer::AccessError do + buffer.set_string("!", 1) end end def test_file_mapped - buffer = File.open(__FILE__) {|file| IO::Buffer.map(file)} - assert_include buffer.to_str, "Hello World" + buffer = File.open(__FILE__) {|file| IO::Buffer.map(file, nil, 0, IO::Buffer::READONLY)} + contents = buffer.get_string + + assert_include contents, "Hello World" + assert_equal Encoding::BINARY, contents.encoding + end + + def test_file_mapped_invalid + assert_raise NoMethodError do + IO::Buffer.map("foobar") + end end def test_string_mapped string = "Hello World" buffer = IO::Buffer.for(string) + assert buffer.readonly? + end - # Cannot modify string as it's locked by the buffer: - assert_raise RuntimeError do - string[0] = "h" - end + def test_string_mapped_frozen + string = "Hello World".freeze + buffer = IO::Buffer.for(string) + assert buffer.readonly? + end - buffer.set(:U8, 0, "h".ord) + def test_string_mapped_mutable + string = "Hello World" + IO::Buffer.for(string) do |buffer| + refute buffer.readonly? - # Buffer releases it's ownership of the string: - buffer.free + # Cannot modify string as it's locked by the buffer: + assert_raise RuntimeError do + string[0] = "h" + end - assert_equal "hello World", string - string[0] = "H" - assert_equal "Hello World", string + buffer.set_value(:U8, 0, "h".ord) + + # Buffer releases it's ownership of the string: + buffer.free + + assert_equal "hello World", string + end end def test_non_string @@ -97,18 +124,22 @@ class TestIOBuffer < Test::Unit::TestCase end end - def test_resize - buffer = IO::Buffer.new(1024, IO::Buffer::MAPPED) - buffer.resize(2048, 0) + def test_resize_mapped + buffer = IO::Buffer.new + + buffer.resize(2048) assert_equal 2048, buffer.size + + buffer.resize(4096) + assert_equal 4096, buffer.size end def test_resize_preserve message = "Hello World" - buffer = IO::Buffer.new(1024, IO::Buffer::MAPPED) - buffer.copy(message, 0) - buffer.resize(2048, 1024) - assert_equal message, buffer.to_str(0, message.bytesize) + buffer = IO::Buffer.new(1024) + buffer.set_string(message) + buffer.resize(2048) + assert_equal message, buffer.get_string(0, message.bytesize) end def test_compare_same_size @@ -116,8 +147,8 @@ class TestIOBuffer < Test::Unit::TestCase assert_equal buffer1, buffer1 buffer2 = IO::Buffer.new(1) - buffer1.set(:U8, 0, 0x10) - buffer2.set(:U8, 0, 0x20) + buffer1.set_value(:U8, 0, 0x10) + buffer2.set_value(:U8, 0, 0x20) assert_negative buffer1 <=> buffer2 assert_positive buffer2 <=> buffer1 @@ -134,15 +165,14 @@ class TestIOBuffer < Test::Unit::TestCase def test_slice buffer = IO::Buffer.new(128) slice = buffer.slice(8, 32) - slice.copy("Hello World", 0) - assert_equal("Hello World", buffer.to_str(8, 11)) + slice.set_string("Hello World") + assert_equal("Hello World", buffer.get_string(8, 11)) end def test_slice_bounds buffer = IO::Buffer.new(128) - # What is best exception class? - assert_raise RuntimeError do + assert_raise ArgumentError do buffer.slice(128, 10) end @@ -154,19 +184,73 @@ class TestIOBuffer < Test::Unit::TestCase def test_locked buffer = IO::Buffer.new(128, IO::Buffer::INTERNAL|IO::Buffer::LOCKED) - assert_raise RuntimeError do - buffer.resize(256, 0) + assert_raise IO::Buffer::LockedError do + buffer.resize(256) end assert_equal 128, buffer.size - assert_raise RuntimeError do + assert_raise IO::Buffer::LockedError do buffer.free end assert_equal 128, buffer.size end + def test_get_string + message = "Hello World 🤓" + + buffer = IO::Buffer.new(128) + buffer.set_string(message) + + chunk = buffer.get_string(0, message.bytesize, Encoding::UTF_8) + assert_equal message, chunk + assert_equal Encoding::UTF_8, chunk.encoding + + chunk = buffer.get_string(0, message.bytesize, Encoding::BINARY) + assert_equal Encoding::BINARY, chunk.encoding + end + + # We check that values are correctly round tripped. + RANGES = { + :U8 => [0, 2**8-1], + :S8 => [-2**7, 0, 2**7-1], + + :U16 => [0, 2**16-1], + :S16 => [-2**15, 0, 2**15-1], + :u16 => [0, 2**16-1], + :s16 => [-2**15, 0, 2**15-1], + + :U32 => [0, 2**32-1], + :S32 => [-2**31, 0, 2**31-1], + :u32 => [0, 2**32-1], + :s32 => [-2**31, 0, 2**31-1], + + :U64 => [0, 2**64-1], + :S64 => [-2**63, 0, 2**63-1], + :u64 => [0, 2**64-1], + :s64 => [-2**63, 0, 2**63-1], + + :F32 => [-1.0, 0.0, 0.5, 1.0, 128.0], + :F64 => [-1.0, 0.0, 0.5, 1.0, 128.0], + } + + def test_get_set_primitives + buffer = IO::Buffer.new(128) + + RANGES.each do |type, values| + values.each do |value| + buffer.set_value(type, 0, value) + assert_equal value, buffer.get_value(type, 0), "Converting #{value} as #{type}." + end + end + end + + def test_clear + buffer = IO::Buffer.new(16) + buffer.set_string("Hello World!") + end + def test_invalidation input, output = IO.pipe @@ -181,7 +265,7 @@ class TestIOBuffer < Test::Unit::TestCase # (4) scheduler returns # (5) rb_write_internal invalidate the buffer object - assert_raise RuntimeError do + assert_raise IO::Buffer::LockedError do buffer.free end @@ -192,4 +276,79 @@ class TestIOBuffer < Test::Unit::TestCase input.close end + + def test_read + io = Tempfile.new + io.write("Hello World") + io.seek(0) + + buffer = IO::Buffer.new(128) + buffer.read(io, 5) + + assert_equal "Hello", buffer.get_string(0, 5) + ensure + io.close! + end + + def test_write + io = Tempfile.new + + buffer = IO::Buffer.new(128) + buffer.set_string("Hello") + buffer.write(io, 5) + + io.seek(0) + assert_equal "Hello", io.read(5) + ensure + io.close! + end + + def test_pread + io = Tempfile.new + io.write("Hello World") + io.seek(0) + + buffer = IO::Buffer.new(128) + buffer.pread(io, 5, 6) + + assert_equal "World", buffer.get_string(0, 5) + assert_equal 0, io.tell + ensure + io.close! + end + + def test_pwrite + io = Tempfile.new + + buffer = IO::Buffer.new(128) + buffer.set_string("World") + buffer.pwrite(io, 5, 6) + + assert_equal 0, io.tell + + io.seek(6) + assert_equal "World", io.read(5) + ensure + io.close! + end + + def test_operators + source = IO::Buffer.for("1234123412") + mask = IO::Buffer.for("133\x00") + + assert_equal IO::Buffer.for("123\x00123\x0012"), (source & mask) + assert_equal IO::Buffer.for("1334133413"), (source | mask) + assert_equal IO::Buffer.for("\x00\x01\x004\x00\x01\x004\x00\x01"), (source ^ mask) + assert_equal IO::Buffer.for("\xce\xcd\xcc\xcb\xce\xcd\xcc\xcb\xce\xcd"), ~source + end + + def test_inplace_operators + source = IO::Buffer.for("1234123412") + mask = IO::Buffer.for("133\x00") + + assert_equal IO::Buffer.for("123\x00123\x0012"), source.dup.and!(mask) + assert_equal IO::Buffer.for("1334133413"), source.dup.or!(mask) + assert_equal IO::Buffer.for("\x00\x01\x004\x00\x01\x004\x00\x01"), source.dup.xor!(mask) + assert_equal IO::Buffer.for("\xce\xcd\xcc\xcb\xce\xcd\xcc\xcb\xce\xcd"), source.dup.not! + end end diff --git a/test/ruby/test_iseq.rb b/test/ruby/test_iseq.rb index ac191531de..2a18ff02e1 100644 --- a/test/ruby/test_iseq.rb +++ b/test/ruby/test_iseq.rb @@ -129,7 +129,7 @@ class TestISeq < Test::Unit::TestCase def test_lambda_with_ractor_roundtrip iseq = compile(<<~EOF, __LINE__+1) x = 42 - y = lambda { x } + y = nil.instance_eval{ lambda { x } } Ractor.make_shareable(y) y.call EOF @@ -148,17 +148,21 @@ class TestISeq < Test::Unit::TestCase def test_ractor_unshareable_outer_variable name = "\u{2603 26a1}" - y = eval("proc {#{name} = nil; proc {|x| #{name} = x}}").call + y = nil.instance_eval do + eval("proc {#{name} = nil; proc {|x| #{name} = x}}").call + end assert_raise_with_message(ArgumentError, /\(#{name}\)/) do Ractor.make_shareable(y) end - y = eval("proc {#{name} = []; proc {|x| #{name}}}").call + y = nil.instance_eval do + eval("proc {#{name} = []; proc {|x| #{name}}}").call + end assert_raise_with_message(Ractor::IsolationError, /`#{name}'/) do Ractor.make_shareable(y) end obj = Object.new - def obj.foo(*) ->{super} end - assert_raise_with_message(Ractor::IsolationError, /hidden variable/) do + def obj.foo(*) nil.instance_eval{ ->{super} } end + assert_raise_with_message(Ractor::IsolationError, /refer unshareable object \[\] from variable `\*'/) do Ractor.make_shareable(obj.foo) end end @@ -388,10 +392,18 @@ class TestISeq < Test::Unit::TestCase def anon_star(*); end - def test_anon_param_in_disasm + def test_anon_rest_param_in_disasm iseq = RubyVM::InstructionSequence.of(method(:anon_star)) param_names = iseq.to_a[iseq.to_a.index(:method) + 1] - assert_equal [2], param_names + assert_equal [:*], param_names + end + + def anon_keyrest(**); end + + def test_anon_keyrest_param_in_disasm + iseq = RubyVM::InstructionSequence.of(method(:anon_keyrest)) + param_names = iseq.to_a[iseq.to_a.index(:method) + 1] + assert_equal [:**], param_names end def anon_block(&); end @@ -527,7 +539,7 @@ class TestISeq < Test::Unit::TestCase bin = assert_nothing_raised(mesg) do iseq.to_binary rescue RuntimeError => e - skip e.message if /compile with coverage/ =~ e.message + omit e.message if /compile with coverage/ =~ e.message raise end 10.times do @@ -721,4 +733,21 @@ class TestISeq < Test::Unit::TestCase assert_equal at0, Time.public_send(:at, 0, 0) RUBY end + + def test_mandatory_only_redef + assert_separately ['-W0'], <<~RUBY + r = Ractor.new{ + Float(10) + module Kernel + undef Float + def Float(n) + :new + end + end + GC.start + Float(30) + } + assert_equal :new, r.take + RUBY + end end diff --git a/test/ruby/test_jit_debug.rb b/test/ruby/test_jit_debug.rb deleted file mode 100644 index 50e52b4c2e..0000000000 --- a/test/ruby/test_jit_debug.rb +++ /dev/null @@ -1,17 +0,0 @@ -require_relative 'test_jit' - -return unless defined?(TestJIT) -return if ENV.key?('APPVEYOR') -return if ENV.key?('RUBYCI_NICKNAME') -return if ENV['RUBY_DEBUG']&.include?('ci') # ci.rvm.jp -return if /mswin/ =~ RUBY_PLATFORM - -class TestJITDebug < TestJIT - @@test_suites.delete TestJIT if self.respond_to? :on_parallel_worker? - - def setup - super - # let `#eval_with_jit` use --jit-debug - @jit_debug = true - end -end diff --git a/test/ruby/test_keyword.rb b/test/ruby/test_keyword.rb index 9094259bc2..9978072744 100644 --- a/test/ruby/test_keyword.rb +++ b/test/ruby/test_keyword.rb @@ -190,6 +190,53 @@ class TestKeywordArguments < Test::Unit::TestCase assert_equal(["bar", 111111], f[str: "bar", num: 111111]) end + def test_unset_hash_flag + bug18625 = "[ruby-core: 107847]" + singleton_class.class_eval do + ruby2_keywords def foo(*args) + args + end + + def single(arg) + arg + end + + def splat(*args) + args.last + end + + def kwargs(**kw) + kw + end + end + + h = { a: 1 } + args = foo(**h) + marked = args.last + assert_equal(true, Hash.ruby2_keywords_hash?(marked)) + + after_usage = single(*args) + assert_equal(h, after_usage) + assert_same(marked, args.last) + assert_not_same(marked, after_usage) + assert_equal(false, Hash.ruby2_keywords_hash?(after_usage)) + + after_usage = splat(*args) + assert_equal(h, after_usage) + assert_same(marked, args.last) + assert_not_same(marked, after_usage, bug18625) + assert_equal(false, Hash.ruby2_keywords_hash?(after_usage), bug18625) + + after_usage = kwargs(*args) + assert_equal(h, after_usage) + assert_same(marked, args.last) + assert_not_same(marked, after_usage, bug18625) + assert_not_same(marked, after_usage) + assert_equal(false, Hash.ruby2_keywords_hash?(after_usage)) + + assert_equal(true, Hash.ruby2_keywords_hash?(marked)) + end + def test_keyword_splat_new kw = {} h = {a: 1} @@ -3538,7 +3585,7 @@ class TestKeywordArguments < Test::Unit::TestCase assert_equal(splat_expect, pr.call(a), bug8463) pr = proc {|a, **opt| next a, opt} - assert_equal(splat_expect.values_at(0, -1), pr.call(splat_expect), bug8463) + assert_equal([splat_expect, {}], pr.call(splat_expect), bug8463) end def req_plus_keyword(x, **h) diff --git a/test/ruby/test_literal.rb b/test/ruby/test_literal.rb index 8c3256c034..99dd3a0c56 100644 --- a/test/ruby/test_literal.rb +++ b/test/ruby/test_literal.rb @@ -26,7 +26,7 @@ class TestRubyLiteral < Test::Unit::TestCase assert_equal '5', 0b101.inspect assert_instance_of Integer, 0b101 assert_raise(SyntaxError) { eval("0b") } - assert_equal '123456789012345678901234567890', 123456789012345678901234567890.inspect + assert_equal '123456789012345678901234567890', 123456789012345678901234567890.to_s assert_instance_of Integer, 123456789012345678901234567890 assert_instance_of Float, 1.3 assert_equal '2', eval("0x00+2").inspect diff --git a/test/ruby/test_m17n.rb b/test/ruby/test_m17n.rb index c793520ac4..c00bf59e18 100644 --- a/test/ruby/test_m17n.rb +++ b/test/ruby/test_m17n.rb @@ -300,7 +300,7 @@ class TestM17N < Test::Unit::TestCase orig_int, Encoding.default_internal = Encoding.default_internal, nil orig_ext = Encoding.default_external - skip "https://bugs.ruby-lang.org/issues/18338" + omit "https://bugs.ruby-lang.org/issues/18338" o = Object.new diff --git a/test/ruby/test_method.rb b/test/ruby/test_method.rb index daf0ec73ca..83e499913a 100644 --- a/test/ruby/test_method.rb +++ b/test/ruby/test_method.rb @@ -199,6 +199,11 @@ class TestMethod < Test::Unit::TestCase assert_equal(o.method(:foo), o.method(:foo)) assert_equal(o.method(:foo), o.method(:bar)) assert_not_equal(o.method(:foo), o.method(:baz)) + + class << o + private :bar + end + assert_not_equal(o.method(:foo), o.method(:bar)) end def test_hash @@ -318,6 +323,17 @@ class TestMethod < Test::Unit::TestCase assert_equal(:foo, o.foo) end + PUBLIC_SINGLETON_TEST = Object.new + class << PUBLIC_SINGLETON_TEST + private + PUBLIC_SINGLETON_TEST.define_singleton_method(:dsm){} + def PUBLIC_SINGLETON_TEST.def; end + end + def test_define_singleton_method_public + assert_equal(true, PUBLIC_SINGLETON_TEST.method(:dsm).public?) + assert_equal(true, PUBLIC_SINGLETON_TEST.method(:def).public?) + end + def test_define_singleton_method_no_proc o = Object.new assert_raise(ArgumentError) { @@ -566,9 +582,9 @@ class TestMethod < Test::Unit::TestCase assert_equal([[:req, :a], [:rest, :b], [:req, :c]], method(:mo5).parameters) assert_equal([[:req, :a], [:rest, :b], [:req, :c], [:block, :d]], method(:mo6).parameters) assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:block, :e]], method(:mo7).parameters) - assert_equal([[:req, :a], [:opt, :b], [:rest], [:req, :d], [:block, :e]], method(:mo8).parameters) + assert_equal([[:req, :a], [:opt, :b], [:rest, :*], [:req, :d], [:block, :e]], method(:mo8).parameters) assert_equal([[:req], [:block, :b]], method(:ma1).parameters) - assert_equal([[:keyrest]], method(:mk1).parameters) + assert_equal([[:keyrest, :**]], method(:mk1).parameters) assert_equal([[:keyrest, :o]], method(:mk2).parameters) assert_equal([[:req, :a], [:keyrest, :o]], method(:mk3).parameters) assert_equal([[:opt, :a], [:keyrest, :o]], method(:mk4).parameters) @@ -592,9 +608,9 @@ class TestMethod < Test::Unit::TestCase assert_equal([[:req, :a], [:rest, :b], [:req, :c]], self.class.instance_method(:mo5).parameters) assert_equal([[:req, :a], [:rest, :b], [:req, :c], [:block, :d]], self.class.instance_method(:mo6).parameters) assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:block, :e]], self.class.instance_method(:mo7).parameters) - assert_equal([[:req, :a], [:opt, :b], [:rest], [:req, :d], [:block, :e]], self.class.instance_method(:mo8).parameters) + assert_equal([[:req, :a], [:opt, :b], [:rest, :*], [:req, :d], [:block, :e]], self.class.instance_method(:mo8).parameters) assert_equal([[:req], [:block, :b]], self.class.instance_method(:ma1).parameters) - assert_equal([[:keyrest]], self.class.instance_method(:mk1).parameters) + assert_equal([[:keyrest, :**]], self.class.instance_method(:mk1).parameters) assert_equal([[:keyrest, :o]], self.class.instance_method(:mk2).parameters) assert_equal([[:req, :a], [:keyrest, :o]], self.class.instance_method(:mk3).parameters) assert_equal([[:opt, :a], [:keyrest, :o]], self.class.instance_method(:mk4).parameters) @@ -619,7 +635,7 @@ class TestMethod < Test::Unit::TestCase assert_equal([[:req, :a], [:rest, :b], [:req, :c], [:block, :d]], method(:pmo6).parameters) assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:block, :e]], method(:pmo7).parameters) assert_equal([[:req], [:block, :b]], method(:pma1).parameters) - assert_equal([[:keyrest]], method(:pmk1).parameters) + assert_equal([[:keyrest, :**]], method(:pmk1).parameters) assert_equal([[:keyrest, :o]], method(:pmk2).parameters) assert_equal([[:req, :a], [:keyrest, :o]], method(:pmk3).parameters) assert_equal([[:opt, :a], [:keyrest, :o]], method(:pmk4).parameters) @@ -643,7 +659,7 @@ class TestMethod < Test::Unit::TestCase assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:block, :e]], self.class.instance_method(:pmo7).parameters) assert_equal([[:req], [:block, :b]], self.class.instance_method(:pma1).parameters) assert_equal([[:req], [:block, :b]], self.class.instance_method(:pma1).parameters) - assert_equal([[:keyrest]], self.class.instance_method(:pmk1).parameters) + assert_equal([[:keyrest, :**]], self.class.instance_method(:pmk1).parameters) assert_equal([[:keyrest, :o]], self.class.instance_method(:pmk2).parameters) assert_equal([[:req, :a], [:keyrest, :o]], self.class.instance_method(:pmk3).parameters) assert_equal([[:opt, :a], [:keyrest, :o]], self.class.instance_method(:pmk4).parameters) @@ -1181,6 +1197,50 @@ class TestMethod < Test::Unit::TestCase assert_nil(super_method) end + def test_method_visibility_predicates + v = Visibility.new + assert_equal(true, v.method(:mv1).public?) + assert_equal(true, v.method(:mv2).private?) + assert_equal(true, v.method(:mv3).protected?) + assert_equal(false, v.method(:mv2).public?) + assert_equal(false, v.method(:mv3).private?) + assert_equal(false, v.method(:mv1).protected?) + end + + def test_unbound_method_visibility_predicates + assert_equal(true, Visibility.instance_method(:mv1).public?) + assert_equal(true, Visibility.instance_method(:mv2).private?) + assert_equal(true, Visibility.instance_method(:mv3).protected?) + assert_equal(false, Visibility.instance_method(:mv2).public?) + assert_equal(false, Visibility.instance_method(:mv3).private?) + assert_equal(false, Visibility.instance_method(:mv1).protected?) + end + + class VisibilitySub < Visibility + protected :mv1 + public :mv2 + private :mv3 + end + + def test_method_visibility_predicates_with_subclass_visbility_change + v = VisibilitySub.new + assert_equal(false, v.method(:mv1).public?) + assert_equal(false, v.method(:mv2).private?) + assert_equal(false, v.method(:mv3).protected?) + assert_equal(true, v.method(:mv2).public?) + assert_equal(true, v.method(:mv3).private?) + assert_equal(true, v.method(:mv1).protected?) + end + + def test_unbound_method_visibility_predicates_with_subclass_visbility_change + assert_equal(false, VisibilitySub.instance_method(:mv1).public?) + assert_equal(false, VisibilitySub.instance_method(:mv2).private?) + assert_equal(false, VisibilitySub.instance_method(:mv3).protected?) + assert_equal(true, VisibilitySub.instance_method(:mv2).public?) + assert_equal(true, VisibilitySub.instance_method(:mv3).private?) + assert_equal(true, VisibilitySub.instance_method(:mv1).protected?) + end + def rest_parameter(*rest) rest end @@ -1188,7 +1248,7 @@ class TestMethod < Test::Unit::TestCase def test_splat_long_array if File.exist?('/etc/os-release') && File.read('/etc/os-release').include?('openSUSE Leap') # For RubyCI's openSUSE machine http://rubyci.s3.amazonaws.com/opensuseleap/ruby-trunk/recent.html, which tends to die with NoMemoryError here. - skip 'do not exhaust memory on RubyCI openSUSE Leap machine' + omit 'do not exhaust memory on RubyCI openSUSE Leap machine' end n = 10_000_000 assert_equal n , rest_parameter(*(1..n)).size, '[Feature #10440]' @@ -1390,7 +1450,7 @@ class TestMethod < Test::Unit::TestCase # use_symbol = Object.instance_methods[0].is_a?(Symbol) nummodule = nummethod = 0 mods = [] - ObjectSpace.each_object(Module) {|m| mods << m if m.name } + ObjectSpace.each_object(Module) {|m| mods << m if String === m.name } mods = mods.sort_by {|m| m.name } mods.each {|mod| nummodule += 1 diff --git a/test/ruby/test_jit.rb b/test/ruby/test_mjit.rb index dcbe694d7a..30c5659c14 100644 --- a/test/ruby/test_jit.rb +++ b/test/ruby/test_mjit.rb @@ -3,8 +3,8 @@ require 'test/unit' require 'tmpdir' require_relative '../lib/jit_support' -# Test for --jit option -class TestJIT < Test::Unit::TestCase +# Test for --mjit option +class TestMJIT < Test::Unit::TestCase include JITSupport IGNORABLE_PATTERNS = [ @@ -31,7 +31,7 @@ class TestJIT < Test::Unit::TestCase :opt_invokebuiltin_delegate, ].each do |insn| if !RubyVM::INSTRUCTION_NAMES.include?(insn.to_s) - warn "instruction #{insn.inspect} is not defined but included in TestJIT::TEST_PENDING_INSNS" + warn "instruction #{insn.inspect} is not defined but included in TestMJIT::TEST_PENDING_INSNS" end end @@ -46,17 +46,17 @@ class TestJIT < Test::Unit::TestCase # ci.rvm.jp caches its build environment. Clean up temporary files left by SEGV. if ENV['RUBY_DEBUG']&.include?('ci') Dir.glob("#{ENV.fetch('TMPDIR', '/tmp')}/_ruby_mjit_p*u*.*").each do |file| - puts "test/ruby/test_jit.rb: removing #{file}" + puts "test/ruby/test_mjit.rb: removing #{file}" File.unlink(file) end end - # ruby -w -Itest/lib test/ruby/test_jit.rb + # ruby -w -Itest/lib test/ruby/test_mjit.rb if $VERBOSE pid = $$ at_exit do - if pid == $$ && !TestJIT.untested_insns.empty? - warn "you may want to add tests for following insns, when you have a chance: #{TestJIT.untested_insns.join(' ')}" + if pid == $$ && !TestMJIT.untested_insns.empty? + warn "you may want to add tests for following insns, when you have a chance: #{TestMJIT.untested_insns.join(' ')}" end end end @@ -64,7 +64,7 @@ class TestJIT < Test::Unit::TestCase def setup unless JITSupport.supported? - skip 'JIT seems not supported on this platform' + omit 'JIT seems not supported on this platform' end self.class.setup end @@ -321,7 +321,7 @@ class TestJIT < Test::Unit::TestCase end def test_compile_insn_reput - skip "write test" + omit "write test" end def test_compile_insn_setn @@ -352,11 +352,11 @@ class TestJIT < Test::Unit::TestCase end def test_compile_insn_tracecoverage - skip "write test" + omit "write test" end def test_compile_insn_defineclass - skip "support this in mjit_compile (low priority)" + omit "support this in mjit_compile (low priority)" end def test_compile_insn_send @@ -620,7 +620,7 @@ class TestJIT < Test::Unit::TestCase end; end - def test_jit_output + def test_mjit_output out, err = eval_with_jit('5.times { puts "MJIT" }', verbose: 1, min_calls: 5) assert_equal("MJIT\n" * 5, out) assert_match(/^#{JIT_SUCCESS_PREFIX}: block in <main>@-e:1 -> .+_ruby_mjit_p\d+u\d+\.c$/, err) @@ -709,7 +709,7 @@ class TestJIT < Test::Unit::TestCase if RUBY_PLATFORM.match?(/mswin/) # "Permission Denied" error is preventing to remove so file on AppVeyor/RubyCI. - skip 'Removing so file is randomly failing on AppVeyor/RubyCI mswin due to Permission Denied.' + omit 'Removing so file is randomly failing on AppVeyor/RubyCI mswin due to Permission Denied.' else # verify .c files are deleted on unload_units assert_send([Dir, :empty?, dir], debug_info) @@ -996,7 +996,7 @@ class TestJIT < Test::Unit::TestCase def test_clean_so if RUBY_PLATFORM.match?(/mswin/) - skip 'Removing so file is randomly failing on AppVeyor/RubyCI mswin due to Permission Denied.' + omit 'Removing so file is randomly failing on AppVeyor/RubyCI mswin due to Permission Denied.' end Dir.mktmpdir("jit_test_clean_so_") do |dir| code = "x = 0; 10.times {|i|x+=i}" @@ -1010,7 +1010,7 @@ class TestJIT < Test::Unit::TestCase def test_clean_objects_on_exec if /mswin|mingw/ =~ RUBY_PLATFORM # TODO: check call stack and close handle of code which is not on stack, and remove objects on best-effort basis - skip 'Removing so file being used does not work on Windows' + omit 'Removing so file being used does not work on Windows' end Dir.mktmpdir("jit_test_clean_objects_on_exec_") do |dir| eval_with_jit({"TMPDIR"=>dir}, "#{<<~"begin;"}\n#{<<~"end;"}", min_calls: 1) @@ -1108,7 +1108,7 @@ class TestJIT < Test::Unit::TestCase def test_mjit_pause_wait assert_eval_with_jit("#{<<~"begin;"}\n#{<<~"end;"}", stdout: '', success_count: 0, min_calls: 1) begin; - RubyVM::JIT.pause + RubyVM::MJIT.pause proc {}.call end; end @@ -1194,8 +1194,8 @@ class TestJIT < Test::Unit::TestCase out, err = eval_with_jit(script, verbose: 1, min_calls: min_calls, max_cache: max_cache) success_actual = err.scan(/^#{JIT_SUCCESS_PREFIX}:/).size recompile_actual = err.scan(/^#{JIT_RECOMPILE_PREFIX}:/).size - # Add --jit-verbose=2 logs for cl.exe because compiler's error message is suppressed - # for cl.exe with --jit-verbose=1. See `start_process` in mjit_worker.c. + # Add --mjit-verbose=2 logs for cl.exe because compiler's error message is suppressed + # for cl.exe with --mjit-verbose=1. See `start_process` in mjit_worker.c. if RUBY_PLATFORM.match?(/mswin/) && success_count != success_actual out2, err2 = eval_with_jit(script, verbose: 2, min_calls: min_calls, max_cache: max_cache) end @@ -1237,7 +1237,7 @@ class TestJIT < Test::Unit::TestCase $stderr.puts warn "'#{insn}' insn is not included in the script. Actual insns are: #{used_insns.join(' ')}\n", uplevel: uplevel end - TestJIT.untested_insns.delete(insn) + TestMJIT.untested_insns.delete(insn) end # Collect block's insns or defined method's insns, which are expected to be JIT-ed. diff --git a/test/ruby/test_mjit_debug.rb b/test/ruby/test_mjit_debug.rb new file mode 100644 index 0000000000..0b50acc68d --- /dev/null +++ b/test/ruby/test_mjit_debug.rb @@ -0,0 +1,17 @@ +require_relative 'test_mjit' + +return unless defined?(TestMJIT) +return if ENV.key?('APPVEYOR') +return if ENV.key?('RUBYCI_NICKNAME') +return if ENV['RUBY_DEBUG']&.include?('ci') # ci.rvm.jp +return if /mswin/ =~ RUBY_PLATFORM + +class TestMJITDebug < TestMJIT + @@test_suites.delete TestMJIT if self.respond_to? :on_parallel_worker? + + def setup + super + # let `#eval_with_jit` use --mjit-debug + @mjit_debug = true + end +end diff --git a/test/ruby/test_module.rb b/test/ruby/test_module.rb index e1524a5d81..c7245ab2db 100644 --- a/test/ruby/test_module.rb +++ b/test/ruby/test_module.rb @@ -475,6 +475,15 @@ class TestModule < Test::Unit::TestCase assert_not_include(mod.ancestor_list, BasicObject) end + def test_module_collected_extended_object + m1 = labeled_module("m1") + m2 = labeled_module("m2") + Object.new.extend(m1) + GC.start + m1.include(m2) + assert_equal([m1, m2], m1.ancestors) + end + def test_dup OtherSetup.call @@ -519,6 +528,16 @@ class TestModule < Test::Unit::TestCase assert_raise(ArgumentError) { Module.new { include } } end + def test_include_before_initialize + m = Class.new(Module) do + def initialize(...) + include Enumerable + super + end + end.new + assert_operator(m, :<, Enumerable) + end + def test_prepend_self m = Module.new assert_equal([m], m.ancestors) @@ -553,6 +572,26 @@ class TestModule < Test::Unit::TestCase assert_equal(2, a2.b) end + def test_ancestry_of_duped_classes + m = Module.new + sc = Class.new + a = Class.new(sc) do + def b; 2 end + prepend m + end + + a2 = a.dup.new + + assert_kind_of Object, a2 + assert_kind_of sc, a2 + refute_kind_of a, a2 + assert_kind_of m, a2 + + assert_kind_of Class, a2.class + assert_kind_of sc.singleton_class, a2.class + assert_same sc, a2.class.superclass + end + def test_gc_prepend_chain assert_separately([], <<-EOS) 10000.times { |i| @@ -737,6 +776,25 @@ class TestModule < Test::Unit::TestCase assert_equal([:m1, :m0, :m, :sc, :m1, :m0, :c], sc.new.m) end + def test_protected_include_into_included_module + m1 = Module.new do + def other_foo(other) + other.foo + end + + protected + def foo + :ok + end + end + m2 = Module.new + c1 = Class.new { include m2 } + c2 = Class.new { include m2 } + m2.include(m1) + + assert_equal :ok, c1.new.other_foo(c2.new) + end + def test_instance_methods assert_equal([:user, :user2], User.instance_methods(false).sort) assert_equal([:user, :user2, :mixin].sort, User.instance_methods(true).sort) @@ -1665,6 +1723,45 @@ class TestModule < Test::Unit::TestCase assert_match(/::X\u{df}:/, c.new.to_s) end + + def test_const_added + eval(<<~RUBY) + module TestConstAdded + @memo = [] + class << self + attr_accessor :memo + + def const_added(sym) + memo << sym + end + end + CONST = 1 + module SubModule + end + + class SubClass + end + end + TestConstAdded::OUTSIDE_CONST = 2 + module TestConstAdded::OutsideSubModule; end + class TestConstAdded::OutsideSubClass; end + RUBY + TestConstAdded.const_set(:CONST_SET, 3) + assert_equal [ + :CONST, + :SubModule, + :SubClass, + :OUTSIDE_CONST, + :OutsideSubModule, + :OutsideSubClass, + :CONST_SET, + ], TestConstAdded.memo + ensure + if self.class.const_defined? :TestConstAdded + self.class.send(:remove_const, :TestConstAdded) + end + end + def test_method_added memo = [] mod = Module.new do diff --git a/test/ruby/test_optimization.rb b/test/ruby/test_optimization.rb index a834996788..80c3c3860b 100644 --- a/test/ruby/test_optimization.rb +++ b/test/ruby/test_optimization.rb @@ -510,7 +510,7 @@ class TestRubyOptimization < Test::Unit::TestCase end def test_tailcall_not_to_grow_stack - skip 'currently JIT-ed code always creates a new stack frame' if defined?(RubyVM::JIT) && RubyVM::JIT.enabled? + omit 'currently JIT-ed code always creates a new stack frame' if defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? bug16161 = '[ruby-core:94881]' tailcall("#{<<-"begin;"}\n#{<<~"end;"}") diff --git a/test/ruby/test_parse.rb b/test/ruby/test_parse.rb index d697a29c1c..2841e20f6d 100644 --- a/test/ruby/test_parse.rb +++ b/test/ruby/test_parse.rb @@ -930,6 +930,10 @@ x = __ENCODING__ assert_no_warning(/shadowing outer local variable/) {eval("a=1; tap {|a|}")} end + def test_shadowing_private_local_variable + assert_equal 1, eval("_ = 1; [[2]].each{ |(_)| }; _") + end + def test_unused_variable o = Object.new assert_warning(/assigned but unused variable/) {o.instance_eval("def foo; a=1; nil; end")} diff --git a/test/ruby/test_pattern_matching.rb b/test/ruby/test_pattern_matching.rb index 35c41eb8b6..7531466f91 100644 --- a/test/ruby/test_pattern_matching.rb +++ b/test/ruby/test_pattern_matching.rb @@ -1,8 +1,6 @@ # frozen_string_literal: true require 'test/unit' -experimental, Warning[:experimental] = Warning[:experimental], false # suppress "warning: Pattern matching is experimental, and the behavior may change in future versions of Ruby!" -eval "\n#{<<~'END_of_GUARD'}", binding, __FILE__, __LINE__ class TestPatternMatching < Test::Unit::TestCase class NullFormatter def message_for(corrections) @@ -1550,22 +1548,6 @@ END assert_equal false, (1 in 2) end - def assert_experimental_warning(code) - w = Warning[:experimental] - - Warning[:experimental] = false - assert_warn('') {eval(code)} - - Warning[:experimental] = true - assert_warn(/is experimental/) {eval(code)} - ensure - Warning[:experimental] = w - end - - def test_experimental_warning - assert_experimental_warning("case [0]; in [*, 0, *]; end") - end - ################################################################ def test_single_pattern_error_value_pattern @@ -1693,5 +1675,3 @@ END end end end -END_of_GUARD -Warning[:experimental] = experimental diff --git a/test/ruby/test_proc.rb b/test/ruby/test_proc.rb index 51872e49be..05c6e03aac 100644 --- a/test/ruby/test_proc.rb +++ b/test/ruby/test_proc.rb @@ -412,6 +412,11 @@ class TestProc < Test::Unit::TestCase assert_equal(:foo, bc.foo) end + def test_dup_subclass + c1 = Class.new(Proc) + assert_equal c1, c1.new{}.dup.class, '[Bug #17545]' + end + def test_binding b = proc {|x, y, z| proc {}.binding }.call(1, 2, 3) class << b; attr_accessor :foo; end @@ -440,6 +445,11 @@ class TestProc < Test::Unit::TestCase assert_equal(@@line_of_source_location_test, lineno, 'Bug #2427') end + def test_binding_error_unless_ruby_frame + define_singleton_method :binding_from_c!, method(:binding).to_proc >> ->(bndg) {bndg} + assert_raise(RuntimeError) { binding_from_c! } + end + def test_proc_lambda assert_raise(ArgumentError) { proc } assert_raise(ArgumentError) { assert_warn(/deprecated/) {lambda} } @@ -847,6 +857,88 @@ class TestProc < Test::Unit::TestCase assert_equal [[1, 2], Proc, :x], (pr.call(1, 2){|x| x}) end + def test_proc_args_single_kw_no_autosplat + pr = proc {|c, a: 1| [c, a] } + assert_equal [nil, 1], pr.call() + assert_equal [1, 1], pr.call(1) + assert_equal [[1], 1], pr.call([1]) + assert_equal [1, 1], pr.call(1,2) + assert_equal [[1, 2], 1], pr.call([1,2]) + + assert_equal [nil, 3], pr.call(a: 3) + assert_equal [1, 3], pr.call(1, a: 3) + assert_equal [[1], 3], pr.call([1], a: 3) + assert_equal [1, 3], pr.call(1,2, a: 3) + assert_equal [[1, 2], 3], pr.call([1,2], a: 3) + end + + def test_proc_args_single_kwsplat_no_autosplat + pr = proc {|c, **kw| [c, kw] } + assert_equal [nil, {}], pr.call() + assert_equal [1, {}], pr.call(1) + assert_equal [[1], {}], pr.call([1]) + assert_equal [1, {}], pr.call(1,2) + assert_equal [[1, 2], {}], pr.call([1,2]) + + assert_equal [nil, {a: 3}], pr.call(a: 3) + assert_equal [1, {a: 3}], pr.call(1, a: 3) + assert_equal [[1], {a: 3}], pr.call([1], a: 3) + assert_equal [1, {a: 3}], pr.call(1,2, a: 3) + assert_equal [[1, 2], {a: 3}], pr.call([1,2], a: 3) + end + + def test_proc_args_multiple_kw_autosplat + pr = proc {|c, b, a: 1| [c, b, a] } + assert_equal [1, 2, 1], pr.call([1,2]) + + pr = proc {|c=nil, b=nil, a: 1| [c, b, a] } + assert_equal [nil, nil, 1], pr.call([]) + assert_equal [1, nil, 1], pr.call([1]) + assert_equal [1, 2, 1], pr.call([1,2]) + + pr = proc {|c, b=nil, a: 1| [c, b, a] } + assert_equal [1, nil, 1], pr.call([1]) + assert_equal [1, 2, 1], pr.call([1,2]) + + pr = proc {|c=nil, b, a: 1| [c, b, a] } + assert_equal [nil, 1, 1], pr.call([1]) + assert_equal [1, 2, 1], pr.call([1,2]) + + pr = proc {|c, *b, a: 1| [c, b, a] } + assert_equal [1, [], 1], pr.call([1]) + assert_equal [1, [2], 1], pr.call([1,2]) + + pr = proc {|*c, b, a: 1| [c, b, a] } + assert_equal [[], 1, 1], pr.call([1]) + assert_equal [[1], 2, 1], pr.call([1,2]) + end + + def test_proc_args_multiple_kwsplat_autosplat + pr = proc {|c, b, **kw| [c, b, kw] } + assert_equal [1, 2, {}], pr.call([1,2]) + + pr = proc {|c=nil, b=nil, **kw| [c, b, kw] } + assert_equal [nil, nil, {}], pr.call([]) + assert_equal [1, nil, {}], pr.call([1]) + assert_equal [1, 2, {}], pr.call([1,2]) + + pr = proc {|c, b=nil, **kw| [c, b, kw] } + assert_equal [1, nil, {}], pr.call([1]) + assert_equal [1, 2, {}], pr.call([1,2]) + + pr = proc {|c=nil, b, **kw| [c, b, kw] } + assert_equal [nil, 1, {}], pr.call([1]) + assert_equal [1, 2, {}], pr.call([1,2]) + + pr = proc {|c, *b, **kw| [c, b, kw] } + assert_equal [1, [], {}], pr.call([1]) + assert_equal [1, [2], {}], pr.call([1,2]) + + pr = proc {|*c, b, **kw| [c, b, kw] } + assert_equal [[], 1, {}], pr.call([1]) + assert_equal [[1], 2, {}], pr.call([1,2]) + end + def test_proc_args_only_rest pr = proc {|*c| c } assert_equal [], pr.call() @@ -1229,6 +1321,28 @@ class TestProc < Test::Unit::TestCase assert_empty(pr.parameters.map{|_,n|n}.compact) end + def test_parameters_lambda + assert_equal([], proc {}.parameters(lambda: true)) + assert_equal([], proc {||}.parameters(lambda: true)) + assert_equal([[:req, :a]], proc {|a|}.parameters(lambda: true)) + assert_equal([[:req, :a], [:req, :b]], proc {|a, b|}.parameters(lambda: true)) + assert_equal([[:opt, :a], [:block, :b]], proc {|a=:a, &b|}.parameters(lambda: true)) + assert_equal([[:req, :a], [:opt, :b]], proc {|a, b=:b|}.parameters(lambda: true)) + assert_equal([[:rest, :a]], proc {|*a|}.parameters(lambda: true)) + assert_equal([[:req, :a], [:rest, :b], [:block, :c]], proc {|a, *b, &c|}.parameters(lambda: true)) + assert_equal([[:req, :a], [:rest, :b], [:req, :c]], proc {|a, *b, c|}.parameters(lambda: true)) + assert_equal([[:req, :a], [:rest, :b], [:req, :c], [:block, :d]], proc {|a, *b, c, &d|}.parameters(lambda: true)) + assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:block, :e]], proc {|a, b=:b, *c, d, &e|}.parameters(lambda: true)) + assert_equal([[:req], [:block, :b]], proc {|(a), &b|a}.parameters(lambda: true)) + assert_equal([[:req, :a], [:req, :b], [:opt, :c], [:opt, :d], [:rest, :e], [:req, :f], [:req, :g], [:block, :h]], proc {|a,b,c=:c,d=:d,*e,f,g,&h|}.parameters(lambda: true)) + + pr = eval("proc{|"+"(_),"*30+"|}") + assert_empty(pr.parameters(lambda: true).map{|_,n|n}.compact) + + assert_equal([[:opt, :a]], lambda {|a|}.parameters(lambda: false)) + assert_equal([[:opt, :a], [:opt, :b], [:opt, :c], [:opt, :d], [:rest, :e], [:opt, :f], [:opt, :g], [:block, :h]], lambda {|a,b,c=:c,d=:d,*e,f,g,&h|}.parameters(lambda: false)) + end + def pm0() end def pm1(a) end def pm2(a, b) end @@ -1261,7 +1375,7 @@ class TestProc < Test::Unit::TestCase assert_equal([[:req, :a], [:rest, :b], [:req, :c], [:block, :d]], method(:pmo6).to_proc.parameters) assert_equal([[:req, :a], [:opt, :b], [:rest, :c], [:req, :d], [:block, :e]], method(:pmo7).to_proc.parameters) assert_equal([[:req], [:block, :b]], method(:pma1).to_proc.parameters) - assert_equal([[:keyrest]], method(:pmk1).to_proc.parameters) + assert_equal([[:keyrest, :**]], method(:pmk1).to_proc.parameters) assert_equal([[:keyrest, :o]], method(:pmk2).to_proc.parameters) assert_equal([[:req, :a], [:keyrest, :o]], method(:pmk3).to_proc.parameters) assert_equal([[:opt, :a], [:keyrest, :o]], method(:pmk4).to_proc.parameters) diff --git a/test/ruby/test_process.rb b/test/ruby/test_process.rb index 636871f822..c4888598a8 100644 --- a/test/ruby/test_process.rb +++ b/test/ruby/test_process.rb @@ -169,7 +169,7 @@ class TestProcess < Test::Unit::TestCase end def test_execopts_pgroup - skip "system(:pgroup) is not supported" if windows? + omit "system(:pgroup) is not supported" if windows? assert_nothing_raised { system(*TRUECOMMAND, :pgroup=>false) } io = IO.popen([RUBY, "-e", "print Process.getpgrp"]) @@ -208,39 +208,39 @@ class TestProcess < Test::Unit::TestCase n = max IO.popen([RUBY, "-e", - "p Process.getrlimit(:CORE)", :rlimit_core=>n]) {|io| - assert_equal("[#{n}, #{n}]\n", io.read) + "puts Process.getrlimit(:CORE)", :rlimit_core=>n]) {|io| + assert_equal("#{n}\n#{n}\n", io.read) } n = 0 IO.popen([RUBY, "-e", - "p Process.getrlimit(:CORE)", :rlimit_core=>n]) {|io| - assert_equal("[#{n}, #{n}]\n", io.read) + "puts Process.getrlimit(:CORE)", :rlimit_core=>n]) {|io| + assert_equal("#{n}\n#{n}\n", io.read) } n = max IO.popen([RUBY, "-e", - "p Process.getrlimit(:CORE)", :rlimit_core=>[n]]) {|io| - assert_equal("[#{n}, #{n}]", io.read.chomp) + "puts Process.getrlimit(:CORE)", :rlimit_core=>[n]]) {|io| + assert_equal("#{n}\n#{n}\n", io.read) } m, n = 0, max IO.popen([RUBY, "-e", - "p Process.getrlimit(:CORE)", :rlimit_core=>[m,n]]) {|io| - assert_equal("[#{m}, #{n}]", io.read.chomp) + "puts Process.getrlimit(:CORE)", :rlimit_core=>[m,n]]) {|io| + assert_equal("#{m}\n#{n}\n", io.read) } m, n = 0, 0 IO.popen([RUBY, "-e", - "p Process.getrlimit(:CORE)", :rlimit_core=>[m,n]]) {|io| - assert_equal("[#{m}, #{n}]", io.read.chomp) + "puts Process.getrlimit(:CORE)", :rlimit_core=>[m,n]]) {|io| + assert_equal("#{m}\n#{n}\n", io.read) } n = max IO.popen([RUBY, "-e", - "p Process.getrlimit(:CORE), Process.getrlimit(:CPU)", + "puts Process.getrlimit(:CORE), Process.getrlimit(:CPU)", :rlimit_core=>n, :rlimit_cpu=>3600]) {|io| - assert_equal("[#{n}, #{n}]\n[3600, 3600]", io.read.chomp) + assert_equal("#{n}\n#{n}\n""3600\n3600\n", io.read) } assert_raise(ArgumentError) do @@ -511,7 +511,7 @@ class TestProcess < Test::Unit::TestCase UMASK = [RUBY, '-e', 'printf "%04o\n", File.umask'] def test_execopts_umask - skip "umask is not supported" if windows? + omit "umask is not supported" if windows? IO.popen([*UMASK, :umask => 0]) {|io| assert_equal("0000", io.read.chomp) } @@ -837,7 +837,7 @@ class TestProcess < Test::Unit::TestCase STDERR=>"out", STDOUT=>[:child, STDERR]) assert_equal("errout", File.read("out")) - skip "inheritance of fd other than stdin,stdout and stderr is not supported" if windows? + omit "inheritance of fd other than stdin,stdout and stderr is not supported" if windows? Process.wait spawn(RUBY, "-e", "STDERR.print 'err'; STDOUT.print 'out'", STDOUT=>"out", STDERR=>[:child, 3], @@ -889,7 +889,7 @@ class TestProcess < Test::Unit::TestCase end def test_execopts_popen_extra_fd - skip "inheritance of fd other than stdin,stdout and stderr is not supported" if windows? + omit "inheritance of fd other than stdin,stdout and stderr is not supported" if windows? with_tmpchdir {|d| with_pipe {|r, w| IO.popen([RUBY, '-e', 'IO.new(3, "w").puts("a"); puts "b"', 3=>w]) {|io| @@ -918,7 +918,7 @@ class TestProcess < Test::Unit::TestCase end def test_fd_inheritance - skip "inheritance of fd other than stdin,stdout and stderr is not supported" if windows? + omit "inheritance of fd other than stdin,stdout and stderr is not supported" if windows? with_pipe {|r, w| system(RUBY, '-e', 'IO.new(ARGV[0].to_i, "w").puts(:ba)', w.fileno.to_s, w=>w) w.close @@ -964,7 +964,7 @@ class TestProcess < Test::Unit::TestCase end def test_execopts_close_others - skip "inheritance of fd other than stdin,stdout and stderr is not supported" if windows? + omit "inheritance of fd other than stdin,stdout and stderr is not supported" if windows? with_tmpchdir {|d| with_pipe {|r, w| system(RUBY, '-e', 'STDERR.reopen("err", "w"); IO.new(ARGV[0].to_i, "w").puts("ma")', w.fileno.to_s, :close_others=>true) @@ -1058,7 +1058,7 @@ class TestProcess < Test::Unit::TestCase } } rescue NotImplementedError - skip "IO#close_on_exec= is not supported" + omit "IO#close_on_exec= is not supported" end end unless windows? # passing non-stdio fds is not supported on Windows @@ -1610,7 +1610,7 @@ class TestProcess < Test::Unit::TestCase else assert_kind_of(Integer, max) assert_predicate(max, :positive?) - skip "not limited to NGROUPS_MAX" if /darwin/ =~ RUBY_PLATFORM + omit "not limited to NGROUPS_MAX" if /darwin/ =~ RUBY_PLATFORM gs = Process.groups assert_operator(gs.size, :<=, max) gs[0] ||= 0 @@ -1637,7 +1637,7 @@ class TestProcess < Test::Unit::TestCase end def test_setegid - skip "root can use Process.egid on Android platform" if RUBY_PLATFORM =~ /android/ + omit "root can use Process.egid on Android platform" if RUBY_PLATFORM =~ /android/ assert_nothing_raised(TypeError) {Process.egid += 0} rescue NotImplementedError end @@ -1698,7 +1698,7 @@ class TestProcess < Test::Unit::TestCase if /freebsd|openbsd/ =~ RUBY_PLATFORM # this relates #4173 # When ruby can use 2 cores, signal and wait4 may miss the signal. - skip "this fails on FreeBSD and OpenBSD on multithreaded environment" + omit "this fails on FreeBSD and OpenBSD on multithreaded environment" end signal_received = [] IO.pipe do |sig_r, sig_w| @@ -1718,7 +1718,7 @@ class TestProcess < Test::Unit::TestCase Process.wait pid assert_send [sig_r, :wait_readable, 5], 'self-pipe not readable' end - if defined?(RubyVM::JIT) && RubyVM::JIT.enabled? # checking -DMJIT_FORCE_ENABLE. It may trigger extra SIGCHLD. + if defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? # checking -DMJIT_FORCE_ENABLE. It may trigger extra SIGCHLD. assert_equal [true], signal_received.uniq, "[ruby-core:19744]" else assert_equal [true], signal_received, "[ruby-core:19744]" @@ -1733,7 +1733,7 @@ class TestProcess < Test::Unit::TestCase def test_no_curdir if /solaris/i =~ RUBY_PLATFORM - skip "Temporary skip to avoid CI failures after commit to use realpath on required files" + omit "Temporary omit to avoid CI failures after commit to use realpath on required files" end with_tmpchdir {|d| Dir.mkdir("vd") @@ -1775,7 +1775,7 @@ class TestProcess < Test::Unit::TestCase def test_aspawn_too_long_path if /solaris/i =~ RUBY_PLATFORM && !defined?(Process::RLIMIT_NPROC) - skip "Too exhaustive test on platforms without Process::RLIMIT_NPROC such as Solaris 10" + omit "Too exhaustive test on platforms without Process::RLIMIT_NPROC such as Solaris 10" end bug4315 = '[ruby-core:34833] #7904 [ruby-core:52628] #11613' assert_fail_too_long_path(%w"echo |", bug4315) @@ -1958,7 +1958,7 @@ class TestProcess < Test::Unit::TestCase end def test_execopts_uid - skip "root can use uid option of Kernel#system on Android platform" if RUBY_PLATFORM =~ /android/ + omit "root can use uid option of Kernel#system on Android platform" if RUBY_PLATFORM =~ /android/ feature6975 = '[ruby-core:47414]' [30000, [Process.uid, ENV["USER"]]].each do |uid, user| @@ -1989,8 +1989,8 @@ class TestProcess < Test::Unit::TestCase end def test_execopts_gid - skip "Process.groups not implemented on Windows platform" if windows? - skip "root can use Process.groups on Android platform" if RUBY_PLATFORM =~ /android/ + omit "Process.groups not implemented on Windows platform" if windows? + omit "root can use Process.groups on Android platform" if RUBY_PLATFORM =~ /android/ feature6975 = '[ruby-core:47414]' groups = Process.groups.map do |g| @@ -2511,7 +2511,7 @@ EOS end def test_forked_child_handles_signal - skip "fork not supported" unless Process.respond_to?(:fork) + omit "fork not supported" unless Process.respond_to?(:fork) assert_normal_exit(<<-"end;", '[ruby-core:82883] [Bug #13916]') require 'timeout' pid = fork { sleep } diff --git a/test/ruby/test_rand.rb b/test/ruby/test_rand.rb index 13b7329269..f066433f6a 100644 --- a/test/ruby/test_rand.rb +++ b/test/ruby/test_rand.rb @@ -317,7 +317,7 @@ class TestRand < Test::Unit::TestCase assert_equal(r1, r2, bug5661) assert_fork_status(1, '[ruby-core:82100] [Bug #13753]') do - Random::DEFAULT.rand(4) + Random.rand(4) end rescue NotImplementedError end @@ -395,8 +395,8 @@ class TestRand < Test::Unit::TestCase assert_separately([], "#{<<~"begin;"}\n#{<<~'end;'}") begin; verbose, $VERBOSE = $VERBOSE, nil - seed = Random::DEFAULT::seed - rand1 = Random::DEFAULT::rand + seed = Random.seed + rand1 = Random.rand $VERBOSE = verbose rand2 = Random.new(seed).rand assert_equal(rand1, rand2) diff --git a/test/ruby/test_random_formatter.rb b/test/ruby/test_random_formatter.rb new file mode 100644 index 0000000000..a5072099e1 --- /dev/null +++ b/test/ruby/test_random_formatter.rb @@ -0,0 +1,123 @@ +require 'test/unit' +require 'random/formatter' + +module Random::Formatter + module FormatterTest + def test_random_bytes + assert_equal(16, @it.random_bytes.size) + assert_equal(Encoding::ASCII_8BIT, @it.random_bytes.encoding) + 65.times do |idx| + assert_equal(idx, @it.random_bytes(idx).size) + end + end + + def test_hex + s = @it.hex + assert_equal(16 * 2, s.size) + assert_match(/\A\h+\z/, s) + 33.times do |idx| + s = @it.hex(idx) + assert_equal(idx * 2, s.size) + assert_match(/\A\h*\z/, s) + end + end + + def test_hex_encoding + assert_equal(Encoding::US_ASCII, @it.hex.encoding) + end + + def test_base64 + assert_equal(16, @it.base64.unpack1('m*').size) + 17.times do |idx| + assert_equal(idx, @it.base64(idx).unpack1('m*').size) + end + end + + def test_urlsafe_base64 + safe = /[\n+\/]/ + 65.times do |idx| + assert_not_match(safe, @it.urlsafe_base64(idx)) + end + # base64 can include unsafe byte + assert((0..10000).any? {|idx| safe =~ @it.base64(idx)}, "None of base64(0..10000) is url-safe") + end + + def test_random_number_float + 101.times do + v = @it.random_number + assert_in_range(0.0...1.0, v) + end + end + + def test_random_number_float_by_zero + 101.times do + v = @it.random_number(0) + assert_in_range(0.0...1.0, v) + end + end + + def test_random_number_int + 101.times do |idx| + next if idx.zero? + v = @it.random_number(idx) + assert_in_range(0...idx, v) + end + end + + def test_uuid + uuid = @it.uuid + assert_equal(36, uuid.size) + + # Check time_hi_and_version and clock_seq_hi_res bits (RFC 4122 4.4) + assert_equal('4', uuid[14]) + assert_include(%w'8 9 a b', uuid[19]) + + assert_match(/\A\h{8}-\h{4}-\h{4}-\h{4}-\h{12}\z/, uuid) + end + + def test_alphanumeric + 65.times do |n| + an = @it.alphanumeric(n) + assert_match(/\A[0-9a-zA-Z]*\z/, an) + assert_equal(n, an.length) + end + end + + def assert_in_range(range, result, mesg = nil) + assert(range.cover?(result), build_message(mesg, "Expected #{result} to be in #{range}")) + end + end + + module NotDefaultTest + def test_random_number_not_default + msg = "random_number should not be affected by srand" + seed = srand(0) + x = @it.random_number(1000) + 10.times do|i| + srand(0) + return unless @it.random_number(1000) == x + end + srand(0) + assert_not_equal(x, @it.random_number(1000), msg) + ensure + srand(seed) if seed + end + end + + class TestClassMethods < Test::Unit::TestCase + include FormatterTest + + def setup + @it = Random + end + end + + class TestInstanceMethods < Test::Unit::TestCase + include FormatterTest + include NotDefaultTest + + def setup + @it = Random.new + end + end +end diff --git a/test/ruby/test_range.rb b/test/ruby/test_range.rb index 8ac1930be6..8789eca749 100644 --- a/test/ruby/test_range.rb +++ b/test/ruby/test_range.rb @@ -604,6 +604,10 @@ class TestRange < Test::Unit::TestCase assert_include(0...10, 5) assert_include(5..., 10) assert_not_include(5..., 0) + assert_include(.."z", "z") + assert_not_include(..."z", "z") + assert_include(..10, 10) + assert_not_include(...10, 10) end def test_cover diff --git a/test/ruby/test_refinement.rb b/test/ruby/test_refinement.rb index 19857b035c..c0754d8cf0 100644 --- a/test/ruby/test_refinement.rb +++ b/test/ruby/test_refinement.rb @@ -225,7 +225,7 @@ class TestRefinement < Test::Unit::TestCase end end def test_method_should_use_refinements - skip if Test::Unit::Runner.current_repeat_count > 0 + omit if Test::Unit::Runner.current_repeat_count > 0 foo = Foo.new assert_raise(NameError) { foo.method(:z) } @@ -248,7 +248,7 @@ class TestRefinement < Test::Unit::TestCase end end def test_instance_method_should_use_refinements - skip if Test::Unit::Runner.current_repeat_count > 0 + omit if Test::Unit::Runner.current_repeat_count > 0 foo = Foo.new assert_raise(NameError) { Foo.instance_method(:z) } @@ -754,134 +754,30 @@ class TestRefinement < Test::Unit::TestCase $VERBOSE = verbose end - module IncludeIntoRefinement - class C - def bar - return "C#bar" - end - - def baz - return "C#baz" - end - end - - module Mixin - def foo - return "Mixin#foo" - end - - def bar - return super << " Mixin#bar" - end - - def baz - return super << " Mixin#baz" - end - end - - module M - refine C do - TestRefinement.suppress_verbose do - include Mixin - end - - def baz - return super << " M#baz" - end - end - end - end - - eval <<-EOF, Sandbox::BINDING - using TestRefinement::IncludeIntoRefinement::M - - module TestRefinement::IncludeIntoRefinement::User - def self.invoke_foo_on(x) - x.foo - end - - def self.invoke_bar_on(x) - x.bar - end - - def self.invoke_baz_on(x) - x.baz - end - end - EOF - def test_include_into_refinement - x = IncludeIntoRefinement::C.new - assert_equal("Mixin#foo", IncludeIntoRefinement::User.invoke_foo_on(x)) - assert_equal("C#bar Mixin#bar", - IncludeIntoRefinement::User.invoke_bar_on(x)) - assert_equal("C#baz Mixin#baz M#baz", - IncludeIntoRefinement::User.invoke_baz_on(x)) - end - - module PrependIntoRefinement - class C - def bar - return "C#bar" - end - - def baz - return "C#baz" - end - end - - module Mixin - def foo - return "Mixin#foo" - end - - def bar - return super << " Mixin#bar" - end - - def baz - return super << " Mixin#baz" - end - end - - module M - refine C do - TestRefinement.suppress_verbose do - prepend Mixin - end + assert_raise(TypeError) do + c = Class.new + mixin = Module.new - def baz - return super << " M#baz" + Module.new do + refine c do + include mixin end end end end - eval <<-EOF, Sandbox::BINDING - using TestRefinement::PrependIntoRefinement::M - - module TestRefinement::PrependIntoRefinement::User - def self.invoke_foo_on(x) - x.foo - end - - def self.invoke_bar_on(x) - x.bar - end + def test_prepend_into_refinement + assert_raise(TypeError) do + c = Class.new + mixin = Module.new - def self.invoke_baz_on(x) - x.baz + Module.new do + refine c do + prepend mixin + end end end - EOF - - def test_prepend_into_refinement - x = PrependIntoRefinement::C.new - assert_equal("Mixin#foo", PrependIntoRefinement::User.invoke_foo_on(x)) - assert_equal("C#bar Mixin#bar", - PrependIntoRefinement::User.invoke_bar_on(x)) - assert_equal("C#baz M#baz Mixin#baz", - PrependIntoRefinement::User.invoke_baz_on(x)) end PrependAfterRefine_CODE = <<-EOC @@ -923,7 +819,7 @@ class TestRefinement < Test::Unit::TestCase def test_prepend_after_refine_wb_miss if /\A(arm|mips)/ =~ RUBY_PLATFORM - skip "too slow cpu" + omit "too slow cpu" end assert_normal_exit %Q{ GC.stress = true @@ -1791,6 +1687,8 @@ class TestRefinement < Test::Unit::TestCase refine Object do def in_ref_a end + + RefA.const_set(:REF, self) end end @@ -1798,6 +1696,8 @@ class TestRefinement < Test::Unit::TestCase refine Object do def in_ref_b end + + RefB.const_set(:REF, self) end end @@ -1807,23 +1707,28 @@ class TestRefinement < Test::Unit::TestCase refine Object do def in_ref_c end + + RefC.const_set(:REF, self) end end module Foo using RefB USED_MODS = Module.used_modules + USED_REFS = Module.used_refinements end module Bar using RefC USED_MODS = Module.used_modules + USED_REFS = Module.used_refinements end module Combined using RefA using RefB USED_MODS = Module.used_modules + USED_REFS = Module.used_refinements end end @@ -1835,6 +1740,41 @@ class TestRefinement < Test::Unit::TestCase assert_equal [ref::RefB, ref::RefA], ref::Combined::USED_MODS end + def test_used_refinements + ref = VisibleRefinements + assert_equal [], Module.used_refinements + assert_equal [ref::RefB::REF], ref::Foo::USED_REFS + assert_equal [ref::RefC::REF], ref::Bar::USED_REFS + assert_equal [ref::RefB::REF, ref::RefA::REF], ref::Combined::USED_REFS + end + + def test_refinements + int_refinement = nil + str_refinement = nil + m = Module.new { + refine Integer do + int_refinement = self + end + + refine String do + str_refinement = self + end + } + assert_equal([int_refinement, str_refinement], m.refinements) + end + + def test_refined_class + refinements = Module.new { + refine Integer do + end + + refine String do + end + }.refinements + assert_equal(Integer, refinements[0].refined_class) + assert_equal(String, refinements[1].refined_class) + end + def test_warn_setconst_in_refinmenet bug10103 = '[ruby-core:64143] [Bug #10103]' warnings = [ @@ -1979,10 +1919,10 @@ class TestRefinement < Test::Unit::TestCase m = Module.new do r = refine(String) {def test;:ok end} end - assert_raise_with_message(ArgumentError, /refinement/, bug) do + assert_raise_with_message(TypeError, /refinement/, bug) do m.module_eval {include r} end - assert_raise_with_message(ArgumentError, /refinement/, bug) do + assert_raise_with_message(TypeError, /refinement/, bug) do m.module_eval {prepend r} end end @@ -2626,18 +2566,6 @@ class TestRefinement < Test::Unit::TestCase end end - module D - refine A do - TestRefinement.suppress_verbose do - include B - end - - def foo - "refined" - end - end - end - module UsingC using C @@ -2645,19 +2573,10 @@ class TestRefinement < Test::Unit::TestCase A.new.bar end end - - module UsingD - using D - - def self.call_bar - A.new.bar - end - end end def test_import_methods assert_equal("refined:bar", TestImport::UsingC.call_bar) - assert_equal("original:bar", TestImport::UsingD.call_bar) assert_raise(ArgumentError) do Module.new do diff --git a/test/ruby/test_regexp.rb b/test/ruby/test_regexp.rb index 2bf4649f14..84687c5380 100644 --- a/test/ruby/test_regexp.rb +++ b/test/ruby/test_regexp.rb @@ -424,6 +424,27 @@ class TestRegexp < Test::Unit::TestCase assert_equal([2, 3], m.offset(3)) end + def test_match_byteoffset_begin_end + m = /(?<x>b..)/.match("foobarbaz") + assert_equal([3, 6], m.byteoffset("x")) + assert_equal(3, m.begin("x")) + assert_equal(6, m.end("x")) + assert_raise(IndexError) { m.byteoffset("y") } + assert_raise(IndexError) { m.byteoffset(2) } + assert_raise(IndexError) { m.begin(2) } + assert_raise(IndexError) { m.end(2) } + + m = /(?<x>q..)?/.match("foobarbaz") + assert_equal([nil, nil], m.byteoffset("x")) + assert_equal(nil, m.begin("x")) + assert_equal(nil, m.end("x")) + + m = /\A\u3042(.)(.)?(.)\z/.match("\u3042\u3043\u3044") + assert_equal([3, 6], m.byteoffset(1)) + assert_equal([nil, nil], m.byteoffset(2)) + assert_equal([6, 9], m.byteoffset(3)) + end + def test_match_to_s m = /(?<x>b..)/.match("foobarbaz") assert_equal("bar", m.to_s) @@ -467,6 +488,7 @@ class TestRegexp < Test::Unit::TestCase assert_nil(m[5]) assert_raise(IndexError) { m[:foo] } assert_raise(TypeError) { m[nil] } + assert_equal(["baz", nil], m[-2, 3]) end def test_match_values_at @@ -536,6 +558,8 @@ class TestRegexp < Test::Unit::TestCase def test_initialize assert_raise(ArgumentError) { Regexp.new } assert_equal(/foo/, assert_warning(/ignored/) {Regexp.new(/foo/, Regexp::IGNORECASE)}) + assert_equal(/foo/, assert_no_warning(/ignored/) {Regexp.new(/foo/)}) + assert_equal(/foo/, assert_no_warning(/ignored/) {Regexp.new(/foo/, timeout: nil)}) assert_equal(Encoding.find("US-ASCII"), Regexp.new("b..", nil, "n").encoding) assert_equal("bar", "foobarbaz"[Regexp.new("b..", nil, "n")]) @@ -1184,6 +1208,11 @@ class TestRegexp < Test::Unit::TestCase assert_no_match(/^\p{age=12.0}$/u, "\u32FF") assert_match(/^\p{age=12.1}$/u, "\u32FF") + assert_no_match(/^\p{age=13.0}$/u, "\u{10570}") + assert_match(/^\p{age=14.0}$/u, "\u{10570}") + assert_match(/^\p{age=14.0}$/u, "\u9FFF") + assert_match(/^\p{age=14.0}$/u, "\u{2A6DF}") + assert_match(/^\p{age=14.0}$/u, "\u{2B738}") end MatchData_A = eval("class MatchData_\u{3042} < MatchData; self; end") @@ -1396,6 +1425,21 @@ class TestRegexp < Test::Unit::TestCase end end + def test_bug18631 + assert_kind_of MatchData, /(?<x>a)(?<x>aa)\k<x>/.match("aaaaa") + assert_kind_of MatchData, /(?<x>a)(?<x>aa)\k<x>/.match("aaaa") + assert_kind_of MatchData, /(?<x>a)(?<x>aa)\k<x>/.match("aaaab") + end + + def test_invalid_group + assert_separately([], "#{<<-"begin;"}\n#{<<-'end;'}") + begin; + assert_raise_with_message(RegexpError, /invalid conditional pattern/) do + Regexp.new("((?(1)x|x|)x)+") + end + end; + end + # This assertion is for porting x2() tests in testpy.py of Onigmo. def assert_match_at(re, str, positions, msg = nil) re = Regexp.new(re) unless re.is_a?(Regexp) @@ -1425,4 +1469,43 @@ class TestRegexp < Test::Unit::TestCase } assert_empty(errs, msg) end + + def test_s_timeout + assert_separately([], "#{<<-"begin;"}\n#{<<-"end;"}") + begin; + timeout = EnvUtil.apply_timeout_scale(0.2) + + Regexp.timeout = timeout + assert_equal(timeout, Regexp.timeout) + + t = Time.now + assert_raise_with_message(Regexp::TimeoutError, "regexp match timeout") do + # A typical ReDoS case + /^(a*)*$/ =~ "a" * 1000000 + "x" + end + t = Time.now - t + + assert_in_delta(timeout, t, timeout / 2) + end; + end + + def test_timeout + assert_separately([], "#{<<-"begin;"}\n#{<<-"end;"}") + begin; + dummy_timeout = EnvUtil.apply_timeout_scale(10) + timeout = EnvUtil.apply_timeout_scale(0.2) + + Regexp.timeout = dummy_timeout # This should be ignored + + re = Regexp.new("^a*b?a*$", timeout: timeout) + + t = Time.now + assert_raise_with_message(Regexp::TimeoutError, "regexp match timeout") do + re =~ "a" * 1000000 + "x" + end + t = Time.now - t + + assert_in_delta(timeout, t, timeout / 2) + end; + end end diff --git a/test/ruby/test_require.rb b/test/ruby/test_require.rb index 77cdae64d9..5a24cb1ba5 100644 --- a/test/ruby/test_require.rb +++ b/test/ruby/test_require.rb @@ -93,7 +93,7 @@ class TestRequire < Test::Unit::TestCase begin require_path = File.join(tmp, dir, 'foo.rb').encode(encoding) rescue - skip "cannot convert path encoding to #{encoding}" + omit "cannot convert path encoding to #{encoding}" end Dir.mkdir(File.dirname(require_path)) open(require_path, "wb") {|f| f.puts '$:.push __FILE__'} @@ -175,7 +175,7 @@ class TestRequire < Test::Unit::TestCase t.close path = File.expand_path(t.path).sub(/\A(\w):/, '//127.0.0.1/\1$') - skip "local drive #$1: is not shared" unless File.exist?(path) + omit "local drive #$1: is not shared" unless File.exist?(path) args = ['--disable-gems', "-I#{File.dirname(path)}"] assert_in_out_err(args, "#{<<~"END;"}", [path], []) begin @@ -460,7 +460,7 @@ class TestRequire < Test::Unit::TestCase result = IO.popen([EnvUtil.rubybin, "b/tst.rb"], &:read) assert_equal("a/lib.rb\n", result, "[ruby-dev:40040]") rescue NotImplementedError, Errno::EACCES - skip "File.symlink is not implemented" + omit "File.symlink is not implemented" end } } @@ -486,7 +486,7 @@ class TestRequire < Test::Unit::TestCase result = IO.popen([EnvUtil.rubybin, "c.rb"], &:read) assert_equal("1", result, "bug17885 [ruby-core:104010]") rescue NotImplementedError, Errno::EACCES - skip "File.symlink is not implemented" + omit "File.symlink is not implemented" end } } @@ -850,7 +850,7 @@ class TestRequire < Test::Unit::TestCase end if File.respond_to?(:mkfifo) def test_loading_fifo_fd_leak - skip if RUBY_PLATFORM =~ /android/ # https://rubyci.org/logs/rubyci.s3.amazonaws.com/android29-x86_64/ruby-master/log/20200419T124100Z.fail.html.gz + omit if RUBY_PLATFORM =~ /android/ # https://rubyci.org/logs/rubyci.s3.amazonaws.com/android29-x86_64/ruby-master/log/20200419T124100Z.fail.html.gz Tempfile.create(%w'fifo .rb') {|f| f.close @@ -911,7 +911,7 @@ class TestRequire < Test::Unit::TestCase begin File.symlink "real", File.join(tmp, "symlink") rescue NotImplementedError, Errno::EACCES - skip "File.symlink is not implemented" + omit "File.symlink is not implemented" end File.write(File.join(tmp, "real/test_symlink_load_path.rb"), "print __FILE__") result = IO.popen([EnvUtil.rubybin, "-I#{tmp}/symlink", "-e", "require 'test_symlink_load_path.rb'"], &:read) diff --git a/test/ruby/test_require_lib.rb b/test/ruby/test_require_lib.rb index 6b2846c8fd..95fa3f29e1 100644 --- a/test/ruby/test_require_lib.rb +++ b/test/ruby/test_require_lib.rb @@ -18,7 +18,7 @@ class TestRequireLib < Test::Unit::TestCase begin require #{lib.dump} rescue Exception - skip $! + omit $! end assert_equal n, Thread.list.size end; diff --git a/test/ruby/test_rubyoptions.rb b/test/ruby/test_rubyoptions.rb index b4080010e2..ab15006e4c 100644 --- a/test/ruby/test_rubyoptions.rb +++ b/test/ruby/test_rubyoptions.rb @@ -10,8 +10,8 @@ class TestRubyOptions < Test::Unit::TestCase def self.yjit_enabled? = defined?(RubyVM::YJIT.enabled?) && RubyVM::YJIT.enabled? NO_JIT_DESCRIPTION = - if defined?(RubyVM::JIT) && RubyVM::JIT.enabled? # checking -DMJIT_FORCE_ENABLE - RUBY_DESCRIPTION.sub(/\+JIT /, '') + if defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? # checking -DMJIT_FORCE_ENABLE + RUBY_DESCRIPTION.sub(/\+MJIT /, '') elsif yjit_enabled? # checking -DYJIT_FORCE_ENABLE RUBY_DESCRIPTION.sub(/\+YJIT /, '') else @@ -121,6 +121,8 @@ class TestRubyOptions < Test::Unit::TestCase assert_in_out_err(["--disable-gems", "--debug", "-e", "p $DEBUG"], "", %w(true), []) + + assert_in_out_err(["--disable-gems", "--debug-", "-e", "p $DEBUG"], "", %w(), /invalid option --debug-/) end q = Regexp.method(:quote) @@ -137,7 +139,7 @@ class TestRubyOptions < Test::Unit::TestCase VERSION_PATTERN_WITH_JIT = case RUBY_ENGINE when 'ruby' - /^ruby #{q[RUBY_VERSION]}(?:[p ]|dev|rc).*? \+JIT \[#{q[RUBY_PLATFORM]}\]$/ + /^ruby #{q[RUBY_VERSION]}(?:[p ]|dev|rc).*? \+MJIT \[#{q[RUBY_PLATFORM]}\]$/ else VERSION_PATTERN end @@ -146,7 +148,7 @@ class TestRubyOptions < Test::Unit::TestCase def test_verbose assert_in_out_err([{'RUBY_YJIT_ENABLE' => nil}, "-vve", ""]) do |r, e| assert_match(VERSION_PATTERN, r[0]) - if defined?(RubyVM::JIT) && RubyVM::JIT.enabled? && !mjit_force_enabled? # checking -DMJIT_FORCE_ENABLE + if defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? && !mjit_force_enabled? # checking -DMJIT_FORCE_ENABLE assert_equal(NO_JIT_DESCRIPTION, r[0]) elsif self.class.yjit_enabled? && !yjit_force_enabled? # checking -DYJIT_FORCE_ENABLE assert_equal(NO_JIT_DESCRIPTION, r[0]) @@ -214,7 +216,7 @@ class TestRubyOptions < Test::Unit::TestCase assert_match(VERSION_PATTERN, r[0]) if ENV['RUBY_YJIT_ENABLE'] == '1' assert_equal(NO_JIT_DESCRIPTION, r[0]) - elsif defined?(RubyVM::JIT) && RubyVM::JIT.enabled? || self.class.yjit_enabled? # checking -D(M|Y)JIT_FORCE_ENABLE + elsif defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? || self.class.yjit_enabled? # checking -D(M|Y)JIT_FORCE_ENABLE assert_equal(EnvUtil.invoke_ruby(['-e', 'print RUBY_DESCRIPTION'], '', true).first, r[0]) else assert_equal(RUBY_DESCRIPTION, r[0]) @@ -226,9 +228,14 @@ class TestRubyOptions < Test::Unit::TestCase return if yjit_force_enabled? [ - %w(--version --jit --disable=jit), - %w(--version --enable=jit --disable=jit), - %w(--version --enable-jit --disable-jit), + %w(--version --mjit --disable=mjit), + %w(--version --enable=mjit --disable=mjit), + %w(--version --enable-mjit --disable-mjit), + *([ + %w(--version --jit --disable=jit), + %w(--version --enable=jit --disable=jit), + %w(--version --enable-jit --disable-jit), + ] unless JITSupport.yjit_supported?), ].each do |args| assert_in_out_err([env] + args) do |r, e| assert_match(VERSION_PATTERN, r[0]) @@ -239,16 +246,21 @@ class TestRubyOptions < Test::Unit::TestCase if JITSupport.supported? [ - %w(--version --jit), - %w(--version --enable=jit), - %w(--version --enable-jit), + %w(--version --mjit), + %w(--version --enable=mjit), + %w(--version --enable-mjit), + *([ + %w(--version --jit), + %w(--version --enable=jit), + %w(--version --enable-jit), + ] unless JITSupport.yjit_supported?), ].each do |args| assert_in_out_err([env] + args) do |r, e| assert_match(VERSION_PATTERN_WITH_JIT, r[0]) - if defined?(RubyVM::JIT) && RubyVM::JIT.enabled? # checking -DMJIT_FORCE_ENABLE + if defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? # checking -DMJIT_FORCE_ENABLE assert_equal(RUBY_DESCRIPTION, r[0]) else - assert_equal(EnvUtil.invoke_ruby([env, '--jit', '-e', 'print RUBY_DESCRIPTION'], '', true).first, r[0]) + assert_equal(EnvUtil.invoke_ruby([env, '--mjit', '-e', 'print RUBY_DESCRIPTION'], '', true).first, r[0]) end assert_equal([], e) end @@ -345,9 +357,9 @@ class TestRubyOptions < Test::Unit::TestCase assert_in_out_err(%W(-\r -e) + [""], "", [], []) - assert_in_out_err(%W(-\rx), "", [], /invalid option -\\r \(-h will show valid options\) \(RuntimeError\)/) + assert_in_out_err(%W(-\rx), "", [], /invalid option -[\r\n] \(-h will show valid options\) \(RuntimeError\)/) - assert_in_out_err(%W(-\x01), "", [], /invalid option -\\x01 \(-h will show valid options\) \(RuntimeError\)/) + assert_in_out_err(%W(-\x01), "", [], /invalid option -\x01 \(-h will show valid options\) \(RuntimeError\)/) assert_in_out_err(%w(-Z), "", [], /invalid option -Z \(-h will show valid options\) \(RuntimeError\)/) end @@ -664,7 +676,7 @@ class TestRubyOptions < Test::Unit::TestCase end def test_set_program_name - skip "platform dependent feature" unless defined?(PSCMD) and PSCMD + omit "platform dependent feature" unless defined?(PSCMD) and PSCMD with_tmpchdir do write_file("test-script", "$0 = 'hello world'; /test-script/ =~ Process.argv0 or $0 = 'Process.argv0 changed!'; sleep 60") @@ -687,7 +699,7 @@ class TestRubyOptions < Test::Unit::TestCase end def test_setproctitle - skip "platform dependent feature" unless defined?(PSCMD) and PSCMD + omit "platform dependent feature" unless defined?(PSCMD) and PSCMD assert_separately([], "#{<<-"{#"}\n#{<<-'};'}") {# @@ -750,6 +762,7 @@ class TestRubyOptions < Test::Unit::TestCase %r( (?: --\sC\slevel\sbacktrace\sinformation\s-------------------------------------------\n + (?:Un(?:expected|supported|known)\s.*\n)* (?:(?:.*\s)?\[0x\h+\].*\n|.*:\d+\n)*\n )? )x, @@ -762,7 +775,7 @@ class TestRubyOptions < Test::Unit::TestCase end def assert_segv(args, message=nil) - skip if ENV['RUBY_ON_BUG'] + omit if ENV['RUBY_ON_BUG'] test_stdin = "" opt = SEGVTest::ExecOptions.dup @@ -847,7 +860,7 @@ class TestRubyOptions < Test::Unit::TestCase Process.wait pid } rescue RuntimeError - skip $! + omit $! end } assert_equal("", result, '[ruby-dev:37798]') @@ -897,7 +910,7 @@ class TestRubyOptions < Test::Unit::TestCase name = c.chr(Encoding::UTF_8) expected = name.encode("locale") rescue nil } - skip "can't make locale name" + omit "can't make locale name" end name << ".rb" expected << ".rb" @@ -1105,15 +1118,15 @@ class TestRubyOptions < Test::Unit::TestCase end def test_null_script - skip "#{IO::NULL} is not a character device" unless File.chardev?(IO::NULL) + omit "#{IO::NULL} is not a character device" unless File.chardev?(IO::NULL) assert_in_out_err([IO::NULL], success: true) end - def test_jit_debug + def test_mjit_debug # mswin uses prebuilt precompiled header. Thus it does not show a pch compilation log to check "-O0 -O1". if JITSupport.supported? && !RUBY_PLATFORM.match?(/mswin/) env = { 'MJIT_SEARCH_BUILD_DIR' => 'true' } - assert_in_out_err([env, "--disable-yjit", "--jit-debug=-O0 -O1", "--jit-verbose=2", "" ], "", [], /-O0 -O1/) + assert_in_out_err([env, "--disable-yjit", "--mjit-debug=-O0 -O1", "--mjit-verbose=2", "" ], "", [], /-O0 -O1/) end end diff --git a/test/ruby/test_rubyvm.rb b/test/ruby/test_rubyvm.rb index 7d4588a165..d0b7cba341 100644 --- a/test/ruby/test_rubyvm.rb +++ b/test/ruby/test_rubyvm.rb @@ -4,11 +4,11 @@ require 'test/unit' class TestRubyVM < Test::Unit::TestCase def test_stat assert_kind_of Hash, RubyVM.stat - assert_kind_of Integer, RubyVM.stat[:global_constant_state] + assert_kind_of Integer, RubyVM.stat[:class_serial] RubyVM.stat(stat = {}) assert_not_empty stat - assert_equal stat[:global_constant_state], RubyVM.stat(:global_constant_state) + assert_equal stat[:class_serial], RubyVM.stat(:class_serial) end def test_stat_unknown @@ -34,6 +34,8 @@ class TestRubyVM < Test::Unit::TestCase end def test_keep_script_lines + pend if ENV['RUBY_ISEQ_DUMP_DEBUG'] # TODO + prev_conf = RubyVM.keep_script_lines # keep diff --git a/test/ruby/test_rubyvm_jit.rb b/test/ruby/test_rubyvm_mjit.rb index 2104ce3d18..94b773c4e6 100644 --- a/test/ruby/test_rubyvm_jit.rb +++ b/test/ruby/test_rubyvm_mjit.rb @@ -4,12 +4,12 @@ require_relative '../lib/jit_support' return if RbConfig::CONFIG["MJIT_SUPPORT"] == 'no' -class TestRubyVMJIT < Test::Unit::TestCase +class TestRubyVMMJIT < Test::Unit::TestCase include JITSupport def setup unless JITSupport.supported? - skip 'JIT seems not supported on this platform' + omit 'JIT seems not supported on this platform' end end @@ -20,13 +20,13 @@ class TestRubyVMJIT < Test::Unit::TestCase eval("def mjit#{i}; end; mjit#{i}") i += 1 end - print RubyVM::JIT.pause - print RubyVM::JIT.pause + print RubyVM::MJIT.pause + print RubyVM::MJIT.pause while i < 10 eval("def mjit#{i}; end; mjit#{i}") i += 1 end - print RubyVM::JIT.pause # no JIT here + print RubyVM::MJIT.pause # no JIT here EOS assert_equal('truefalsefalse', out) assert_equal( @@ -39,7 +39,7 @@ class TestRubyVMJIT < Test::Unit::TestCase out, err = eval_with_jit(<<~'EOS', verbose: 1, min_calls: 1, wait: false) def a() end; a def b() end; b - RubyVM::JIT.pause + RubyVM::MJIT.pause EOS assert_equal( 2, err.scan(/#{JITSupport::JIT_SUCCESS_PREFIX}/).size, @@ -58,7 +58,7 @@ class TestRubyVMJIT < Test::Unit::TestCase eval("def mjit#{i}; end; mjit#{i}") i += 1 end - print RubyVM::JIT.pause + print RubyVM::MJIT.pause EOS assert_equal('true', out) end @@ -70,8 +70,8 @@ class TestRubyVMJIT < Test::Unit::TestCase eval("def mjit#{i}; end; mjit#{i}") i += 1 end - print RubyVM::JIT.pause(wait: false) - print RubyVM::JIT.pause(wait: false) + print RubyVM::MJIT.pause(wait: false) + print RubyVM::MJIT.pause(wait: false) EOS assert_equal('truefalse', out) assert_equal(true, err.scan(/#{JITSupport::JIT_SUCCESS_PREFIX}/).size < 10) @@ -79,11 +79,11 @@ class TestRubyVMJIT < Test::Unit::TestCase def test_resume out, err = eval_with_jit(<<~'EOS', verbose: 1, min_calls: 1, wait: false) - print RubyVM::JIT.resume - print RubyVM::JIT.pause - print RubyVM::JIT.resume - print RubyVM::JIT.resume - print RubyVM::JIT.pause + print RubyVM::MJIT.resume + print RubyVM::MJIT.pause + print RubyVM::MJIT.resume + print RubyVM::MJIT.resume + print RubyVM::MJIT.pause EOS assert_equal('falsetruetruefalsetrue', out) assert_equal(0, err.scan(/#{JITSupport::JIT_SUCCESS_PREFIX}/).size) diff --git a/test/ruby/test_settracefunc.rb b/test/ruby/test_settracefunc.rb index 4a37426531..b43f9c114d 100644 --- a/test/ruby/test_settracefunc.rb +++ b/test/ruby/test_settracefunc.rb @@ -108,6 +108,10 @@ class TestSetTraceFunc < Test::Unit::TestCase events.shift) assert_equal(["line", 4, __method__, self.class], events.shift) + assert_equal(["c-call", 4, :const_added, Module], + events.shift) + assert_equal(["c-return", 4, :const_added, Module], + events.shift) assert_equal(["c-call", 4, :inherited, Class], events.shift) assert_equal(["c-return", 4, :inherited, Class], @@ -345,6 +349,8 @@ class TestSetTraceFunc < Test::Unit::TestCase [["c-return", 2, :add_trace_func, Thread], ["line", 3, __method__, self.class], + ["c-call", 3, :const_added, Module], + ["c-return", 3, :const_added, Module], ["c-call", 3, :inherited, Class], ["c-return", 3, :inherited, Class], ["class", 3, nil, nil], @@ -393,7 +399,7 @@ class TestSetTraceFunc < Test::Unit::TestCase [["c-return", 3, :set_trace_func, Kernel], ["line", 6, __method__, self.class], ["call", 1, :foobar, FooBar], - ["return", 6, :foobar, FooBar], + ["return", 1, :foobar, FooBar], ["line", 7, __method__, self.class], ["c-call", 7, :set_trace_func, Kernel]].each{|e| assert_equal(e, events.shift) @@ -487,6 +493,8 @@ class TestSetTraceFunc < Test::Unit::TestCase [:line, 5, 'xyzzy', self.class, method, self, :inner, :nothing], [:c_return, 4, "xyzzy", Integer, :times, 1, :outer, 1], [:line, 7, 'xyzzy', self.class, method, self, :outer, :nothing], + [:c_call, 7, "xyzzy", Module, :const_added, TestSetTraceFunc, :outer, :nothing], + [:c_return, 7, "xyzzy", Module, :const_added, TestSetTraceFunc, :outer, nil], [:c_call, 7, "xyzzy", Class, :inherited, Object, :outer, :nothing], [:c_return, 7, "xyzzy", Class, :inherited, Object, :outer, nil], [:class, 7, "xyzzy", nil, nil, xyzzy.class, nil, :nothing], @@ -586,7 +594,7 @@ CODE eval <<-EOF.gsub(/^.*?: /, ""), nil, 'xyzzy' 1: set_trace_func(lambda{|event, file, line, id, binding, klass| - 2: events << [event, line, file, klass, id, binding.eval('self'), binding.eval("_local_var")] if file == 'xyzzy' + 2: events << [event, line, file, klass, id, binding&.eval('self'), binding&.eval("_local_var")] if file == 'xyzzy' 3: }) 4: 1.times{|;_local_var| _local_var = :inner 5: tap{} @@ -611,29 +619,31 @@ CODE answer_events = [ # - [:c_return, 1, "xyzzy", TracePoint, :trace, TracePoint, :outer, trace], + [:c_return, 1, "xyzzy", TracePoint, :trace, TracePoint, nil, nil], [:line, 4, 'xyzzy', self.class, method, self, :outer, :nothing], - [:c_call, 4, 'xyzzy', Integer, :times, 1, :outer, :nothing], + [:c_call, 4, 'xyzzy', Integer, :times, 1, nil, nil], [:line, 4, 'xyzzy', self.class, method, self, nil, :nothing], [:line, 5, 'xyzzy', self.class, method, self, :inner, :nothing], - [:c_return, 4, "xyzzy", Integer, :times, 1, :outer, 1], + [:c_return, 4, "xyzzy", Integer, :times, 1, nil, nil], [:line, 7, 'xyzzy', self.class, method, self, :outer, :nothing], - [:c_call, 7, "xyzzy", Class, :inherited, Object, :outer, :nothing], - [:c_return, 7, "xyzzy", Class, :inherited, Object, :outer, nil], + [:c_call, 7, "xyzzy", Class, :inherited, Object, nil, nil], + [:c_return, 7, "xyzzy", Class, :inherited, Object, nil, nil], + [:c_call, 7, "xyzzy", Class, :const_added, Object, nil, nil], + [:c_return, 7, "xyzzy", Class, :const_added, Object, nil, nil], [:class, 7, "xyzzy", nil, nil, xyzzy.class, nil, :nothing], [:line, 8, "xyzzy", nil, nil, xyzzy.class, nil, :nothing], [:line, 9, "xyzzy", nil, nil, xyzzy.class, :XYZZY_outer, :nothing], - [:c_call, 9, "xyzzy", Module, :method_added, xyzzy.class, :XYZZY_outer, :nothing], - [:c_return, 9, "xyzzy", Module, :method_added, xyzzy.class, :XYZZY_outer, nil], + [:c_call, 9, "xyzzy", Module, :method_added, xyzzy.class, nil, nil], + [:c_return, 9, "xyzzy", Module, :method_added, xyzzy.class, nil, nil], [:line, 13, "xyzzy", nil, nil, xyzzy.class, :XYZZY_outer, :nothing], - [:c_call, 13, "xyzzy", Module, :method_added, xyzzy.class, :XYZZY_outer, :nothing], - [:c_return,13, "xyzzy", Module, :method_added, xyzzy.class, :XYZZY_outer, nil], + [:c_call, 13, "xyzzy", Module, :method_added, xyzzy.class, nil, nil], + [:c_return,13, "xyzzy", Module, :method_added, xyzzy.class, nil, nil], [:end, 17, "xyzzy", nil, nil, xyzzy.class, :XYZZY_outer, :nothing], [:line, 18, "xyzzy", TestSetTraceFunc, method, self, :outer, :nothing], - [:c_call, 18, "xyzzy", Class, :new, xyzzy.class, :outer, :nothing], - [:c_call, 18, "xyzzy", BasicObject, :initialize, xyzzy, :outer, :nothing], - [:c_return,18, "xyzzy", BasicObject, :initialize, xyzzy, :outer, nil], - [:c_return,18, "xyzzy", Class, :new, xyzzy.class, :outer, xyzzy], + [:c_call, 18, "xyzzy", Class, :new, xyzzy.class, nil, nil], + [:c_call, 18, "xyzzy", BasicObject, :initialize, xyzzy, nil, nil], + [:c_return,18, "xyzzy", BasicObject, :initialize, xyzzy, nil, nil], + [:c_return,18, "xyzzy", Class, :new, xyzzy.class, nil, nil], [:line, 19, "xyzzy", TestSetTraceFunc, method, self, :outer, :nothing], [:call, 9, "xyzzy", xyzzy.class, :foo, xyzzy, nil, :nothing], [:line, 10, "xyzzy", xyzzy.class, :foo, xyzzy, nil, :nothing], @@ -644,23 +654,29 @@ CODE [:return, 16, "xyzzy", xyzzy.class, :bar, xyzzy, :XYZZY_bar, xyzzy], [:return, 12, "xyzzy", xyzzy.class, :foo, xyzzy, :XYZZY_foo, xyzzy], [:line, 20, "xyzzy", TestSetTraceFunc, method, self, :outer, :nothing], - [:c_call, 20, "xyzzy", Kernel, :raise, self, :outer, :nothing], - [:c_call, 20, "xyzzy", Exception, :exception, RuntimeError, :outer, :nothing], - [:c_call, 20, "xyzzy", Exception, :initialize, raised_exc, :outer, :nothing], - [:c_return,20, "xyzzy", Exception, :initialize, raised_exc, :outer, raised_exc], - [:c_return,20, "xyzzy", Exception, :exception, RuntimeError, :outer, raised_exc], - [:c_return,20, "xyzzy", Kernel, :raise, self, :outer, nil], - [:c_call, 20, "xyzzy", Exception, :backtrace, raised_exc, :outer, :nothing], - [:c_return,20, "xyzzy", Exception, :backtrace, raised_exc, :outer, nil], + [:c_call, 20, "xyzzy", Kernel, :raise, self, nil, nil], + [:c_call, 20, "xyzzy", Exception, :exception, RuntimeError, nil, nil], + [:c_call, 20, "xyzzy", Exception, :initialize, raised_exc, nil, nil], + [:c_return,20, "xyzzy", Exception, :initialize, raised_exc, nil, nil], + [:c_return,20, "xyzzy", Exception, :exception, RuntimeError, nil, nil], + [:c_return,20, "xyzzy", Kernel, :raise, self, nil, nil], + [:c_call, 20, "xyzzy", Exception, :backtrace, raised_exc, nil, nil], + [:c_return,20, "xyzzy", Exception, :backtrace, raised_exc, nil, nil], [:raise, 20, "xyzzy", TestSetTraceFunc, :trace_by_tracepoint, self, :outer, raised_exc], - [:c_call, 20, "xyzzy", Module, :===, RuntimeError,:outer, :nothing], - [:c_return,20, "xyzzy", Module, :===, RuntimeError,:outer, true], + [:c_call, 20, "xyzzy", Module, :===, RuntimeError, nil, nil], + [:c_return,20, "xyzzy", Module, :===, RuntimeError, nil, nil], [:line, 21, "xyzzy", TestSetTraceFunc, method, self, :outer, :nothing], - [:c_call, 21, "xyzzy", TracePoint, :disable, trace, :outer, :nothing], + [:c_call, 21, "xyzzy", TracePoint, :disable, trace, nil, nil], ] return events, answer_events end + def test_set_trace_func_curry_argument_error + b = lambda {|x, y, z| (x||0) + (y||0) + (z||0) }.curry[1, 2] + set_trace_func(proc {}) + assert_raise(ArgumentError) {b[3, 4]} + end + def test_set_trace_func actual_events, expected_events = trace_by_set_trace_func expected_events.zip(actual_events){|e, a| @@ -717,25 +733,30 @@ CODE def test_tracepoint_enable ary = [] args = nil - trace = TracePoint.new(:call){|tp| - next if !target_thread? - ary << tp.method_id - } - foo - trace.enable{|*a| - args = a + begin + trace = TracePoint.new(:call){|tp| + next if !target_thread? + ary << tp.method_id + } foo - } - foo - assert_equal([:foo], ary) - assert_equal([], args) + trace.enable(target_thread: nil){|*a| + args = a + foo + } + foo + assert_equal([:foo], ary) + assert_equal([], args) + ensure + trace&.disable + end trace = TracePoint.new{} begin assert_equal(false, trace.enable) assert_equal(true, trace.enable) - trace.enable{} - assert_equal(true, trace.enable) + trace.enable(target_thread: nil){} + trace.disable + assert_equal(false, trace.enable) ensure trace.disable end @@ -967,7 +988,7 @@ CODE tp.defined_class, #=> nil, tp.self.class # tp.self return creating/ending thread ] - }.enable{ + }.enable(target_thread: nil){ created_thread = Thread.new{thread_self = self} created_thread.join } @@ -1951,7 +1972,7 @@ CODE end define_method(:f_break_defined) do - return :f_break_defined + break :f_break_defined end define_method(:f_raise_defined) do @@ -1972,27 +1993,44 @@ CODE tp_return_value(:f_last_defined), '[Bug #13369]' - assert_equal [[:b_return, :f_return_defined, nil], # current limitation + assert_equal [[:b_return, :f_return_defined, :f_return_defined], [:return, :f_return_defined, :f_return_defined]], tp_return_value(:f_return_defined), '[Bug #13369]' - assert_equal [[:b_return, :f_break_defined, nil], + assert_equal [[:b_return, :f_break_defined, :f_break_defined], [:return, :f_break_defined, :f_break_defined]], tp_return_value(:f_break_defined), '[Bug #13369]' - assert_equal [[:b_return, :f_raise_defined, nil], + assert_equal [[:b_return, :f_raise_defined, f_raise_defined], [:return, :f_raise_defined, f_raise_defined]], tp_return_value(:f_raise_defined), '[Bug #13369]' - assert_equal [[:b_return, :f_break_in_rescue_defined, nil], + assert_equal [[:b_return, :f_break_in_rescue_defined, f_break_in_rescue_defined], [:return, :f_break_in_rescue_defined, f_break_in_rescue_defined]], tp_return_value(:f_break_in_rescue_defined), '[Bug #13369]' end + define_method(:just_yield) do |&block| + block.call + end + + define_method(:unwind_multiple_bmethods) do + just_yield { return :unwind_multiple_bmethods } + end + + def test_non_local_return_across_multiple_define_methods + assert_equal [[:b_return, :unwind_multiple_bmethods, nil], + [:b_return, :just_yield, nil], + [:return, :just_yield, nil], + [:b_return, :unwind_multiple_bmethods, :unwind_multiple_bmethods], + [:return, :unwind_multiple_bmethods, :unwind_multiple_bmethods]], + tp_return_value(:unwind_multiple_bmethods) + end + def f_iter yield end @@ -2089,7 +2127,7 @@ CODE Thread.pass until t.status == 'sleep' # When MJIT thread exists, t.status becomes 'sleep' even if it does not reach m2t_q.pop. # This sleep forces it to reach m2t_q.pop for --jit-wait. - sleep 1 if defined?(RubyVM::JIT) && RubyVM::JIT.enabled? + sleep 1 if defined?(RubyVM::MJIT) && RubyVM::MJIT.enabled? t.add_trace_func proc{|ev, file, line, *args| if file == __FILE__ @@ -2212,7 +2250,7 @@ CODE # global TP and targeted TP ex = assert_raise(ArgumentError) do tp = TracePoint.new(:line){} - tp.enable{ + tp.enable(target_thread: nil){ tp.enable(target: code2){} } end @@ -2354,7 +2392,7 @@ CODE } assert_equal [], events, 'script_compiled event should not be invoked on compile error' - skip "TODO: test for requires" + omit "TODO: test for requires" events.clear tp.enable{ @@ -2403,6 +2441,99 @@ CODE assert_equal Array.new(2){th}, events end + def test_return_bmethod_location + bug13392 = "[ruby-core:80515] incorrect bmethod return location" + actual = nil + obj = Object.new + expected = __LINE__ + 1 + obj.define_singleton_method(:t){} + tp = TracePoint.new(:return) do + next unless target_thread? + actual = tp.lineno + end + tp.enable {obj.t} + assert_equal(expected, actual, bug13392) + end + + def test_b_tracepoints_going_away + # test that call and return TracePoints continue to work + # when b_call and b_return TracePoints stop + events = [] + record_events = ->(tp) do + next unless target_thread? + events << [tp.event, tp.method_id] + end + + call_ret_tp = TracePoint.new(:call, :return, &record_events) + block_call_ret_tp = TracePoint.new(:b_call, :b_return, &record_events) + + obj = Object.new + obj.define_singleton_method(:foo) {} # a bmethod + + foo = obj.method(:foo) + call_ret_tp.enable(target: foo) do + block_call_ret_tp.enable(target: foo) do + obj.foo + end + obj.foo + end + + assert_equal( + [ + [:call, :foo], + [:b_call, :foo], + [:b_return, :foo], + [:return, :foo], + [:call, :foo], + [:return, :foo], + ], + events, + ) + end + + def test_target_different_bmethod_same_iseq + # make two bmethods that share the same block iseq + block = Proc.new {} + obj = Object.new + obj.define_singleton_method(:one, &block) + obj.define_singleton_method(:two, &block) + + events = [] + record_events = ->(tp) do + next unless target_thread? + events << [tp.event, tp.method_id] + end + tp_one = TracePoint.new(:call, :return, &record_events) + tp_two = TracePoint.new(:call, :return, &record_events) + + tp_one.enable(target: obj.method(:one)) do + obj.one + obj.two # not targeted + end + assert_equal([[:call, :one], [:return, :one]], events) + events.clear + + tp_one.enable(target: obj.method(:one)) do + obj.one + tp_two.enable(target: obj.method(:two)) do + obj.two + end + obj.two + obj.one + end + assert_equal( + [ + [:call, :one], + [:return, :one], + [:call, :two], + [:return, :two], + [:call, :one], + [:return, :one], + ], + events + ) + end + def test_return_event_with_rescue obj = Object.new def obj.example @@ -2465,4 +2596,28 @@ CODE } assert_equal [__LINE__ - 5, __LINE__ - 4, __LINE__ - 3], lines, 'Bug #17868' end + + def test_allow_reentry + event_lines = [] + _l1 = _l2 = _l3 = _l4 = nil + TracePoint.new(:line) do |tp| + next unless target_thread? + + event_lines << tp.lineno + next if (__LINE__ + 2 .. __LINE__ + 4).cover?(tp.lineno) + TracePoint.allow_reentry do + _a = 1; _l3 = __LINE__ + _b = 2; _l4 = __LINE__ + end + end.enable do + _c = 3; _l1 = __LINE__ + _d = 4; _l2 = __LINE__ + end + + assert_equal [_l1, _l3, _l4, _l2, _l3, _l4], event_lines + + assert_raise RuntimeError do + TracePoint.allow_reentry{} + end + end end diff --git a/test/ruby/test_signal.rb b/test/ruby/test_signal.rb index a62537d59d..c5043eea59 100644 --- a/test/ruby/test_signal.rb +++ b/test/ruby/test_signal.rb @@ -291,7 +291,8 @@ class TestSignal < Test::Unit::TestCase if trap = Signal.list['TRAP'] bug9820 = '[ruby-dev:48592] [Bug #9820]' - status = assert_in_out_err(['-e', 'Process.kill(:TRAP, $$)']) + no_core = "Process.setrlimit(Process::RLIMIT_CORE, 0); " if defined?(Process.setrlimit) && defined?(Process::RLIMIT_CORE) + status = assert_in_out_err(['-e', "#{no_core}Process.kill(:TRAP, $$)"]) assert_predicate(status, :signaled?, bug9820) assert_equal(trap, status.termsig, bug9820) end @@ -323,7 +324,7 @@ class TestSignal < Test::Unit::TestCase end def test_sigchld_ignore - skip 'no SIGCHLD' unless Signal.list['CHLD'] + omit 'no SIGCHLD' unless Signal.list['CHLD'] old = trap(:CHLD, 'IGNORE') cmd = [ EnvUtil.rubybin, '--disable=gems', '-e' ] assert(system(*cmd, 'exit!(0)'), 'no ECHILD') diff --git a/test/ruby/test_string.rb b/test/ruby/test_string.rb index 3f7c06e075..d96e8dff22 100644 --- a/test/ruby/test_string.rb +++ b/test/ruby/test_string.rb @@ -83,7 +83,7 @@ class TestString < Test::Unit::TestCase end def test_initialize_shared - String.new(str = "mystring" * 10).__send__(:initialize, capacity: str.bytesize) + S(str = "mystring" * 10).__send__(:initialize, capacity: str.bytesize) assert_equal("mystring", str[0, 8]) end @@ -97,6 +97,8 @@ class TestString < Test::Unit::TestCase end def test_initialize_memory_leak + return unless @cls == String + assert_no_memory_leak([], <<-PREP, <<-CODE, rss: true) code = proc {('x'*100000).__send__(:initialize, '')} 1_000.times(&code) @@ -107,6 +109,8 @@ CODE # Bug #18154 def test_initialize_nofree_memory_leak + return unless @cls == String + assert_no_memory_leak([], <<-PREP, <<-CODE, rss: true) code = proc {0.to_s.__send__(:initialize, capacity: 10000)} 1_000.times(&code) @@ -240,23 +244,23 @@ CODE assert_equal(-1, S("ABCDEF") <=> S("abcdef")) - assert_nil("foo" <=> Object.new) + assert_nil(S("foo") <=> Object.new) o = Object.new def o.to_str; "bar"; end - assert_equal(1, "foo" <=> o) + assert_equal(1, S("foo") <=> o) class << o;remove_method :to_str;end def o.<=>(x); nil; end - assert_nil("foo" <=> o) + assert_nil(S("foo") <=> o) class << o;remove_method :<=>;end def o.<=>(x); 1; end - assert_equal(-1, "foo" <=> o) + assert_equal(-1, S("foo") <=> o) class << o;remove_method :<=>;end def o.<=>(x); 2**100; end - assert_equal(-1, "foo" <=> o) + assert_equal(-1, S("foo") <=> o) end def test_EQUAL # '==' @@ -270,10 +274,10 @@ CODE o = Object.new def o.to_str; end def o.==(x); false; end - assert_equal(false, "foo" == o) + assert_equal(false, S("foo") == o) class << o;remove_method :==;end def o.==(x); true; end - assert_equal(true, "foo" == o) + assert_equal(true, S("foo") == o) end def test_LSHIFT # '<<' @@ -648,12 +652,12 @@ CODE result << 0x0300 expected = S("\u0300".encode(Encoding::UTF_16LE)) assert_equal(expected, result, bug7090) - assert_raise(TypeError) { 'foo' << :foo } - assert_raise(FrozenError) { 'foo'.freeze.concat('bar') } + assert_raise(TypeError) { S('foo') << :foo } + assert_raise(FrozenError) { S('foo').freeze.concat('bar') } end def test_concat_literals - s="." * 50 + s=S("." * 50) assert_equal(Encoding::UTF_8, "#{s}x".encoding) end @@ -664,18 +668,18 @@ CODE assert_equal(4, a.count(S("hello"), S("^l"))) assert_equal(4, a.count(S("ej-m"))) assert_equal(0, S("y").count(S("a\\-z"))) - assert_equal(5, "abc\u{3042 3044 3046}".count("^a")) - assert_equal(1, "abc\u{3042 3044 3046}".count("\u3042")) - assert_equal(5, "abc\u{3042 3044 3046}".count("^\u3042")) - assert_equal(2, "abc\u{3042 3044 3046}".count("a-z", "^a")) - assert_equal(0, "abc\u{3042 3044 3046}".count("a", "\u3042")) - assert_equal(0, "abc\u{3042 3044 3046}".count("\u3042", "a")) - assert_equal(0, "abc\u{3042 3044 3046}".count("\u3042", "\u3044")) - assert_equal(4, "abc\u{3042 3044 3046}".count("^a", "^\u3044")) - assert_equal(4, "abc\u{3042 3044 3046}".count("^\u3044", "^a")) - assert_equal(4, "abc\u{3042 3044 3046}".count("^\u3042", "^\u3044")) + assert_equal(5, S("abc\u{3042 3044 3046}").count("^a")) + assert_equal(1, S("abc\u{3042 3044 3046}").count("\u3042")) + assert_equal(5, S("abc\u{3042 3044 3046}").count("^\u3042")) + assert_equal(2, S("abc\u{3042 3044 3046}").count("a-z", "^a")) + assert_equal(0, S("abc\u{3042 3044 3046}").count("a", "\u3042")) + assert_equal(0, S("abc\u{3042 3044 3046}").count("\u3042", "a")) + assert_equal(0, S("abc\u{3042 3044 3046}").count("\u3042", "\u3044")) + assert_equal(4, S("abc\u{3042 3044 3046}").count("^a", "^\u3044")) + assert_equal(4, S("abc\u{3042 3044 3046}").count("^\u3044", "^a")) + assert_equal(4, S("abc\u{3042 3044 3046}").count("^\u3042", "^\u3044")) - assert_raise(ArgumentError) { "foo".count } + assert_raise(ArgumentError) { S("foo").count } end def crypt_supports_des_crypt? @@ -717,17 +721,17 @@ CODE assert_equal(S("hell"), S("hello").delete(S("aeiou"), S("^e"))) assert_equal(S("ho"), S("hello").delete(S("ej-m"))) - assert_equal("a".hash, "a\u0101".delete("\u0101").hash, '[ruby-talk:329267]') - assert_equal(true, "a\u0101".delete("\u0101").ascii_only?) - assert_equal(true, "a\u3041".delete("\u3041").ascii_only?) - assert_equal(false, "a\u3041\u3042".delete("\u3041").ascii_only?) + assert_equal(S("a").hash, S("a\u0101").delete("\u0101").hash, '[ruby-talk:329267]') + assert_equal(true, S("a\u0101").delete("\u0101").ascii_only?) + assert_equal(true, S("a\u3041").delete("\u3041").ascii_only?) + assert_equal(false, S("a\u3041\u3042").delete("\u3041").ascii_only?) - assert_equal("a", "abc\u{3042 3044 3046}".delete("^a")) - assert_equal("bc\u{3042 3044 3046}", "abc\u{3042 3044 3046}".delete("a")) - assert_equal("\u3042", "abc\u{3042 3044 3046}".delete("^\u3042")) + assert_equal("a", S("abc\u{3042 3044 3046}").delete("^a")) + assert_equal("bc\u{3042 3044 3046}", S("abc\u{3042 3044 3046}").delete("a")) + assert_equal("\u3042", S("abc\u{3042 3044 3046}").delete("^\u3042")) bug6160 = '[ruby-dev:45374]' - assert_equal("", '\\'.delete('\\'), bug6160) + assert_equal("", S('\\').delete('\\'), bug6160) end def test_delete! @@ -832,10 +836,10 @@ CODE assert_equal(Encoding::UTF_8, S('"\\u3042"').encode(Encoding::EUC_JP).undump.encoding) assert_equal("abc".encode(Encoding::UTF_16LE), - '"a\x00b\x00c\x00".force_encoding("UTF-16LE")'.undump) + S('"a\x00b\x00c\x00".force_encoding("UTF-16LE")').undump) - assert_equal('\#', '"\\\\#"'.undump) - assert_equal('\#{', '"\\\\\#{"'.undump) + assert_equal('\#', S('"\\\\#"').undump) + assert_equal('\#{', S('"\\\\\#{"').undump) assert_raise(RuntimeError) { S('\u3042').undump } assert_raise(RuntimeError) { S('"\x82\xA0\u3042"'.force_encoding("SJIS")).undump } @@ -867,7 +871,7 @@ CODE assert_raise(RuntimeError) { S('"\\"').undump } assert_raise(RuntimeError) { S(%("\0")).undump } assert_raise_with_message(RuntimeError, /invalid/) { - '"\\u{007F}".xxxxxx'.undump + S('"\\u{007F}".xxxxxx').undump } end @@ -1047,9 +1051,9 @@ CODE g = g.encode(enc) assert_equal g.chars, g.grapheme_clusters end - assert_equal ["a", "b", "c"], "abc".b.grapheme_clusters + assert_equal ["a", "b", "c"], S("abc").b.grapheme_clusters - s = "ABC".b + s = S("ABC").b res = [] assert_same s, s.grapheme_clusters {|x| res << x } assert_equal(3, res.size) @@ -1095,7 +1099,7 @@ CODE $/ = save s = nil - "foo\nbar".each_line(nil) {|s2| s = s2 } + S("foo\nbar").each_line(nil) {|s2| s = s2 } assert_equal("foo\nbar", s) assert_equal "hello\n", S("hello\nworld").each_line.next @@ -1103,7 +1107,7 @@ CODE bug7646 = "[ruby-dev:46827]" assert_nothing_raised(bug7646) do - "\n\u0100".each_line("\n") {} + S("\n\u0100").each_line("\n") {} end ensure $/ = save @@ -1137,7 +1141,7 @@ CODE assert_equal(S("a"), res[0]) s = nil - "foo\nbar".each_line(nil, chomp: true) {|s2| s = s2 } + S("foo\nbar").each_line(nil, chomp: true) {|s2| s = s2 } assert_equal("foo\nbar", s) assert_equal "hello", S("hello\nworld").each_line(chomp: true).next @@ -1202,9 +1206,9 @@ CODE S("hello").gsub(/(hell)(.)/) { |s| $1.upcase + S('-') + $2 }) assert_equal(S("<>h<>e<>l<>l<>o<>"), S("hello").gsub(S(''), S('<\0>'))) - assert_equal("z", "abc".gsub(/./, "a" => "z"), "moved from btest/knownbug") + assert_equal("z", S("abc").gsub(/./, "a" => "z"), "moved from btest/knownbug") - assert_raise(ArgumentError) { "foo".gsub } + assert_raise(ArgumentError) { S("foo").gsub } end def test_gsub_encoding @@ -1251,23 +1255,23 @@ CODE end def test_sub_hash - assert_equal('azc', 'abc'.sub(/b/, "b" => "z")) - assert_equal('ac', 'abc'.sub(/b/, {})) - assert_equal('a1c', 'abc'.sub(/b/, "b" => 1)) - assert_equal('aBc', 'abc'.sub(/b/, Hash.new {|h, k| k.upcase })) - assert_equal('a[\&]c', 'abc'.sub(/b/, "b" => '[\&]')) - assert_equal('aBcabc', 'abcabc'.sub(/b/, Hash.new {|h, k| h[k] = k.upcase })) - assert_equal('aBcdef', 'abcdef'.sub(/de|b/, "b" => "B", "de" => "DE")) + assert_equal('azc', S('abc').sub(/b/, "b" => "z")) + assert_equal('ac', S('abc').sub(/b/, {})) + assert_equal('a1c', S('abc').sub(/b/, "b" => 1)) + assert_equal('aBc', S('abc').sub(/b/, Hash.new {|h, k| k.upcase })) + assert_equal('a[\&]c', S('abc').sub(/b/, "b" => '[\&]')) + assert_equal('aBcabc', S('abcabc').sub(/b/, Hash.new {|h, k| h[k] = k.upcase })) + assert_equal('aBcdef', S('abcdef').sub(/de|b/, "b" => "B", "de" => "DE")) end def test_gsub_hash - assert_equal('azc', 'abc'.gsub(/b/, "b" => "z")) - assert_equal('ac', 'abc'.gsub(/b/, {})) - assert_equal('a1c', 'abc'.gsub(/b/, "b" => 1)) - assert_equal('aBc', 'abc'.gsub(/b/, Hash.new {|h, k| k.upcase })) - assert_equal('a[\&]c', 'abc'.gsub(/b/, "b" => '[\&]')) - assert_equal('aBcaBc', 'abcabc'.gsub(/b/, Hash.new {|h, k| h[k] = k.upcase })) - assert_equal('aBcDEf', 'abcdef'.gsub(/de|b/, "b" => "B", "de" => "DE")) + assert_equal('azc', S('abc').gsub(/b/, "b" => "z")) + assert_equal('ac', S('abc').gsub(/b/, {})) + assert_equal('a1c', S('abc').gsub(/b/, "b" => 1)) + assert_equal('aBc', S('abc').gsub(/b/, Hash.new {|h, k| k.upcase })) + assert_equal('a[\&]c', S('abc').gsub(/b/, "b" => '[\&]')) + assert_equal('aBcaBc', S('abcabc').gsub(/b/, Hash.new {|h, k| h[k] = k.upcase })) + assert_equal('aBcDEf', S('abcdef').gsub(/de|b/, "b" => "B", "de" => "DE")) end def test_hash @@ -1329,13 +1333,22 @@ CODE o = Object.new def o.to_str; "bar"; end - assert_equal(3, "foobarbarbaz".index(o)) - assert_raise(TypeError) { "foo".index(Object.new) } + assert_equal(3, S("foobarbarbaz").index(o)) + assert_raise(TypeError) { S("foo").index(Object.new) } - assert_nil("foo".index(//, -100)) + assert_nil(S("foo").index(//, -100)) assert_nil($~) assert_equal(2, S("abcdbce").index(/b\Kc/)) + + assert_equal(0, S("こんにちは").index(?こ)) + assert_equal(1, S("こんにちは").index(S("んにち"))) + assert_equal(2, S("こんにちは").index(/にち./)) + + assert_equal(0, S("にんにちは").index(?に, 0)) + assert_equal(2, S("にんにちは").index(?に, 1)) + assert_equal(2, S("にんにちは").index(?に, 2)) + assert_nil(S("にんにちは").index(?に, 3)) end def test_insert @@ -1442,16 +1455,16 @@ CODE b = a.replace(S("xyz")) assert_equal(S("xyz"), b) - s = "foo" * 100 + s = S("foo") * 100 s2 = ("bar" * 100).dup s.replace(s2) assert_equal(s2, s) - s2 = ["foo"].pack("p") + s2 = [S("foo")].pack("p") s.replace(s2) assert_equal(s2, s) - fs = "".freeze + fs = S("").freeze assert_raise(FrozenError) { fs.replace("a") } assert_raise(FrozenError) { fs.replace(fs) } assert_raise(ArgumentError) { fs.replace() } @@ -1498,18 +1511,41 @@ CODE assert_nil(S("hello").rindex(S("z"))) assert_nil(S("hello").rindex(/z./)) + assert_equal(5, S("hello").rindex(S(""))) + assert_equal(5, S("hello").rindex(S(""), 5)) + assert_equal(4, S("hello").rindex(S(""), 4)) + assert_equal(0, S("hello").rindex(S(""), 0)) + o = Object.new def o.to_str; "bar"; end - assert_equal(6, "foobarbarbaz".rindex(o)) - assert_raise(TypeError) { "foo".rindex(Object.new) } + assert_equal(6, S("foobarbarbaz").rindex(o)) + assert_raise(TypeError) { S("foo").rindex(Object.new) } - assert_nil("foo".rindex(//, -100)) + assert_nil(S("foo").rindex(//, -100)) assert_nil($~) - assert_equal(3, "foo".rindex(//)) + assert_equal(3, S("foo").rindex(//)) assert_equal([3, 3], $~.offset(0)) assert_equal(5, S("abcdbce").rindex(/b\Kc/)) + + assert_equal(2, S("こんにちは").rindex(?に)) + assert_equal(6, S("にちは、こんにちは").rindex(S("にちは"))) + assert_equal(6, S("にちは、こんにちは").rindex(/にち./)) + + assert_equal(6, S("にちは、こんにちは").rindex(S("にちは"), 7)) + assert_equal(6, S("にちは、こんにちは").rindex(S("にちは"), -2)) + assert_equal(6, S("にちは、こんにちは").rindex(S("にちは"), 6)) + assert_equal(6, S("にちは、こんにちは").rindex(S("にちは"), -3)) + assert_equal(0, S("にちは、こんにちは").rindex(S("にちは"), 5)) + assert_equal(0, S("にちは、こんにちは").rindex(S("にちは"), -4)) + assert_equal(0, S("にちは、こんにちは").rindex(S("にちは"), 1)) + assert_equal(0, S("にちは、こんにちは").rindex(S("にちは"), 0)) + + assert_equal(0, S("こんにちは").rindex(S("こんにちは"))) + assert_nil(S("こんにち").rindex(S("こんにちは"))) + assert_nil(S("こ").rindex(S("こんにちは"))) + assert_nil(S("").rindex(S("こんにちは"))) end def test_rjust @@ -1689,7 +1725,8 @@ CODE assert_equal(S("Bar"), a.slice!(S("Bar"))) assert_equal(S("Foo"), a) - assert_raise(ArgumentError) { "foo".slice! } + a = S("foo") + assert_raise(ArgumentError) { a.slice! } end def test_split @@ -1714,7 +1751,7 @@ CODE assert_equal([S("a"), S(""), S("b"), S("c")], S("a||b|c|").split(S('|'))) assert_equal([S("a"), S(""), S("b"), S("c"), S("")], S("a||b|c|").split(S('|'), -1)) - assert_equal([], "".split(//, 1)) + assert_equal([], S("").split(//, 1)) ensure EnvUtil.suppress_warning {$; = fs} end @@ -1753,16 +1790,18 @@ CODE result = []; S("a||b|c|").split(S('|'), -1) {|s| result << s} assert_equal([S("a"), S(""), S("b"), S("c"), S("")], result) - result = []; "".split(//, 1) {|s| result << s} + result = []; S("").split(//, 1) {|s| result << s} assert_equal([], result) - result = []; "aaa,bbb,ccc,ddd".split(/,/) {|s| result << s.gsub(/./, "A")} + result = []; S("aaa,bbb,ccc,ddd").split(/,/) {|s| result << s.gsub(/./, "A")} assert_equal(["AAA"]*4, result) ensure EnvUtil.suppress_warning {$; = fs} end def test_fs + return unless @cls == String + assert_raise_with_message(TypeError, /\$;/) { $; = [] } @@ -1856,9 +1895,9 @@ CODE bug5536 = '[ruby-core:40623]' assert_raise(TypeError, bug5536) {S("str").start_with? :not_convertible_to_string} - assert_equal(true, "hello".start_with?(/hel/)) + assert_equal(true, S("hello").start_with?(/hel/)) assert_equal("hel", $&) - assert_equal(false, "hello".start_with?(/el/)) + assert_equal(false, S("hello").start_with?(/el/)) assert_nil($&) end @@ -1868,9 +1907,9 @@ CODE assert_equal(S("x"), S("\x00x\x00").strip) assert_equal("0b0 ".force_encoding("UTF-16BE"), - "\x00 0b0 ".force_encoding("UTF-16BE").strip) + S("\x00 0b0 ").force_encoding("UTF-16BE").strip) assert_equal("0\x000b0 ".force_encoding("UTF-16BE"), - "0\x000b0 ".force_encoding("UTF-16BE").strip) + S("0\x000b0 ").force_encoding("UTF-16BE").strip) end def test_strip! @@ -1935,17 +1974,17 @@ CODE o = Object.new def o.to_str; "bar"; end - assert_equal("fooBARbaz", "foobarbaz".sub(o, "BAR")) + assert_equal("fooBARbaz", S("foobarbaz").sub(o, "BAR")) - assert_raise(TypeError) { "foo".sub(Object.new, "") } + assert_raise(TypeError) { S("foo").sub(Object.new, "") } - assert_raise(ArgumentError) { "foo".sub } + assert_raise(ArgumentError) { S("foo").sub } assert_raise(IndexError) { "foo"[/(?:(o$)|(x))/, 2] = 'bar' } o = Object.new def o.to_s; self; end - assert_match(/^foo#<Object:0x.*>baz$/, "foobarbaz".sub("bar") { o }) + assert_match(/^foo#<Object:0x.*>baz$/, S("foobarbaz").sub("bar") { o }) assert_equal(S("Abc"), S("abc").sub("a", "A")) m = nil @@ -1954,7 +1993,7 @@ CODE assert_equal(/a/, m.regexp) bug = '[ruby-core:78686] [Bug #13042] other than regexp has no name references' assert_raise_with_message(IndexError, /oops/, bug) { - 'hello'.gsub('hello', '\k<oops>') + S('hello').gsub('hello', '\k<oops>') } end @@ -2001,18 +2040,18 @@ CODE assert_equal(S("AAAAA000"), S("ZZZZ999").succ) assert_equal(S("*+"), S("**").succ) - assert_equal("abce", "abcd".succ) - assert_equal("THX1139", "THX1138".succ) - assert_equal("<\<koalb>>", "<\<koala>>".succ) - assert_equal("2000aaa", "1999zzz".succ) - assert_equal("AAAA0000", "ZZZ9999".succ) - assert_equal("**+", "***".succ) + assert_equal("abce", S("abcd").succ) + assert_equal("THX1139", S("THX1138").succ) + assert_equal("<\<koalb>>", S("<\<koala>>").succ) + assert_equal("2000aaa", S("1999zzz").succ) + assert_equal("AAAA0000", S("ZZZ9999").succ) + assert_equal("**+", S("***").succ) - assert_equal("!", " ".succ) - assert_equal("", "".succ) + assert_equal("!", S(" ").succ) + assert_equal("", S("").succ) bug = '[ruby-core:83062] [Bug #13952]' - s = "\xff".b + s = S("\xff").b assert_not_predicate(s, :ascii_only?) assert_predicate(s.succ, :ascii_only?, bug) end @@ -2064,8 +2103,8 @@ CODE assert_equal(S(""), a.succ!) assert_equal(S(""), a) - assert_equal("aaaaaaaaaaaa", "zzzzzzzzzzz".succ!) - assert_equal("aaaaaaaaaaaaaaaaaaaaaaaa", "zzzzzzzzzzzzzzzzzzzzzzz".succ!) + assert_equal("aaaaaaaaaaaa", S("zzzzzzzzzzz").succ!) + assert_equal("aaaaaaaaaaaaaaaaaaaaaaaa", S("zzzzzzzzzzzzzzzzzzzzzzz").succ!) end def test_sum @@ -2087,8 +2126,8 @@ CODE end def test_sum_2 - assert_equal(0, "".sum) - assert_equal(294, "abc".sum) + assert_equal(0, S("").sum) + assert_equal(294, S("abc").sum) check_sum("abc") check_sum("\x80") -3.upto(70) {|bits| @@ -2135,39 +2174,39 @@ CODE def test_to_i assert_equal(1480, S("1480ft/sec").to_i) assert_equal(0, S("speed of sound in water @20C = 1480ft/sec)").to_i) - assert_equal(0, " 0".to_i) - assert_equal(0, "+0".to_i) - assert_equal(0, "-0".to_i) - assert_equal(0, "--0".to_i) - assert_equal(16, "0x10".to_i(0)) - assert_equal(16, "0X10".to_i(0)) - assert_equal(2, "0b10".to_i(0)) - assert_equal(2, "0B10".to_i(0)) - assert_equal(8, "0o10".to_i(0)) - assert_equal(8, "0O10".to_i(0)) - assert_equal(10, "0d10".to_i(0)) - assert_equal(10, "0D10".to_i(0)) - assert_equal(8, "010".to_i(0)) - assert_raise(ArgumentError) { "010".to_i(-10) } + assert_equal(0, S(" 0").to_i) + assert_equal(0, S("+0").to_i) + assert_equal(0, S("-0").to_i) + assert_equal(0, S("--0").to_i) + assert_equal(16, S("0x10").to_i(0)) + assert_equal(16, S("0X10").to_i(0)) + assert_equal(2, S("0b10").to_i(0)) + assert_equal(2, S("0B10").to_i(0)) + assert_equal(8, S("0o10").to_i(0)) + assert_equal(8, S("0O10").to_i(0)) + assert_equal(10, S("0d10").to_i(0)) + assert_equal(10, S("0D10").to_i(0)) + assert_equal(8, S("010").to_i(0)) + assert_raise(ArgumentError) { S("010").to_i(-10) } 2.upto(36) {|radix| - assert_equal(radix, "10".to_i(radix)) - assert_equal(radix**2, "100".to_i(radix)) + assert_equal(radix, S("10").to_i(radix)) + assert_equal(radix**2, S("100").to_i(radix)) } - assert_raise(ArgumentError) { "0".to_i(1) } - assert_raise(ArgumentError) { "0".to_i(37) } - assert_equal(0, "z".to_i(10)) - assert_equal(12, "1_2".to_i(10)) - assert_equal(0x40000000, "1073741824".to_i(10)) - assert_equal(0x4000000000000000, "4611686018427387904".to_i(10)) - assert_equal(1, "1__2".to_i(10)) - assert_equal(1, "1_z".to_i(10)) + assert_raise(ArgumentError) { S("0").to_i(1) } + assert_raise(ArgumentError) { S("0").to_i(37) } + assert_equal(0, S("z").to_i(10)) + assert_equal(12, S("1_2").to_i(10)) + assert_equal(0x40000000, S("1073741824").to_i(10)) + assert_equal(0x4000000000000000, S("4611686018427387904").to_i(10)) + assert_equal(1, S("1__2").to_i(10)) + assert_equal(1, S("1_z").to_i(10)) bug6192 = '[ruby-core:43566]' - assert_raise(Encoding::CompatibilityError, bug6192) {"0".encode("utf-16be").to_i} - assert_raise(Encoding::CompatibilityError, bug6192) {"0".encode("utf-16le").to_i} - assert_raise(Encoding::CompatibilityError, bug6192) {"0".encode("utf-32be").to_i} - assert_raise(Encoding::CompatibilityError, bug6192) {"0".encode("utf-32le").to_i} - assert_raise(Encoding::CompatibilityError, bug6192) {"0".encode("iso-2022-jp").to_i} + assert_raise(Encoding::CompatibilityError, bug6192) {S("0".encode("utf-16be")).to_i} + assert_raise(Encoding::CompatibilityError, bug6192) {S("0".encode("utf-16le")).to_i} + assert_raise(Encoding::CompatibilityError, bug6192) {S("0".encode("utf-32be")).to_i} + assert_raise(Encoding::CompatibilityError, bug6192) {S("0".encode("utf-32le")).to_i} + assert_raise(Encoding::CompatibilityError, bug6192) {S("0".encode("iso-2022-jp")).to_i} end def test_to_s @@ -2199,13 +2238,13 @@ CODE assert_equal(S("*e**o"), S("hello").tr(S("^aeiou"), S("*"))) assert_equal(S("hal"), S("ibm").tr(S("b-z"), S("a-z"))) - a = "abc".force_encoding(Encoding::US_ASCII) + a = S("abc".force_encoding(Encoding::US_ASCII)) assert_equal(Encoding::US_ASCII, a.tr(S("z"), S("\u0101")).encoding, '[ruby-core:22326]') - assert_equal("a".hash, "a".tr("a", "\u0101").tr("\u0101", "a").hash, '[ruby-core:22328]') - assert_equal(true, "\u0101".tr("\u0101", "a").ascii_only?) - assert_equal(true, "\u3041".tr("\u3041", "a").ascii_only?) - assert_equal(false, "\u3041\u3042".tr("\u3041", "a").ascii_only?) + assert_equal("a".hash, S("a").tr("a", "\u0101").tr("\u0101", "a").hash, '[ruby-core:22328]') + assert_equal(true, S("\u0101").tr("\u0101", "a").ascii_only?) + assert_equal(true, S("\u3041").tr("\u3041", "a").ascii_only?) + assert_equal(false, S("\u3041\u3042").tr("\u3041", "a").ascii_only?) bug6156 = '[ruby-core:43335]' bug13950 = '[ruby-core:83056] [Bug #13950]' @@ -2236,7 +2275,7 @@ CODE assert_nil(a.tr!(S("B-Z"), S("A-Z"))) assert_equal(S("ibm"), a) - a = "abc".force_encoding(Encoding::US_ASCII) + a = S("abc".force_encoding(Encoding::US_ASCII)) assert_nil(a.tr!(S("z"), S("\u0101")), '[ruby-core:22326]') assert_equal(Encoding::US_ASCII, a.encoding, '[ruby-core:22326]') end @@ -2244,8 +2283,8 @@ CODE def test_tr_s assert_equal(S("hypo"), S("hello").tr_s(S("el"), S("yp"))) assert_equal(S("h*o"), S("hello").tr_s(S("el"), S("*"))) - assert_equal("a".hash, "\u0101\u0101".tr_s("\u0101", "a").hash) - assert_equal(true, "\u3041\u3041".tr("\u3041", "a").ascii_only?) + assert_equal("a".hash, S("\u0101\u0101").tr_s("\u0101", "a").hash) + assert_equal(true, S("\u3041\u3041").tr("\u3041", "a").ascii_only?) end def test_tr_s! @@ -2345,6 +2384,7 @@ CODE assert_equal(S("HELLO"), S("HELLO").upcase) assert_equal(S("ABC HELLO 123"), S("abc HELLO 123").upcase) assert_equal(S("H\0""ELLO"), S("H\0""ello").upcase) + assert_equal(S("\u{10574}"), S("\u{1059B}").upcase) end def test_upcase! @@ -2418,6 +2458,8 @@ CODE class S2 < String end def test_str_new4 + return unless @cls == String + s = (0..54).to_a.join # length = 100 s2 = S2.new(s[10,90]) s3 = s2[10,80] @@ -2426,7 +2468,7 @@ CODE end def test_rb_str_new4 - s = "a" * 100 + s = S("a" * 100) s2 = s[10,90] assert_equal("a" * 90, s2) s3 = s2[10,80] @@ -2444,11 +2486,11 @@ CODE end def test_rb_str_to_str - assert_equal("ab", "a" + StringLike.new("b")) + assert_equal("ab", S("a") + StringLike.new("b")) end def test_rb_str_shared_replace - s = "a" * 100 + s = S("a" * 100) s.succ! assert_equal("a" * 99 + "b", s) s = "" @@ -2472,12 +2514,12 @@ CODE def test_times2 s1 = '' 100.times {|n| - s2 = "a" * n + s2 = S("a") * n assert_equal(s1, s2) s1 << 'a' } - assert_raise(ArgumentError) { "foo" * (-1) } + assert_raise(ArgumentError) { S("foo") * (-1) } end def test_respond_to @@ -2485,41 +2527,41 @@ CODE def o.respond_to?(arg) [:to_str].include?(arg) ? nil : super end def o.to_str() "" end def o.==(other) "" == other end - assert_equal(false, "" == o) + assert_equal(false, S("") == o) end def test_match_method - assert_equal("bar", "foobarbaz".match(/bar/).to_s) + assert_equal("bar", S("foobarbaz").match(/bar/).to_s) o = Regexp.new('foo') def o.match(x, y, z); x + y + z; end - assert_equal("foobarbaz", "foo".match(o, "bar", "baz")) + assert_equal("foobarbaz", S("foo").match(o, "bar", "baz")) x = nil - "foo".match(o, "bar", "baz") {|y| x = y } + S("foo").match(o, "bar", "baz") {|y| x = y } assert_equal("foobarbaz", x) - assert_raise(ArgumentError) { "foo".match } + assert_raise(ArgumentError) { S("foo").match } end def test_match_p_regexp /backref/ =~ 'backref' # must match here, but not in a separate method, e.g., assert_send, # to check if $~ is affected or not. - assert_equal(true, "".match?(//)) + assert_equal(true, S("").match?(//)) assert_equal(true, :abc.match?(/.../)) - assert_equal(true, 'abc'.match?(/b/)) - assert_equal(true, 'abc'.match?(/b/, 1)) - assert_equal(true, 'abc'.match?(/../, 1)) - assert_equal(true, 'abc'.match?(/../, -2)) - assert_equal(false, 'abc'.match?(/../, -4)) - assert_equal(false, 'abc'.match?(/../, 4)) - assert_equal(true, "\u3042xx".match?(/../, 1)) - assert_equal(false, "\u3042x".match?(/../, 1)) - assert_equal(true, ''.match?(/\z/)) - assert_equal(true, 'abc'.match?(/\z/)) - assert_equal(true, 'Ruby'.match?(/R.../)) - assert_equal(false, 'Ruby'.match?(/R.../, 1)) - assert_equal(false, 'Ruby'.match?(/P.../)) + assert_equal(true, S('abc').match?(/b/)) + assert_equal(true, S('abc').match?(/b/, 1)) + assert_equal(true, S('abc').match?(/../, 1)) + assert_equal(true, S('abc').match?(/../, -2)) + assert_equal(false, S('abc').match?(/../, -4)) + assert_equal(false, S('abc').match?(/../, 4)) + assert_equal(true, S("\u3042xx").match?(/../, 1)) + assert_equal(false, S("\u3042x").match?(/../, 1)) + assert_equal(true, S('').match?(/\z/)) + assert_equal(true, S('abc').match?(/\z/)) + assert_equal(true, S('Ruby').match?(/R.../)) + assert_equal(false, S('Ruby').match?(/R.../, 1)) + assert_equal(false, S('Ruby').match?(/P.../)) assert_equal('backref', $&) end @@ -2527,21 +2569,21 @@ CODE /backref/ =~ 'backref' # must match here, but not in a separate method, e.g., assert_send, # to check if $~ is affected or not. - assert_equal(true, "".match?('')) + assert_equal(true, S("").match?('')) assert_equal(true, :abc.match?('...')) - assert_equal(true, 'abc'.match?('b')) - assert_equal(true, 'abc'.match?('b', 1)) - assert_equal(true, 'abc'.match?('..', 1)) - assert_equal(true, 'abc'.match?('..', -2)) - assert_equal(false, 'abc'.match?('..', -4)) - assert_equal(false, 'abc'.match?('..', 4)) - assert_equal(true, "\u3042xx".match?('..', 1)) - assert_equal(false, "\u3042x".match?('..', 1)) - assert_equal(true, ''.match?('\z')) - assert_equal(true, 'abc'.match?('\z')) - assert_equal(true, 'Ruby'.match?('R...')) - assert_equal(false, 'Ruby'.match?('R...', 1)) - assert_equal(false, 'Ruby'.match?('P...')) + assert_equal(true, S('abc').match?('b')) + assert_equal(true, S('abc').match?('b', 1)) + assert_equal(true, S('abc').match?('..', 1)) + assert_equal(true, S('abc').match?('..', -2)) + assert_equal(false, S('abc').match?('..', -4)) + assert_equal(false, S('abc').match?('..', 4)) + assert_equal(true, S("\u3042xx").match?('..', 1)) + assert_equal(false, S("\u3042x").match?('..', 1)) + assert_equal(true, S('').match?('\z')) + assert_equal(true, S('abc').match?('\z')) + assert_equal(true, S('Ruby').match?('R...')) + assert_equal(false, S('Ruby').match?('R...', 1)) + assert_equal(false, S('Ruby').match?('P...')) assert_equal('backref', $&) end @@ -2561,18 +2603,18 @@ CODE def test_inspect_nul bug8290 = '[ruby-core:54458]' - s = "\0" + "12" + s = S("\0") + "12" assert_equal '"\u000012"', s.inspect, bug8290 - s = "\0".b + "12" + s = S("\0".b) + "12" assert_equal '"\x0012"', s.inspect, bug8290 end def test_partition - assert_equal(%w(he l lo), "hello".partition(/l/)) - assert_equal(%w(he l lo), "hello".partition("l")) - assert_raise(TypeError) { "hello".partition(1) } + assert_equal(%w(he l lo), S("hello").partition(/l/)) + assert_equal(%w(he l lo), S("hello").partition("l")) + assert_raise(TypeError) { S("hello").partition(1) } def (hyphen = Object.new).to_str; "-"; end - assert_equal(%w(foo - bar), "foo-bar".partition(hyphen), '[ruby-core:23540]') + assert_equal(%w(foo - bar), S("foo-bar").partition(hyphen), '[ruby-core:23540]') bug6206 = '[ruby-dev:45441]' Encoding.list.each do |enc| @@ -2582,24 +2624,24 @@ CODE end assert_equal(["\u30E6\u30FC\u30B6", "@", "\u30C9\u30E1.\u30A4\u30F3"], - "\u30E6\u30FC\u30B6@\u30C9\u30E1.\u30A4\u30F3".partition(/[@.]/)) + S("\u30E6\u30FC\u30B6@\u30C9\u30E1.\u30A4\u30F3").partition(/[@.]/)) bug = '[ruby-core:82911]' - hello = "hello" + hello = S("hello") hello.partition("hi").map(&:upcase!) assert_equal("hello", hello, bug) - assert_equal(["", "", "foo"], "foo".partition(/^=*/)) + assert_equal(["", "", "foo"], S("foo").partition(/^=*/)) assert_equal([S("ab"), S("c"), S("dbce")], S("abcdbce").partition(/b\Kc/)) end def test_rpartition - assert_equal(%w(hel l o), "hello".rpartition(/l/)) - assert_equal(%w(hel l o), "hello".rpartition("l")) - assert_raise(TypeError) { "hello".rpartition(1) } + assert_equal(%w(hel l o), S("hello").rpartition(/l/)) + assert_equal(%w(hel l o), S("hello").rpartition("l")) + assert_raise(TypeError) { S("hello").rpartition(1) } def (hyphen = Object.new).to_str; "-"; end - assert_equal(%w(foo - bar), "foo-bar".rpartition(hyphen), '[ruby-core:23540]') + assert_equal(%w(foo - bar), S("foo-bar").rpartition(hyphen), '[ruby-core:23540]') bug6206 = '[ruby-dev:45441]' Encoding.list.each do |enc| @@ -2610,7 +2652,7 @@ CODE bug8138 = '[ruby-dev:47183]' assert_equal(["\u30E6\u30FC\u30B6@\u30C9\u30E1", ".", "\u30A4\u30F3"], - "\u30E6\u30FC\u30B6@\u30C9\u30E1.\u30A4\u30F3".rpartition(/[@.]/), bug8138) + S("\u30E6\u30FC\u30B6@\u30C9\u30E1.\u30A4\u30F3").rpartition(/[@.]/), bug8138) bug = '[ruby-core:82911]' hello = "hello" @@ -2620,10 +2662,13 @@ CODE assert_equal([S("abcdb"), S("c"), S("e")], S("abcdbce").rpartition(/b\Kc/)) end - def test_setter + def test_fs_setter + return unless @cls == String + assert_raise(TypeError) { $/ = 1 } name = "\u{5206 884c}" - assert_separately([], <<-"end;") # do + assert_separately([], "#{<<~"do;"}\n#{<<~"end;"}") + do; alias $#{name} $/ assert_raise_with_message(TypeError, /\\$#{name}/) { $#{name} = 1 } end; @@ -2656,16 +2701,19 @@ CODE end def test_gsub_enumerator - assert_normal_exit %q{"abc".gsub(/./).next}, "[ruby-dev:34828]" + e = S("abc").gsub(/./) + assert_equal("a", e.next, "[ruby-dev:34828]") + assert_equal("b", e.next) + assert_equal("c", e.next) end def test_clear_nonasciicompat - assert_equal("", "\u3042".encode("ISO-2022-JP").clear) + assert_equal("", S("\u3042".encode("ISO-2022-JP")).clear) end def test_try_convert - assert_equal(nil, String.try_convert(1)) - assert_equal("foo", String.try_convert("foo")) + assert_equal(nil, @cls.try_convert(1)) + assert_equal("foo", @cls.try_convert("foo")) end def test_substr_negative_begin @@ -2674,55 +2722,55 @@ CODE =begin def test_compare_different_encoding_string - s1 = "\xff".force_encoding("UTF-8") - s2 = "\xff".force_encoding("ISO-2022-JP") + s1 = S("\xff".force_encoding("UTF-8")) + s2 = S("\xff".force_encoding("ISO-2022-JP")) assert_equal([-1, 1], [s1 <=> s2, s2 <=> s1].sort) end =end def test_casecmp - assert_equal(0, "FoO".casecmp("fOO")) - assert_equal(1, "FoO".casecmp("BaR")) - assert_equal(-1, "baR".casecmp("FoO")) - assert_equal(1, "\u3042B".casecmp("\u3042a")) - assert_equal(-1, "foo".casecmp("foo\0")) + assert_equal(0, S("FoO").casecmp("fOO")) + assert_equal(1, S("FoO").casecmp("BaR")) + assert_equal(-1, S("baR").casecmp("FoO")) + assert_equal(1, S("\u3042B").casecmp("\u3042a")) + assert_equal(-1, S("foo").casecmp("foo\0")) - assert_nil("foo".casecmp(:foo)) - assert_nil("foo".casecmp(Object.new)) + assert_nil(S("foo").casecmp(:foo)) + assert_nil(S("foo").casecmp(Object.new)) o = Object.new def o.to_str; "fOO"; end - assert_equal(0, "FoO".casecmp(o)) + assert_equal(0, S("FoO").casecmp(o)) end def test_casecmp? - assert_equal(true, 'FoO'.casecmp?('fOO')) - assert_equal(false, 'FoO'.casecmp?('BaR')) - assert_equal(false, 'baR'.casecmp?('FoO')) - assert_equal(true, 'äöü'.casecmp?('ÄÖÜ')) - assert_equal(false, "foo".casecmp?("foo\0")) + assert_equal(true, S('FoO').casecmp?('fOO')) + assert_equal(false, S('FoO').casecmp?('BaR')) + assert_equal(false, S('baR').casecmp?('FoO')) + assert_equal(true, S('äöü').casecmp?('ÄÖÜ')) + assert_equal(false, S("foo").casecmp?("foo\0")) - assert_nil("foo".casecmp?(:foo)) - assert_nil("foo".casecmp?(Object.new)) + assert_nil(S("foo").casecmp?(:foo)) + assert_nil(S("foo").casecmp?(Object.new)) o = Object.new def o.to_str; "fOO"; end - assert_equal(true, "FoO".casecmp?(o)) + assert_equal(true, S("FoO").casecmp?(o)) end def test_upcase2 - assert_equal("\u3042AB", "\u3042aB".upcase) + assert_equal("\u3042AB", S("\u3042aB").upcase) end def test_downcase2 - assert_equal("\u3042ab", "\u3042aB".downcase) + assert_equal("\u3042ab", S("\u3042aB").downcase) end def test_rstrip - assert_equal(" hello", " hello ".rstrip) - assert_equal("\u3042", "\u3042 ".rstrip) - assert_equal("\u3042", "\u3042\u0000".rstrip) - assert_raise(Encoding::CompatibilityError) { "\u3042".encode("ISO-2022-JP").rstrip } + assert_equal(" hello", S(" hello ").rstrip) + assert_equal("\u3042", S("\u3042 ").rstrip) + assert_equal("\u3042", S("\u3042\u0000").rstrip) + assert_raise(Encoding::CompatibilityError) { S("\u3042".encode("ISO-2022-JP")).rstrip } end def test_rstrip_bang @@ -2746,13 +2794,13 @@ CODE assert_equal("\u3042", s5.rstrip!) assert_equal("\u3042", s5) - assert_raise(Encoding::CompatibilityError) { "\u3042".encode("ISO-2022-JP").rstrip! } + assert_raise(Encoding::CompatibilityError) { S("\u3042".encode("ISO-2022-JP")).rstrip! } end def test_lstrip - assert_equal("hello ", " hello ".lstrip) - assert_equal("\u3042", " \u3042".lstrip) - assert_equal("hello ", "\x00hello ".lstrip) + assert_equal("hello ", S(" hello ").lstrip) + assert_equal("\u3042", S(" \u3042").lstrip) + assert_equal("hello ", S("\x00hello ").lstrip) end def test_lstrip_bang @@ -2779,9 +2827,9 @@ CODE end def test_delete_prefix - assert_raise(TypeError) { 'hello'.delete_prefix(nil) } - assert_raise(TypeError) { 'hello'.delete_prefix(1) } - assert_raise(TypeError) { 'hello'.delete_prefix(/hel/) } + assert_raise(TypeError) { S('hello').delete_prefix(nil) } + assert_raise(TypeError) { S('hello').delete_prefix(1) } + assert_raise(TypeError) { S('hello').delete_prefix(/hel/) } s = S("hello") assert_equal("lo", s.delete_prefix('hel')) @@ -2825,9 +2873,9 @@ CODE end def test_delete_prefix_bang - assert_raise(TypeError) { 'hello'.delete_prefix!(nil) } - assert_raise(TypeError) { 'hello'.delete_prefix!(1) } - assert_raise(TypeError) { 'hello'.delete_prefix!(/hel/) } + assert_raise(TypeError) { S('hello').delete_prefix!(nil) } + assert_raise(TypeError) { S('hello').delete_prefix!(1) } + assert_raise(TypeError) { S('hello').delete_prefix!(/hel/) } s = S("hello") assert_equal("lo", s.delete_prefix!('hel')) @@ -2878,9 +2926,9 @@ CODE end def test_delete_suffix - assert_raise(TypeError) { 'hello'.delete_suffix(nil) } - assert_raise(TypeError) { 'hello'.delete_suffix(1) } - assert_raise(TypeError) { 'hello'.delete_suffix(/hel/) } + assert_raise(TypeError) { S('hello').delete_suffix(nil) } + assert_raise(TypeError) { S('hello').delete_suffix(1) } + assert_raise(TypeError) { S('hello').delete_suffix(/hel/) } s = S("hello") assert_equal("hel", s.delete_suffix('lo')) @@ -2929,9 +2977,9 @@ CODE end def test_delete_suffix_bang - assert_raise(TypeError) { 'hello'.delete_suffix!(nil) } - assert_raise(TypeError) { 'hello'.delete_suffix!(1) } - assert_raise(TypeError) { 'hello'.delete_suffix!(/hel/) } + assert_raise(TypeError) { S('hello').delete_suffix!(nil) } + assert_raise(TypeError) { S('hello').delete_suffix!(1) } + assert_raise(TypeError) { S('hello').delete_suffix!(/hel/) } s = S("hello").freeze assert_raise_with_message(FrozenError, /frozen/) {s.delete_suffix!('lo')} @@ -3020,7 +3068,7 @@ CODE end def test_shared_force_encoding - s = "\u{3066}\u{3059}\u{3068}".gsub(//, '') + s = S("\u{3066}\u{3059}\u{3068}").gsub(//, '') h = {} h[s] = nil k = h.keys[0] @@ -3035,16 +3083,16 @@ CODE def test_ascii_incomat_inspect bug4081 = '[ruby-core:33283]' WIDE_ENCODINGS.each do |e| - assert_equal('"abc"', "abc".encode(e).inspect) - assert_equal('"\\u3042\\u3044\\u3046"', "\u3042\u3044\u3046".encode(e).inspect) - assert_equal('"ab\\"c"', "ab\"c".encode(e).inspect, bug4081) + assert_equal('"abc"', S("abc".encode(e)).inspect) + assert_equal('"\\u3042\\u3044\\u3046"', S("\u3042\u3044\u3046".encode(e)).inspect) + assert_equal('"ab\\"c"', S("ab\"c".encode(e)).inspect, bug4081) end begin verbose, $VERBOSE = $VERBOSE, nil ext = Encoding.default_external Encoding.default_external = "us-ascii" $VERBOSE = verbose - i = "abc\"\\".force_encoding("utf-8").inspect + i = S("abc\"\\".force_encoding("utf-8")).inspect ensure $VERBOSE = nil Encoding.default_external = ext @@ -3055,11 +3103,11 @@ CODE def test_dummy_inspect assert_equal('"\e\x24\x42\x22\x4C\x22\x68\e\x28\x42"', - "\u{ffe2}\u{2235}".encode("cp50220").inspect) + S("\u{ffe2}\u{2235}".encode("cp50220")).inspect) end def test_prepend - assert_equal(S("hello world!"), "!".prepend("hello ", "world")) + assert_equal(S("hello world!"), S("!").prepend("hello ", "world")) b = S("ue") assert_equal(S("ueueue"), b.prepend(b, b)) @@ -3067,7 +3115,7 @@ CODE def foo.to_str "b" end - assert_equal(S("ba"), "a".prepend(foo)) + assert_equal(S("ba"), S("a").prepend(foo)) a = S("world") b = S("hello ") @@ -3081,34 +3129,34 @@ CODE end def test_byteslice - assert_equal("h", "hello".byteslice(0)) - assert_equal(nil, "hello".byteslice(5)) - assert_equal("o", "hello".byteslice(-1)) - assert_equal(nil, "hello".byteslice(-6)) - - assert_equal("", "hello".byteslice(0, 0)) - assert_equal("hello", "hello".byteslice(0, 6)) - assert_equal("hello", "hello".byteslice(0, 6)) - assert_equal("", "hello".byteslice(5, 1)) - assert_equal("o", "hello".byteslice(-1, 6)) - assert_equal(nil, "hello".byteslice(-6, 1)) - assert_equal(nil, "hello".byteslice(0, -1)) - - assert_equal("h", "hello".byteslice(0..0)) - assert_equal("", "hello".byteslice(5..0)) - assert_equal("o", "hello".byteslice(4..5)) - assert_equal(nil, "hello".byteslice(6..0)) - assert_equal("", "hello".byteslice(-1..0)) - assert_equal("llo", "hello".byteslice(-3..5)) - - assert_equal(u("\x81"), "\u3042".byteslice(1)) - assert_equal(u("\x81\x82"), "\u3042".byteslice(1, 2)) - assert_equal(u("\x81\x82"), "\u3042".byteslice(1..2)) - - assert_equal(u("\x82")+("\u3042"*9), ("\u3042"*10).byteslice(2, 28)) + assert_equal("h", S("hello").byteslice(0)) + assert_equal(nil, S("hello").byteslice(5)) + assert_equal("o", S("hello").byteslice(-1)) + assert_equal(nil, S("hello").byteslice(-6)) + + assert_equal("", S("hello").byteslice(0, 0)) + assert_equal("hello", S("hello").byteslice(0, 6)) + assert_equal("hello", S("hello").byteslice(0, 6)) + assert_equal("", S("hello").byteslice(5, 1)) + assert_equal("o", S("hello").byteslice(-1, 6)) + assert_equal(nil, S("hello").byteslice(-6, 1)) + assert_equal(nil, S("hello").byteslice(0, -1)) + + assert_equal("h", S("hello").byteslice(0..0)) + assert_equal("", S("hello").byteslice(5..0)) + assert_equal("o", S("hello").byteslice(4..5)) + assert_equal(nil, S("hello").byteslice(6..0)) + assert_equal("", S("hello").byteslice(-1..0)) + assert_equal("llo", S("hello").byteslice(-3..5)) + + assert_equal(u("\x81"), S("\u3042").byteslice(1)) + assert_equal(u("\x81\x82"), S("\u3042").byteslice(1, 2)) + assert_equal(u("\x81\x82"), S("\u3042").byteslice(1..2)) + + assert_equal(u("\x82")+("\u3042"*9), S("\u3042"*10).byteslice(2, 28)) bug7954 = '[ruby-dev:47108]' - assert_equal(false, "\u3042".byteslice(0, 2).valid_encoding?, bug7954) + assert_equal(false, S("\u3042").byteslice(0, 2).valid_encoding?, bug7954) assert_equal(false, ("\u3042"*10).byteslice(0, 20).valid_encoding?, bug7954) end @@ -3123,6 +3171,8 @@ CODE end def test_eq_tilde_can_be_overridden + return unless @cls == String + assert_separately([], <<-RUBY) class String undef =~ @@ -3140,7 +3190,7 @@ CODE end def test_regexp_match_subclass - s = Bug9581.new("abc") + s = Bug9581.new(S("abc")) r = /abc/ assert_equal(:foo, s =~ r) assert_equal(:foo, s.send(:=~, r)) @@ -3150,6 +3200,7 @@ CODE def test_LSHIFT_neary_long_max return unless @cls == String + assert_ruby_status([], <<-'end;', '[ruby-core:61886] [Bug #9709]', timeout: 20) begin a = "a" * 0x4000_0000 @@ -3161,6 +3212,8 @@ CODE # enable only when string size range is smaller than memory space def test_uplus_minus + return unless @cls == String + str = "foo" assert_not_predicate(str, :frozen?) assert_not_predicate(+str, :frozen?) @@ -3182,6 +3235,8 @@ CODE end def test_uminus_frozen + return unless @cls == String + # embedded str1 = ("foobar" * 3).freeze str2 = ("foobar" * 3).freeze @@ -3198,40 +3253,192 @@ CODE end def test_uminus_no_freeze_not_bare - str = @cls.new("foo") |